[API Proposal]: BitStream, BitReader, BitWriter

Open
#117,644 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
5/5
Estimated time
Over a week
Newbie friendliness
25/100
Issue type
Feature
Clarity
Needs clarification
Activity status
Stale
Tech stack
csharp
Domain
api

Research direction

Start by reviewing the proposed BitStream, BitReader, and BitWriter APIs alongside the alternative BinaryReader and BinaryWriter designs. No implementation files or tests are named, so first determine where related System.IO APIs belong and how the bit-width and seeking requirements should be resolved. Done means an agreed API design with appropriate implementation scope and tests.

Written by the indexing model from the issue text.

Description

api-suggestion area-System.IO
Background and motivation

I need a way to efficiently read and write compressed pixel data from a buffer of pixels.

I am currently trying to encode and decode 1bpp, 2bpp, 3bpp, 4bpp, and 32bpp images from raw bytes.

API Proposal
namespace System.IO.Binary;

public class BitStream
{
    public ulong Index { get; }

    public static BitStream FromBytes(byte[] bytes);
    public static BitStream FramFile(string path);
    public static BitStream FromMemory(MemoryStream stream);
    public static BitStream FromStream(Stream stream);
    
    public void SeekBit(ulong @bit);
    public void SeekNibble(ulong @nibble);
    public void SeekByte(ulong @byte);

}

public class BitWriter
{

    public void WriteBit(bool value);
    public void WriteNibble(byte value);
    public void WriteByte(byte value);
}

public class BitReader
{
    public bool ReadBit();
    public byte ReadNibble();
    public byte ReadByte();
}
API Usage
public partial class IndexedBitmap(uint width, uint height) : IImage
{
    private byte[] _pixels = new byte[(width * height) / 2];
    private BitStream _bitStream = new BitStream(_pixels);
    private BitReader _bitReader = new BitReader(_bitStream);

    public void Draw(DrawingContext context, Rect sourceRect, Rect destRect)
    {
        var pen = new Pen();
        var brush = new SolidColorBrush();
        for (var y = destRect.Y; y < destRect.Height; y++)
        {
            for (var x=destRect.X; y<destRect.Width; x++)
            {
                var pixel = _bitReader.ReadNibble();
                brush.Color = Palette.Colors[pixel, ColorSet];
                pen.Brush = brush;
                context.DrawRectangle(pen, new Rect(x, y, 1, 1));
            }
            _bitStream.SeekNibble((ulong)destRect.Width, SeekOrigin.Current);
        }
    }

    public Size Size { get; } = new Size(width / 2, height / 2);
    public uint    ColorSet { get; set; }
    public Palette Palette { get; set; }
}

Please excuse the example code it may not be perfect.

Alternative Designs
public class MemoryStream
{
    public void Seek(ulong @bit, SeekOrigin origin, BitType type=BitType.Byte);
}

public class BinaryReader
{
    public byte ReadByte(BitType type = BitType.Byte);
    
}

public class BinaryWriter
{
    public void WriterByte(byte value, BitType type = BitType.Byte);
}

public enum BitType
{
    OneBit,
    TwoBits,
    ThreeBits,
    FourBits,
    FiveBits,
    SixBits,
    SevenBits,
    Byte
}

or

public class MemoryStream
{
    public void Seek(ulong @bit, SeekOrigin origin, int bits=8);
}

public class BinaryReader
{
    public byte ReadBits(int bits=8);
    
}

public class BinaryWriter
{
    public void WriteBits(byte value, int bits=8);
}
Risks

It might be slower to work in bits rather then bytes, even if you keep track of the current bit your reading and writing the branching could slow it down.

Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from dotnet/runtime

All issues in dotnet/runtime

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.