示例#1
0
        /// <summary>
        /// Packed Bitmap decoder. Calls from ConvertCustomToBitmap if the bitmap is packed, not snes.
        /// </summary>
        /// <param name="_buffer">Bitmap data</param>
        /// <param name="_palette">palette data</param>
        /// <param name="bpp">bits-per-pixel</param>
        /// <returns>Bitmap</returns>
        private static Bitmap PackedDecode(byte[] _buffer, Color[] _palette, int bpp)
        {
            IBitformat format = SnesGFX.AvaiableFormats[Settings.Default.Codec];

            // let's get the width
            int width  = bitmapInfo.Width;
            int height = _buffer.Length;

            if (format.Type == BitformatType.BITFORMAT_PACKED)
            {
                height = height * 8 / format.BitsPerPixel;
            }

            height /= width;

            //int packedtype;

            //if (!Options.PreserveWidth)
            //{
            //    width = 128;
            //}

            //if (Options.PackPacked)
            //{
            //    switch (Settings.Default.Codec)
            //    {
            //        case 4:
            //            packedtype = 2;
            //            height *= 4;
            //            break;

            //        case 5:
            //            packedtype = 4;
            //            height *= 2;
            //            break;

            //        case 6:
            //        case 7:
            //            packedtype = 8;
            //            break;

            //        default:
            //            packedtype = 2;
            //            height /= 4;
            //            break;
            //    }
            //}
            //else
            //{
            //    packedtype = 8;
            //}

            //height /= width;

            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);

            ColorPalette pal = bmp.Palette;
            int          x   = 0;

            while (x < _palette.Length)
            {
                pal.Entries[x] = _palette[x++];
            }
            bmp.Palette = pal;

            byte[] output = format.Decode(_buffer);

            //ExGraphics.CodecInfo codec = new SuperFX.ExGraphics.CodecInfo(-1);
            //codec.Decode = true;
            //codec.SysName = string.Format("Pack{0}BPP", packedtype);
            //codec.Data = _buffer;
            //ExGraphics.StartCodec = codec;

            var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite,
                                       PixelFormat.Format8bppIndexed);

            IntPtr ptr   = bmpData.Scan0;
            int    bytes = Math.Abs(bmpData.Stride) * height;

            Marshal.Copy(output, 0, ptr, bytes);
            bmp.UnlockBits(bmpData);
            return(bmp);
        }
