Beispiel #1
0
 static void WriteBitmap(string path, uint[] palette, byte[] pixels, int width)
 {
     using var stream = File.Open(path, FileMode.Create, FileAccess.Write);
     using var bw     = new BinaryWriter(stream);
     using var s      = new GenericBinaryWriter(bw, Encoding.ASCII.GetBytes);
     Bitmap8Bit.Serdes(new Bitmap8Bit((ushort)width, palette, pixels), s);
 }
Beispiel #2
0
    public static Bitmap8Bit Serdes(Bitmap8Bit b, ISerializer s)
    {
        if (s == null)
        {
            throw new ArgumentNullException(nameof(s));
        }

        var initialOffset = s.Offset;

        b ??= new Bitmap8Bit();

        //-------------\\
        // File Header \\
        //-------------\\
        var magic = Encoding.ASCII.GetString(s.Bytes("Magic", Magic, 2)); // 0

        if (magic != MagicString)
        {
            throw new FormatException($"Tried to read as bitmap, but incorrect signature \"{magic}\" found (expected BM)");
        }

        var  sizeOffset = s.Offset;
        uint size       = s.UInt32("Size", 0); // 2 Will patch this at the end when writing

        if (s.IsReading() && size > s.BytesRemaining + (s.Offset - initialOffset))
        {
            throw new FormatException($"Bitmap specified a size of {size}, but the stream only contains {s.BytesRemaining + (s.Offset - initialOffset)} bytes");
        }

        s.UInt16("Reserved1", 0);                            // 6
        s.UInt16("Reserved2", 0);                            // 8
        var  pixelOffsetOffset = s.Offset;
        uint pixelOffset       = s.UInt32("PixelOffset", 0); // A Will patch later when writing

        if (s.IsReading() && pixelOffset > s.BytesRemaining + (s.Offset - initialOffset))
        {
            throw new FormatException($"Bitmap specified a pixel offset of {pixelOffset}, but the stream only contains {s.BytesRemaining + (s.Offset - initialOffset)} bytes");
        }

        //------------\\
        // DIB Header \\
        //------------\\
        const uint bitmapInfoHeaderSize = 40;
        uint       headerSize           = s.UInt32("HeaderSize", bitmapInfoHeaderSize); // E

        if (headerSize != bitmapInfoHeaderSize)
        {
            throw new FormatException($"Unsupported bitmap header size {headerSize}, expecting {bitmapInfoHeaderSize}.");
        }

        b.Width  = s.UInt32("Width", b.Width);  // 12
        b.Height = s.UInt32("Width", b.Height); // 16
        ushort planes = s.UInt16("Planes", 1);  // 1A

        if (planes != 1)
        {
            throw new FormatException($"Unsupported number of colour planes in bitmap: {planes}, expected 1");
        }

        ushort bpp = s.UInt16("BPP", 8); // 1C

        if (bpp != 8)
        {
            throw new FormatException($"Unsupported colour depth: {bpp} bits per pixel, expected 8");
        }

        Compression compression = s.EnumU32("Compression", Compression.Rgb); // 1E

        if (compression != Compression.Rgb)
        {
            throw new FormatException($"Unsupported compression method {compression}, expected RGB (0)");
        }

        s.UInt32("ImageSize", 0);                                                   // 22 Dummy value for RGB bitmaps
        int  widthPixelsPerMetre  = s.Int32("HorizontalResolution", 3779);          // 26
        int  heightPixelsPerMetre = s.Int32("VerticalResolution", 3779);            // 2A
        uint paletteSize          = s.UInt32("PaletteSize", (uint)b.Palette.Count); // 2E

        if (paletteSize != 256)
        {
            throw new FormatException($"Unsupported palette size {paletteSize}, expected 256");
        }

        s.UInt32("ImportantColours", 0); // 32 Ignored

        //---------\\
        // Palette \\ // 36
        //---------\\
        b.Palette = s.List("Palette", b.Palette, (int)paletteSize, (n, x, s2) =>
        {
            uint b1 = s2.UInt8(null, (byte)((x & 0x00ff0000) >> 16)); // B
            uint b2 = s2.UInt8(null, (byte)((x & 0x0000ff00) >> 8));  // G
            uint b3 = s2.UInt8(null, (byte)(x & 0x000000ff));         // R
            uint b4 = s2.UInt8(null, 0);                              // A
            return(0xff000000U | (b1 << 16) | (b2 << 8) | b3);
        });

        //------------\\
        // Pixel Data \\
        //------------\\
        if (s.IsReading())
        {
            var tempOffset = s.Offset;
            s.Seek(pixelOffsetOffset);
            s.UInt32("PixelOffset", (uint)(tempOffset - initialOffset));
            s.Seek(tempOffset);
        }

        b.Pixels ??= new byte[b.Width * b.Height];
        uint stride = 4 * ((bpp * b.Width + 31) / 32);

        for (int j = 0; j < b.Height; j++)
        {
            uint index = (uint)((b.Height - j - 1) * b.Width);
            for (int i = 0; i < b.Width; i++)
            {
                b.Pixels[index] = s.UInt8(null, b.Pixels[index]);
                index++;
            }

            if (stride - b.Width > 0) // Padding
            {
                s.RepeatU8(null, 0, (int)(stride - b.Width));
            }
        }

        if (s.IsReading())
        {
            var tempOffset = s.Offset;
            s.Seek(sizeOffset);
            s.UInt32("Size", (uint)(tempOffset - initialOffset));
            s.Seek(tempOffset);
        }

        return(b);
    }