Exemplo n.º 1
0
 public abstract Bitmap Load(QOIFHeader header, BinaryReader rd);
Exemplo n.º 2
0
    public override Bitmap Load(QOIFHeader header, BinaryReader rd)
    {
        Bitmap bitmap = new(header.Width, header.Height, PixelFormat.Format32bppArgb);

        RGBAColor[] indexed   = new RGBAColor[64];
        RGBAColor   previous  = RGBAColor.Black;
        int         end_match = 0;

#if DEBUG_LOG
        StringBuilder sb = new StringBuilder().AppendLine(header.ToString()).AppendLine("DECODING");
#endif
        bitmap.LockRGBAPixels((ptr, w, h) =>
        {
            int index = 0;
#if DEBUG_LOG
            void set_pixel(RGBAColor color, string log)
#else
            void set_pixel(RGBAColor color)
#endif
            {
                if (index < w * h)
                {
                    int cache = GetIndex(color);
#if DEBUG_LOG
                    sb.AppendLine($"I={index,6} X={index % w,5} Y={index / w,5} P={previous,12} C={color,12} (CH={cache,2}) {log}");
#endif
                    indexed[cache] = color;
                    ptr[index++]   = color;

                    if (previous != color)
                    {
                        previous = color;
                    }
                }
#if DEBUG_LOG
                else
                {
                    sb.AppendLine($" <<<< index {index} >= {w}x{h} = {w * h} >>>>");
                }
#endif
            }

            try
            {
                while (index < w * h && end_match < END.Length && rd.ReadByte() is byte @byte)
                {
                    if (@byte is TAG_OP_RGB or TAG_OP_RGBA)
                    {
                        RGBAColor color = new(
                            rd.ReadByte(),
                            rd.ReadByte(),
                            rd.ReadByte()
                            );

                        if (@byte is TAG_OP_RGBA)
                        {
                            color.A = rd.ReadByte();
                        }
#if DEBUG_LOG
                        set_pixel(color, "EXPLICIT");
#else
                        set_pixel(color);
#endif
                    }
                    else
                    {
                        int op    = @byte & MASK_TAG2;
                        byte data = (byte)(@byte & ~MASK_TAG2);

                        if (op is TAG_OP_INDEX)
                        {
#if DEBUG_LOG
                            set_pixel(indexed[data], $"INDEXED  {@byte:x2} I={data}");
#else
                            set_pixel(indexed[data]);
#endif
                            if (@byte == END[end_match])
                            {
                                ++end_match;
                            }
                            else
                            {
                                end_match = 0;
                            }
                        }
                        else if (op is TAG_OP_DIFF)
                        {
                            int dr = (@byte & MASK_DIFF_R) >> SHIFT_DIFF_R;
                            int dg = (@byte & MASK_DIFF_G) >> SHIFT_DIFF_G;
                            int db = @byte & MASK_DIFF_B;

                            RGBAColor color = ComputeFrom2BitDistance(previous, dr, dg, db);
#if DEBUG_LOG
                            set_pixel(color, $"2BITDIFF {@byte:x2} ({dr} {dg} {db})");
#else
                            set_pixel(color);
#endif
                        }
                        else if (op is TAG_OP_LUMA)
                        {
                            @byte = rd.ReadByte();

                            int drg         = (@byte & MASK_LUMA_RG) >> SHIFT_LUMA_RG;
                            int dbg         = @byte & MASK_LUMA_BG;
                            RGBAColor color = ComputeFromLuma(previous, 6, 4, drg, data, dbg);
#if DEBUG_LOG
                            set_pixel(color, $"LUMADIFF {op | data:x2}{@byte:x2} ({data} {drg} {dbg})");
#else
                            set_pixel(color);
#endif
                        }
                        else if (op is TAG_OP_RUN)
                        {
                            for (int i = 0, c = data + 1; i < c && index < w * h; ++i)
#if DEBUG_LOG
                            { set_pixel(previous, $"RUN {@byte:x2} R={data + 1}"); }
#else
                            { set_pixel(previous); }
#endif
                        }
#if DEBUG_LOG
                        else
                        {
                            sb.AppendLine($" <<<< UNKNOWN INSTRUCTION {@byte:x2} >>>>");
                        }
#endif
                    }
                }
            }