示例#2
0
        /// <summary>
        /// Rotina de conversão de Imagens para SNES Graphics
        /// </summary>
        private void Ripper_ProcessSystem(bool preview = false)
        {
            StringBuilder report = new StringBuilder();

            try
            {
                if (!init)
                {
                    return;
                }
                EnableOrDisable(false);
                InteragirFlag             = true;
                Application.UseWaitCursor = true;
                new Thread(new ThreadStart(InteragirWindows)).Start();

                if (textBox1.Tag == null)
                {
                    goto End;
                }

                foreach (var file in (string[])textBox1.Tag)
                {
                    string name = Regex.Replace(file.Replace(@"\", @"\\"), "[.]\\w{3,4}", "", Program.ropts);

                    if (!Options.SaveOnImageFolder && name.LastIndexOf("\\") != -1)
                    {
                        name = name.Substring(name.LastIndexOf("\\") + 1);
                    }

                    Bitmap b = null;

                    using (FileStream fs = new FileStream(file, FileMode.Open))
                    {
                        b = new Bitmap(fs);
                        fs.Close();

                        Program.bitmapInfo = b.Size;
                    }

                    double scale = (!checkBox3.Checked) ? 1 : (Int32.Parse(textBox2.Text) / 100D);

                    byte[]  result;
                    byte[]  palette;
                    Color[] memPalette;
                    string  extension;
                    byte[]  mwl = null;

                    Program.BitmapToRAWSNES(b, this.comboBox2.SelectedIndex + 2, scale,
                                            out result, out palette, out extension, out memPalette);

                    b.Dispose();

                    IBitformat codec         = SnesGFX.AvaiableFormats[comboBox1.SelectedIndex];
                    byte[]     outputTilemap = null;

                    if (Options.RemoveDuplicateTiles)
                    {
                        int baseSize = 8;

                        int[]  tilemap;
                        bool[] flipx, flipy;
                        int    theWidth = codec.FixedWidth == 0 ? Program.bitmapInfo.Width :
                                          codec.FixedWidth;

                        SNES.Tile[] tiles  = SNES.Tile.FromBitmap(result, theWidth, baseSize);
                        SNES.Tile[] aTiles = SNES.Tile.RemoveRepeatedBlocks(tiles, Options.RemoveFlippedTiles,
                                                                            out tilemap, out flipx, out flipy);
                        int nTiles = aTiles.Length;
                        // This is needed to some lines don't get cut-off.
                        if (nTiles % 0x10 != 0)
                        {
                            nTiles += 0x10 - nTiles % 0x10;
                        }
                        SNES.Tile[] rTiles = new SNES.Tile[nTiles];
                        aTiles.CopyTo(rTiles, 0);
                        for (int i = aTiles.Length; i < nTiles; ++i)
                        {
                            rTiles[i] = new SNES.Tile(new byte[baseSize * baseSize], baseSize);
                        }
                        result = SNES.Tile.ConvertToBitmap(rTiles, theWidth);

                        int x_flip_count  = 0;
                        int y_flip_count  = 0;
                        int xy_flip_count = 0;

                        for (int i = 0; i < flipx.Length; ++i)
                        {
                            if (flipx[i] && flipy[i])
                            {
                                ++xy_flip_count;
                                continue;
                            }
                            if (flipx[i])
                            {
                                ++x_flip_count;
                                continue;
                            }
                            if (flipy[i])
                            {
                                ++y_flip_count;
                                continue;
                            }
                        }

                        string msg =
                            @"Total Tiles Before Removing Duplicates:		0x{0:X4}
Total Tiles After Removing Duplicates:		0x{1:X4}

Total X Flipped Tiles:				0x{3:X4}
Total Y Flipped Tiles:				0x{4:X4}
Total X+Y Flipped Tiles:			0x{5:X4}
Total Duplicated Tiles:			0x{6:X4}
Total Removed:				0x{7:X4}

Ratio:					{2:F}%"                ;

                        msg = string.Format(CultureInfo.InvariantCulture,
                                            msg, tiles.Length, rTiles.Length, rTiles.Length / (double)tiles.Length * 100,
                                            x_flip_count, y_flip_count, xy_flip_count, tiles.Length - rTiles.Length -
                                            x_flip_count - y_flip_count - xy_flip_count, tiles.Length - rTiles.Length);

                        report.AppendLine(name);
                        report.AppendLine(msg);
                        report.AppendLine();

                        if (((string[])textBox1.Tag).Length == 1)
                        {
                            MessageBox.Show(msg, "Anti-Tile Duplicate Results",
                                            MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }

                        for (int i = 0; i < tilemap.Length; ++i)
                        {
                            tilemap[i] = (tilemap[i] + Options.OffsetTile) & 0x3FF;
                        }

                        if (rTiles.Length > 1024 && Options.TilemapOutput != 3)                        //Options.GenerateMap16)
                        {
                            MessageBox.Show("There are more than 1024 (0x400) tiles, thus " +
                                            "it's impossible to generate a SNES tilemap.", "Error",
                                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                            goto End;
                        }
                        else if (Options.TilemapOutput == 0)
                        {
                            int size = tilemap.Length * 2;
                            // 2kB o caralho
                            //if (size % 0x800 != 0)
                            //{
                            //	size += 0x800 - size % 0x800;
                            //}
                            if (size <= 0x780)
                            {
                                if (size % 0x780 != 0)
                                {
                                    size += 0x780 - size % 0x780;
                                }
                            }
                            else
                            {
                                if (size % 0x800 != 0)
                                {
                                    size += 0x800 - size % 0x800;
                                }
                            }
                            outputTilemap = new byte[size];

                            for (int i = 0; i < tilemap.Length; ++i)
                            {
                                int item = tilemap[i] & 0x3FF;
                                item += flipy[i] ? 0x8000 : 0;
                                item += flipx[i] ? 0x4000 : 0;

                                //int mIndex = i;// &~(0x20 | 0x40);
                                //mIndex |= (i & 0x20) << 1;
                                //mIndex |= (i & 0x40) >> 1;
                                //mIndex <<= 1;

                                int ii = (i & 0x0F) | ((i & ~0x0F) << 1);
                                ii &= 0x3FF;

                                ii |= i & ~0x3FF;
                                ii |= (i & 0x200) >> 5;

                                int mIndex = ((ii & 0x1F) << 1) | (ii & ~0x3F) | ((ii & 0x20) >> 5);
                                mIndex <<= 1;

                                if (mIndex >= size)
                                {
                                    continue;
                                }

                                outputTilemap[mIndex]     = (byte)(item & 0xFF);
                                outputTilemap[mIndex + 1] = (byte)(item >> 8 & 0xFF);
                            }
                        }
                        else if (Options.TilemapOutput == 1)
                        {
                            int size = tilemap.Length * 2;
                            if (size % 0x800 != 0)
                            {
                                size += 0x800 - size % 0x800;
                            }
                            outputTilemap = new byte[size];

                            for (int i = 0; i < tilemap.Length; ++i)
                            {
                                int item = tilemap[i] & 0x3FF;
                                item += flipy[i] ? 0x8000 : 0;
                                item += flipx[i] ? 0x4000 : 0;

                                //int mIndex = i;// &~(0x20 | 0x40);
                                //mIndex |= (i & 0x20) << 1;
                                //mIndex |= (i & 0x40) >> 1;
                                //mIndex <<= 1;

                                int ii = (i & 0x0F) | ((i & ~0x0F) << 1);
                                ii &= 0x3FF;

                                ii |= i & ~0x3FF;
                                ii |= (i & 0x200) >> 5;

                                int mIndex = ((ii & 0x1F) << 1) | (ii & ~0x3F) | ((ii & 0x20) >> 5);
                                mIndex <<= 1;

                                if (mIndex >= size)
                                {
                                    continue;
                                }

                                outputTilemap[mIndex]     = (byte)(item & 0xFF);
                                outputTilemap[mIndex + 1] = (byte)(item >> 8 & 0xFF);
                            }

                            List <int[]> m16opt   = new List <int[]>();
                            int[]        m16index = new int[outputTilemap.Length >> 3];

                            for (int i = 0; i < outputTilemap.Length; i += 8)
                            {
                                int[] group = new int[4];
                                group[0] = outputTilemap[i] | (outputTilemap[i + 1] << 8);
                                group[1] = outputTilemap[i + 2] | (outputTilemap[i + 3] << 8);
                                group[2] = outputTilemap[i + 4] | (outputTilemap[i + 5] << 8);
                                group[3] = outputTilemap[i + 6] | (outputTilemap[i + 7] << 8);

                                int x = m16opt.FindIndex(p => p[0] == group[0] &&
                                                         p[1] == group[1] && p[2] == group[2] && p[3] == group[3]);

                                if (x != -1)
                                {
                                    m16index[i >> 3] = x;
                                }
                                else
                                {
                                    m16index[i >> 3] = m16opt.Count;
                                    m16opt.Add(group);
                                }
                            }

                            size = m16opt.Count * 8;
                            if (size % 0x800 != 0)
                            {
                                size += 0x800 - size % 0x800;
                            }
                            outputTilemap = new byte[size];

                            for (int i = 0; i < m16opt.Count; ++i)
                            {
                                outputTilemap[(i << 3) + 0] = (byte)(m16opt[i][0]);
                                outputTilemap[(i << 3) + 1] = (byte)(m16opt[i][0] >> 8);
                                outputTilemap[(i << 3) + 2] = (byte)(m16opt[i][1]);
                                outputTilemap[(i << 3) + 3] = (byte)(m16opt[i][1] >> 8);
                                outputTilemap[(i << 3) + 4] = (byte)(m16opt[i][2]);
                                outputTilemap[(i << 3) + 5] = (byte)(m16opt[i][2] >> 8);
                                outputTilemap[(i << 3) + 6] = (byte)(m16opt[i][3]);
                                outputTilemap[(i << 3) + 7] = (byte)(m16opt[i][3] >> 8);
                            }

                            // assuming the map16 will get stored at page 0x42...

                            //FuSoYa:
                            //"Base mwl file attached.  This file is already set to use a custom
                            //palette and custom BG.  Insert the BG tilemap at offset 0xD6 (0x800
                            //bytes, 16 bit values little endian).  The upper 4 bits in the byte at
                            //offset 0xCE should be set to the Map16 bank you want to use (0-3),
                            //while the lower 4 bits should not be changed.  Offset 0x8E8 is the
                            //palette table (SNES format, 16 bit values little endian, 0x202 bytes
                            //as there's an extra entry at the end for the back area color)."

                            if (rTiles.Length > 0x300)
                            {
                                MessageBox.Show("There are more than 768 (0x300) tiles. It means it won't fit even if you " +
                                                "use all LM slots (FG1-3; BG1-3). Conversion aborted.", "Error",
                                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                                goto End;
                            }

                            mwl = Resources._base;

                            // we need to deinterleave the gfx "blocks" or it will look weird on LM
                            int w  = Program.bitmapInfo.Width;
                            int h  = Program.bitmapInfo.Height;
                            int h2 = h;
                            if (w % 128 != 0)
                            {
                                w += 128 - w % 128;
                            }
                            if (h % 256 != 0)
                            {
                                h += 256 - h % 256;
                            }

                            if (w > 512 || h > 512)
                            {
                                MessageBox.Show("The output image (" + w + "x" + h + ") is larger than 512x512! Conversion aborted.",
                                                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                goto End;
                            }

                            for (int y = 0; y < h; y += 16)
                            {
                                for (int x = 0; x < w; x += 16)
                                {
                                    // destination: there are 0x400 blocks, each one of 16x16
                                    // format is, well:
                                    // XYyyyyxxxx

                                    int dest = (x >> 4 & 15) | ((y >> 4 & 15) << 4) | ((x >> 8 & 1) << 9) | ((y >> 8 & 1) << 8);
                                    dest <<= 1;
                                    dest  += 0xD6;

                                    // source: this one is more fun.
                                    // format:
                                    // ...PP pyyyYxxx
                                    // and it's offset based.
                                    // oh well.

                                    if (y >> 4 >= h2 >> 4)
                                    {
                                        continue;
                                    }

                                    int fakeY  = (y >> 4) + (x >> 7) * (h2 >> 4);
                                    int source = (x >> 4 & 7) | ((fakeY & 15) << 4) | ((fakeY >> 4 & 1) << 3) | ((fakeY >> 5) << 8);                                    // | ((offset >> 3 & 7) << 4) | ((offset >> 6 & 1) << 3) | ((offset >> 7) << 7);

                                    if (source >= m16index.Length)
                                    {
                                        continue;
                                    }

                                    int m16 = 0x0200 + m16index[source];
                                    mwl[dest]     = (byte)m16;
                                    mwl[dest + 1] = (byte)(m16 >> 8);
                                }
                            }

                            byte[] mw3 = Program.PaletteToMw3(memPalette, 256);
                            mw3[512] = mw3[0];
                            mw3[513] = mw3[1];
                            mw3[0]   = 0;
                            mw3[1]   = 0;
                            mw3.CopyTo(mwl, 0x8E8);
                        }
                        else if (Options.TilemapOutput == 2)
                        {
                            // we need to deinterleave the gfx "blocks" or it will look weird on LM
                            int w  = Program.bitmapInfo.Width;
                            int h  = Program.bitmapInfo.Height;
                            int h2 = h;
                            if (w % 128 != 0)
                            {
                                w += 128 - w % 128;
                            }
                            if (h % 256 != 0)
                            {
                                h += 256 - h % 256;
                            }

                            if (w > 512 || h > 512)
                            {
                                MessageBox.Show("The output image (" + w + "x" + h + ") is larger than 512x512! Conversion aborted.",
                                                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                goto End;
                            }

                            //brrrrrrrrrrrrrrrrrrrrrrrrrr!
                            if (w <= 256 && h <= 256)
                            {
                                //outputTilemap = new byte[32 * 32 * 2];
                                // attention TO DO
                                outputTilemap = new byte[0x780];
                            }
                            else if (w > 256 && h <= 256)
                            {
                                outputTilemap = new byte[64 * 32 * 2];
                            }
                            else
                            {
                                outputTilemap = new byte[64 * 64 * 2];
                            }

                            for (int y = 0; y < h; y += 8)
                            {
                                for (int x = 0; x < w; x += 8)
                                {
                                    // destination: there are 0x1000 blocks, each one of 8x8
                                    // format is, well:
                                    // XYyy yyyx xxxx

                                    int dest = (x >> 3 & 31) | ((y >> 3 & 31) << 5) | ((x >> 8 & 1) << 10) | ((y >> 8 & 1) << 11);
                                    dest <<= 1;


                                    // pp pppp xxxx

                                    if (y >> 3 >= h2 >> 3)
                                    {
                                        continue;
                                    }

                                    int fakeY  = (y >> 3) + (x >> 7) * (h2 >> 3);
                                    int source = (x >> 3 & 15) | (fakeY << 4);

                                    if (source >= tilemap.Length)
                                    {
                                        continue;
                                    }

                                    int item = tilemap[source] & 0x3FF;
                                    item += flipy[source] ? 0x8000 : 0;
                                    item += flipx[source] ? 0x4000 : 0;

                                    outputTilemap[dest]     = (byte)(item & 0xFF);
                                    outputTilemap[dest + 1] = (byte)(item >> 8 & 0xFF);
                                }
                            }
                        }
                        else if (Options.TilemapOutput == 3 || Options.TilemapOutput == 4)
                        {
                            // mode 7

                            int w  = Program.bitmapInfo.Width;
                            int h  = Program.bitmapInfo.Height;
                            int h2 = h;
                            if (w % 128 != 0)
                            {
                                w += 128 - w % 128;
                            }
                            if (h % 256 != 0)
                            {
                                h += 256 - h % 256;
                            }

                            if (w > 1024 || h > 1024)
                            {
                                MessageBox.Show("The output image (" + w + "x" + h + ") is larger than 1024x1024! Conversion aborted.",
                                                "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                goto End;
                            }

                            if (rTiles.Length > 0x100)
                            {
                                MessageBox.Show("There are more than 256 (0x100) tiles. It won't fit on a Mode 7 Character Data, " +
                                                "which is limited to 128x128. Conversion aborted.", "Error",
                                                MessageBoxButtons.OK, MessageBoxIcon.Error);
                                goto End;
                            }

                            outputTilemap = new byte[128 * 128];

                            for (int y = 0; y < h; y += 8)
                            {
                                for (int x = 0; x < w; x += 8)
                                {
                                    // destination: there are 0x1000 blocks, each one of 8x8
                                    // format is, well:
                                    // XYyy yyyx xxxx

                                    // format:
                                    // yy yyyy yxxx xxxx

                                    int dest = (x >> 3 & 1023) | ((y >> 3 & 1023) << 7);

                                    // pp pppp xxxx

                                    if (y >> 3 >= h2 >> 3)
                                    {
                                        continue;
                                    }

                                    int fakeY  = (y >> 3) + (x >> 7) * (h2 >> 3);
                                    int source = (x >> 3 & 15) | (fakeY << 4);

                                    if (source >= tilemap.Length)
                                    {
                                        continue;
                                    }

                                    if (flipy[source] || flipx[source])
                                    {
                                        MessageBox.Show("Mode 7 can't flip tiles! Please disable \"Remove Flipped Tiles\"" +
                                                        "option and try again. Conversion aborted.", "Error",
                                                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                                        goto End;
                                    }

                                    outputTilemap[dest] = (byte)(tilemap[source] & 0xFF);
                                }
                            }
                        }
                    }

                    byte[] output = codec.Encode(result);

                    if (!preview)
                    {
                        int error_count = 0;
                        while (true)
                        {
                            try
                            {
                                if (!Options.SplitOutput)
                                {
                                    if (Options.TilemapOutput == 4)
                                    {
                                        // kk interleave mode
                                        byte[] final = new byte[0x8000];

                                        for (int x = 0, y = 0; x < 0x8000; x += 2, ++y)
                                        {
                                            final[x + 0] = outputTilemap[y];
                                            if (y < output.Length)
                                            {
                                                final[x + 1] = output[y];
                                            }
                                            else
                                            {
                                                final[x + 1] = 0;
                                            }
                                        }

                                        File.WriteAllBytes(name + ".bin", final);
                                    }
                                    else
                                    {
                                        File.WriteAllBytes(name + ".bin", output);
                                    }
                                }
                                else
                                {
                                    if (Options.TilemapOutput == 4)
                                    {
                                        MessageBox.Show("Can't split output with Mode 7 Interleaved Tilemap!", "Error",
                                                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                                        goto End;
                                    }

                                    int maxSize = 1 << (Options.SplitOutputIndex + 9);
                                    int size    = output.Length;
                                    int index   = 0;
                                    int part    = 0;

                                    while (index < size)
                                    {
                                        byte[] area = new byte[maxSize];
                                        if (index + maxSize < size)
                                        {
                                            Array.Copy(output, index, area, 0, maxSize);
                                        }
                                        else
                                        {
                                            Array.Copy(output, index, area, 0, size - index);
                                        }
                                        File.WriteAllBytes(name + "_part_" + part.ToString("X2") + ".bin", area);
                                        index += maxSize;
                                        ++part;
                                    }
                                }

                                if (palette.Length != 0)
                                {
                                    File.WriteAllBytes(name + extension, palette);
                                }

                                if (outputTilemap != null && Options.TilemapOutput != 4)
                                {
                                    File.WriteAllBytes(name + "_map16.bin", outputTilemap);
                                }

                                if (mwl != null)
                                {
                                    File.WriteAllBytes(name + ".mwl", mwl);
                                }
                                break;
                            }

                            catch (Exception e)
                            {
                                if (error_count++ >= 6)
                                {
                                    MessageBox.Show(e.Message, "Error",
                                                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                                    goto End;
                                }
                            }
                        }
                    }
                    else
                    {
                        Bitmap graphics = Program.ConvertCustomToBitmap(output,
                                                                        memPalette, codec.BitsPerPixel);

                        if (Program.view == null)
                        {
                            Program.view       = new Preview(graphics, new Size(256, 256));
                            Program.view.Owner = this;
                            Program.view.Show();
                        }

                        else if (Program.view.IsDisposed)
                        {
                            Program.view       = new Preview(graphics, new Size(256, 256));
                            Program.view.Owner = this;
                            Program.view.Show();
                        }
                        else
                        {
                            Program.view.CurrrentImage = graphics;
                        }
                    }
                }
            }
            catch (NullReferenceException)
            {
                MessageBox.Show("This image has too many colors to fit on configuration. " +
                                "Please enable \"optimize image\" option to reduce the number of colors.",
                                "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            catch (Exception e)
            {
                MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                goto End;
            }

End:
            Application.UseWaitCursor = false;
            EnableOrDisable(true);
            InteragirFlag = false;

            File.WriteAllText("convertlog.txt", report.ToString());
        }
示例#3
0
        /// <summary>
        /// Converts a SNES/PACKED BIT-MAP to Bitmap.
        /// </summary>
        /// <param name="_buffer">The raw data</param>
        /// <param name="_palette">Palette</param>
        /// <param name="bpp">bits-per-pixel</param>
        /// <returns>The Bitmap</returns>
        public static Bitmap ConvertCustomToBitmap(byte[] _buffer, Color[] _palette, int bpp)
        {
            if (SnesGFX.AvaiableFormats[Settings.Default.Codec].Type != BitformatType.BITFORMAT_PLANAR)
            {
                return(PackedDecode(_buffer, _palette, bpp));
            }

            long a8x8 = 0;
            long size = _buffer.Length;

            a8x8 = size / ((64 * bpp) / 8);
            int height = (int)((a8x8 / 16) * 8);
            int width  = (int)((a8x8 > 16) ? 128 : a8x8 * 8);

            if (height == 0)
            {
                height = 0;
            }
            if (height % 8 != 0)
            {
                height += 8 - (height % 8);
            }

            Bitmap bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);

            ColorPalette pal = bmp.Palette;
            int          x   = 0; while (x < _palette.Length)

            {
                pal.Entries[x] = _palette[x++];
            }

            if (Options.AllowTransparency)
            {
                pal.Entries[0] = Color.Transparent;
            }
            bmp.Palette = pal;


            IBitformat format = SnesGFX.AvaiableFormats[Settings.Default.Codec];

            byte[] output = format.Decode(_buffer);

            var bmpData = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite,
                                       PixelFormat.Format8bppIndexed);

            IntPtr ptr   = bmpData.Scan0;
            int    bytes = Math.Abs(bmpData.Stride) * height;

            //fixed (byte* ptr2 = output)
            //{
            //    byte[] rgbValues = SuperFX.ExGraphics.a8x8ToTilemap(ptr2, width, codec.output.Length);
            //    Marshal.Copy(rgbValues, 0, ptr, bytes);
            //    rgbValues = null;
            //}

            Marshal.Copy(output, 0, ptr, bytes);

            bmp.UnlockBits(bmpData);

            return(bmp);
        }