Ejemplo n.º 1
0
        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listView1.SelectedIndices.Count <= 0)
            {
                return;
            }
            if (pictureBox1.Image != null)
            {
                Bitmap temp = (Bitmap)pictureBox1.Image;
                pictureBox1.Image = null;
                temp.Dispose();
            }
            isLocked = true;
            PIGImage image = datafile.Bitmaps[listView1.SelectedIndices[0]];

            pictureBox1.Image             = PiggyBitmapUtilities.GetBitmap(datafile, palette, listView1.SelectedIndices[0]);
            TransparentCheck.Checked      = image.Transparent;
            SupertransparentCheck.Checked = image.SuperTransparent;
            NoLightingCheck.Checked       = image.NoLighting;
            CompressCheckBox.Checked      = image.RLECompressed;
            Color color = Color.FromArgb(palette.GetRGBAValue(image.AverageIndex));

            ColorPreview.BackColor = color;
            pictureBox1.Refresh();
            isLocked = false;
        }
Ejemplo n.º 2
0
        /*public void writePiggyImages(string directory, PIGFile piggyfile)
         * {
         *  int w, h;
         *  byte[] image;
         *  int bytesWritten;
         *  string name;
         *  for (int i = 0; i < piggyfile.images.Count; i++)
         *  {
         *      bytesWritten = 0;
         *      if (!piggyfile.isABM((ushort)i))
         *      {
         *          image = piggyfile.Bitmaps[i];
         *          BinaryWriter bw = new BinaryWriter(File.Open(String.Format("{0}{1}.bbm", directory, piggyfile.images[i].name), FileMode.Create));
         *          //just write the image
         *          WriteBBM(image,
         *          bw.Flush();
         *          bw.Close();
         *          bw.Dispose();
         *      }
         *      else
         *      {
         *          BinaryWriter bw = new BinaryWriter(File.Open(String.Format("{0}{1}.abm", directory, piggyfile.Bitmaps[i].Name), FileMode.Create));
         *          name = piggyfile.Bitmaps[i].Name;
         *          //write FORM header
         *          bw.Write(0x4D524F46);
         *          //will update later on
         *          long loc = bw.BaseStream.Position;
         *          bw.Write(0);
         *          //Note it as a ANIM
         *          //41 4E 49 4D
         *          bw.Write(0x4D494E41);
         *          bytesWritten += 4;
         *          //write the first frame
         *          bytesWritten += WriteBBM(w, h, image, bw, (piggyfile.images[i].flags & 1) != 0);
         *          while (i < piggyfile.images.Count - 1 && piggyfile.images[i + 1].name == name)
         *          {
         *              i++;
         *              image = piggyfile.loadImage(i);
         *              w = piggyfile.images[i].vx;
         *              h = piggyfile.images[i].vy;
         *              //write animation
         *              bytesWritten += writeABMFrame(w, h, image, bw);
         *              //increment frame
         *          }
         *          bw.BaseStream.Seek(loc, SeekOrigin.Begin);
         *          writeInt32BE(bw, bytesWritten);
         *          bw.Flush();
         *          bw.Close();
         *          bw.Dispose();
         *      }
         *  }
         * }*/

        public void WriteABM(PIGImage[] frames, int numFrames, Palette palette, BinaryWriter bw)
        {
            int      bytesWritten = 0;
            PIGImage image        = frames[0];
            bool     transparent  = false;

            for (int i = 0; i < numFrames; i++)
            {
                transparent |= frames[i].Transparent;
            }

            //write FORM header
            bw.Write(0x4D524F46);
            //will update later on
            long loc = bw.BaseStream.Position;

            bw.Write(0);
            //Note it as a ANIM
            //41 4E 49 4D
            bw.Write(0x4D494E41);
            bytesWritten += 4;
            //write the first frame
            bytesWritten += WriteBBM(image, palette, transparent, bw);
            for (int i = 1; i < numFrames; i++)
            {
                //write animation
                bytesWritten += WriteABMFrame(frames[i], palette, bw);
            }
            bw.BaseStream.Seek(loc, SeekOrigin.Begin);
            WriteInt32BE(bw, bytesWritten);
            bw.Flush();
        }
Ejemplo n.º 3
0
        private void CompressCheckBox_CheckedChanged(object sender, EventArgs e)
        {
            if (listView1.SelectedItems.Count == 0)
            {
                return;
            }
            if (isLocked)
            {
                return;           //will call ourselves in case of an error
            }
            isLocked = true;
            bool currentState = !CompressCheckBox.Checked;

            try
            {
                PIGImage img = datafile.Bitmaps[listView1.SelectedIndices[0]];
                img.RLECompressed = CompressCheckBox.Checked;
                listView1.Items[listView1.SelectedIndices[0]].SubItems[1].Text = img.GetSize().ToString();
            }
            catch (Exception exc)
            {
                MessageBox.Show(string.Format("Error compressing image:\r\n{0}", exc.Message));
                CompressCheckBox.Checked = currentState;
            }
            isLocked = false;
        }
Ejemplo n.º 4
0
        //I dunno why i'm being as masochistic as I am with this but okay.
        /// <summary>
        /// Creates the texture tables for all polygon models in this HXM file.
        /// </summary>
        private void BuildModelTextureTables()
        {
            //Write down unanimated texture names
            Dictionary <int, string> TextureNames = new Dictionary <int, string>();
            //Write down EClip IDs for tracking animated texture names
            Dictionary <int, string> EClipNames = new Dictionary <int, string>();
            EClip clip;

            for (int i = 0; i < BaseHAM.EClips.Count; i++)
            {
                clip = BaseHAM.EClips[i];
                if (clip.ChangingObjectTexture != -1)
                {
                    EClipNames.Add(clip.ChangingObjectTexture, clip.Name.ToLower());
                }
            }
            ushort bitmap; string name;

            for (int i = 0; i < BaseHAM.BaseFile.ObjBitmaps.Count; i++)
            {
                bitmap = GetObjBitmap(i);
                //if (bitmap == 0) continue;
                PIGImage image = BaseHAM.piggyFile.Bitmaps[bitmap];
                name = image.Name.ToLower();
                if (!image.IsAnimated)
                {
                    TextureNames.Add(i, name);
                }
            }
            foreach (Polymodel model in ReplacedModels)
            {
                model.UseTextureList = true;
                int textureID, pointer;
                for (int i = model.FirstTexture; i < (model.FirstTexture + model.NumTextures); i++)
                {
                    pointer   = GetObjBitmapPointer(i);
                    textureID = GetObjBitmap(pointer);
                    if (EClipNames.ContainsKey(pointer))
                    {
                        model.TextureList.Add(EClipNames[pointer]);
                    }
                    else if (TextureNames.ContainsKey(pointer))
                    {
                        model.TextureList.Add(TextureNames[pointer]);
                    }
                    else
                    {
                        model.TextureList.Add("bogus");
                    }
                }
                Console.Write("Model texture list: [");
                foreach (string texture in model.TextureList)
                {
                    Console.Write("{0} ", texture);
                }
                Console.WriteLine("]");
                model.BaseTexture = FindFirstObjBitmap(model);
            }
        }
Ejemplo n.º 5
0
        private string ImageFilename(int index)
        {
            PIGImage image = datafile.Bitmaps[index];

            if (!image.IsAnimated)
            {
                return(image.Name);
            }
            else
            {
                return(String.Format("{0}+{1}", image.Name, image.DFlags));
            }
        }
Ejemplo n.º 6
0
        public static void DumpPIGToBBM(PIGFile pigFile, Palette palette, string outputFilename)
        {
            LBMDecoder encoder   = new LBMDecoder();
            string     directory = Path.GetDirectoryName(outputFilename);

            int numFrames = 0;

            PIGImage[] frames = new PIGImage[50];
            PIGImage   image;

            for (int i = 0; i < pigFile.Bitmaps.Count; i++)
            {
                if (pigFile.Bitmaps[i].IsAnimated) //Special animation hacks
                {
                    image = pigFile.Bitmaps[i];
                    if (image.Frame == 0) //Start at the first frame
                    {
                        numFrames           = 0;
                        frames[numFrames++] = image;
                        if ((i + 1) >= pigFile.Bitmaps.Count)
                        {
                            return;                                   //out of images
                        }
                        while (image.Name == pigFile.Bitmaps[i + 1].Name)
                        {
                            frames[numFrames] = pigFile.Bitmaps[i + 1];
                            i++;
                            numFrames++;
                            if ((i + 1) >= pigFile.Bitmaps.Count)
                            {
                                break;                                   //out of images
                            }
                        }
                        BinaryWriter bw = new BinaryWriter(File.OpenWrite(string.Format("{0}{1}{2}.abm", directory, Path.DirectorySeparatorChar, image.Name)));
                        encoder.WriteABM(frames, numFrames, palette, bw);
                        bw.Close();
                        bw.Dispose();
                    }
                }
                else
                {
                    image = pigFile.Bitmaps[i];
                    BinaryWriter bw = new BinaryWriter(File.OpenWrite(string.Format("{0}{1}{2}.bbm", directory, Path.DirectorySeparatorChar, image.Name)));
                    encoder.WriteBBM(image, palette, bw);
                    bw.Close();
                    bw.Dispose();
                }
            }
        }
Ejemplo n.º 7
0
 private void InsertMenu_Click(object sender, EventArgs e)
 {
     openFileDialog1.Multiselect = true;
     if (openFileDialog1.ShowDialog() == DialogResult.OK)
     {
         foreach (string name in openFileDialog1.FileNames)
         {
             Bitmap   img    = new Bitmap(name);
             PIGImage bitmap = PiggyBitmapUtilities.CreatePIGImage(img, palette, Path.GetFileName(name).Substring(0, Math.Min(Path.GetFileName(name).Length, 8)));
             datafile.Bitmaps.Add(bitmap);
             ListViewItem lvi = GeneratePiggyEntry(datafile.Bitmaps.Count - 1);
             listView1.Items.Add(lvi);
             img.Dispose();
         }
     }
 }
        public static Bitmap GetBitmap(IImageProvider piggyFile, Palette palette, int index, int scale = 1)
        {
            int[]    rgbTable = new int[256];
            PIGImage image    = piggyFile.Bitmaps[index];

            int    newWidth  = (int)(image.Width * scale);
            int    newHeight = (int)(image.Height * scale);
            Bitmap bitmap    = new Bitmap(newWidth, newHeight);

            for (int j = 0; j < 256; j++)
            {
                rgbTable[j] = ((j == 255 ? 0 : 255) << 24) + (palette[j].R << 16) + (palette[j].G << 8) + (palette[j].B);
            }

            int[]  rgbData = new int[newWidth * newHeight];
            byte[] rawData = image.GetData();

            switch (scale)
            {
            case 1:
                Scale1X(image.Width, image.Height, newWidth, newHeight, rawData, rgbData, rgbTable);
                break;

            case 2:
                Scale2X(image.Width, image.Height, newWidth, newHeight, rawData, rgbData, rgbTable);
                break;

            case 3:
                Scale3X(image.Width, image.Height, newWidth, newHeight, rawData, rgbData, rgbTable);
                break;

            case 4:
                Scale4X(image.Width, image.Height, newWidth, newHeight, rawData, rgbData, rgbTable);
                break;
            }

            BitmapData bits = bitmap.LockBits(new Rectangle(0, 0, newWidth, newHeight), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

            System.Runtime.InteropServices.Marshal.Copy(rgbData, 0, bits.Scan0, newWidth * newHeight);
            bitmap.UnlockBits(bits);

            return(bitmap);
        }
Ejemplo n.º 9
0
        private ListViewItem GeneratePiggyEntry(int i)
        {
            PIGImage     image = datafile.Bitmaps[i];
            ListViewItem lvi   = new ListViewItem(image.Name);

            lvi.SubItems.Add(i.ToString());
            lvi.SubItems.Add(image.GetSize().ToString());
            lvi.SubItems.Add(string.Format("{0}x{1}", image.Width, image.Height));
            if (image.IsAnimated)
            {
                lvi.SubItems.Add(image.Frame.ToString());
            }
            else
            {
                lvi.SubItems.Add("-1");
            }

            return(lvi);
        }
Ejemplo n.º 10
0
 private void POGEditor_Load(object sender, EventArgs e)
 {
     for (int i = 0; i < datafile.Bitmaps.Count; i++)
     {
         PIGImage     image = (PIGImage)datafile.Bitmaps[i];
         ListViewItem lvi   = new ListViewItem(image.Name);
         lvi.SubItems.Add(image.GetSize().ToString());
         if (image.IsAnimated)
         {
             lvi.SubItems.Add(image.DFlags.ToString());
         }
         else
         {
             lvi.SubItems.Add("-1");
         }
         lvi.SubItems.Add(image.ReplacementNum.ToString());
         listView1.Items.Add(lvi);
     }
 }
        public static PIGImage CreatePIGImage(Bitmap bitmap, byte[] palette, byte[] invCmap, string newname)
        {
            if (bitmap.Width >= 4096 || bitmap.Height >= 4096)
            {
                throw new Exception("Bitmap resolution is too high for a PIG bitmap");
            }
            PIGImage image = new PIGImage(bitmap.Width, bitmap.Height, 0, 0, 0, 0, newname);

            byte[] data     = new byte[image.Width * image.Height];
            byte[] basedata = new byte[image.Width * image.Height * 4];

            BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

            System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, basedata, 0, basedata.Length);
            bitmap.UnlockBits(bitmapData);
            //todo: i dunno it probably can be optimzied
            int color;

            for (int i = 0; i < data.Length; i++)
            {
                if (basedata[i * 4 + 3] < 255)
                {
                    image.Transparent = true;
                    color             = 255;
                }
                else
                {
                    color = invCmap[(basedata[i * 4 + 2] >> 2) * 4096 + (basedata[i * 4 + 1] >> 2) * 64 + (basedata[i * 4] >> 2)];
                }
                data[i] = (byte)color;
            }

            image.Data = data;
            SetAverageColor(image, palette);
            //immediately try to compress if at all possible
            try
            {
                image.RLECompressed = true;
            }
            catch (Exception) { } //it didn't work
            return(image);
        }
Ejemplo n.º 12
0
        private void UpdateImage(int id)
        {
            if (pictureBox1.Image != null)
            {
                Bitmap temp = (Bitmap)pictureBox1.Image;
                pictureBox1.Image = null;
                temp.Dispose();
            }
            PIGImage image = datafile.Bitmaps[listView1.SelectedIndices[0]];

            pictureBox1.Image             = PiggyBitmapUtilities.GetBitmap(datafile.Bitmaps[id], currentPalette);
            TransparentCheck.Checked      = image.Transparent;
            SupertransparentCheck.Checked = image.SuperTransparent;
            NoLightingCheck.Checked       = image.NoLighting;
            CompressCheckBox.Checked      = image.RLECompressed;
            Color color = Color.FromArgb(currentPalette.GetRGBAValue(image.AverageIndex));

            ColorPreview.BackColor = color;
            pictureBox1.Refresh();
        }
Ejemplo n.º 13
0
        public static void SetAverageColor(PIGImage image, Palette palette)
        {
            byte[] data = image.GetData();
            byte   c;
            int    totalr = 0, totalg = 0, totalb = 0;

            for (int i = 0; i < data.Length; i++)
            {
                c       = data[i];
                totalr += palette[c, 0];
                totalg += palette[c, 1];
                totalb += palette[c, 2];
            }

            totalr /= data.Length;
            totalg /= data.Length;
            totalb /= data.Length;

            image.AverageIndex = (byte)palette.GetNearestColor(totalr, totalg, totalb);
        }
        public static void SetAverageColor(PIGImage image, byte[] palette)
        {
            byte[] data = image.GetData();
            int    c;
            int    totalr = 0, totalg = 0, totalb = 0;

            for (int i = 0; i < data.Length; i++)
            {
                c       = data[i] * 3;
                totalr += palette[c];
                totalg += palette[c + 1];
                totalb += palette[c + 2];
            }

            totalr /= data.Length;
            totalg /= data.Length;
            totalb /= data.Length;

            image.AverageIndex = (byte)GetNearestColorIndex(totalr, totalg, totalb, palette);
        }
Ejemplo n.º 15
0
 private void ExportILBMMenu_Click(object sender, EventArgs e)
 {
     saveFileDialog1.Filter = "Deluxe Paint Brush|*.bbm";
     if (panel.SelectedIndices.Count > 1)
     {
         saveFileDialog1.FileName = "ignored";
     }
     else
     {
         saveFileDialog1.FileName = ImageFilename(panel.SelectedIndices[0]);//listView1.Items[listView1.SelectedIndices[0]].Text;
     }
     if (saveFileDialog1.ShowDialog() == DialogResult.OK)
     {
         if (panel.SelectedIndices.Count > 1)
         {
             string directory = Path.GetDirectoryName(saveFileDialog1.FileName);
             foreach (int index in panel.SelectedIndices)
             {
                 PIGImage     image   = datafile.Bitmaps[index];
                 string       newpath = directory + Path.DirectorySeparatorChar + ImageFilename(index) + ".bbm";
                 BinaryWriter bw      = new BinaryWriter(File.Open(newpath, FileMode.Create));
                 lbmDecoder.WriteBBM(image, palette, bw);
                 bw.Flush();
                 bw.Close();
                 bw.Dispose();
             }
         }
         else
         {
             if (saveFileDialog1.FileName != "")
             {
                 PIGImage     image = datafile.Bitmaps[panel.SelectedIndices[0]];
                 BinaryWriter bw    = new BinaryWriter(File.Open(saveFileDialog1.FileName, FileMode.Create));
                 lbmDecoder.WriteBBM(image, palette, bw);
                 bw.Flush();
                 bw.Close();
                 bw.Dispose();
             }
         }
     }
 }
        public static Bitmap GetBitmap(PIGImage image, Palette palette)
        {
            Bitmap bitmap = new Bitmap(image.Width, image.Height);

            int[]  rgbData = new int[image.Width * image.Height];
            byte[] rawData = image.GetData();
            byte   b;

            for (int i = 0; i < rawData.Length; i++)
            {
                b          = rawData[i];
                rgbData[i] = ((b == 255 ? 0 : 255) << 24) + (palette[b].R << 16) + (palette[b].G << 8) + (palette[b].B);
            }

            BitmapData bits = bitmap.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

            System.Runtime.InteropServices.Marshal.Copy(rgbData, 0, bits.Scan0, image.Width * image.Height);
            bitmap.UnlockBits(bits);

            return(bitmap);
        }
Ejemplo n.º 17
0
        /// <summary>
        ///
        /// </summary>
        //Ultimately, it is too much of a pain to stick to the object bitmap and object bitmap pointer tables
        //Instead, don't track them at all in the first place. Build a texture list for each model, and only
        //reconstruct the tables at the time of export
        public void BuildModelTextureTables()
        {
            //Write down unanimated texture names
            Dictionary <int, string> TextureNames = new Dictionary <int, string>();
            //Write down EClip IDs for tracking animated texture names
            Dictionary <int, string> EClipNames = new Dictionary <int, string>();
            EClip clip;

            for (int i = 0; i < EClips.Count; i++)
            {
                clip = EClips[i];
                if (clip.ChangingObjectTexture != -1)
                {
                    EClipNames.Add(clip.ChangingObjectTexture, this.EClips[i].Name.ToLower());
                    ObjBitmapMapping.Add(this.EClips[i].Name.ToLower(), clip.ChangingObjectTexture);
                }
            }
            ushort bitmap; string name;

            for (int i = 0; i < BaseFile.ObjBitmaps.Count; i++)
            {
                bitmap = BaseFile.ObjBitmaps[i];
                //if (bitmap == 0) continue; //UNDONE: it's entirely valid something could have referred to bogus
                //hack
                if (bitmap == 65535)
                {
                    bitmap = 0;
                }
                PIGImage image = piggyFile.Bitmaps[bitmap];
                name = image.Name.ToLower();
                if (!image.IsAnimated)
                {
                    TextureNames.Add(i, name);
                    if (!ObjBitmapMapping.ContainsKey(name))
                    {
                        ObjBitmapMapping.Add(name, i);
                    }
                }
            }
            foreach (Polymodel model in Models)
            {
                model.UseTextureList = true;
                int textureID, pointer;
                for (int i = model.FirstTexture; i < (model.FirstTexture + model.NumTextures); i++)
                {
                    pointer   = BaseFile.ObjBitmapPointers[i];
                    textureID = BaseFile.ObjBitmaps[pointer];
                    if (EClipNames.ContainsKey(pointer))
                    {
                        model.TextureList.Add(EClipNames[pointer]);
                    }
                    else if (TextureNames.ContainsKey(pointer))
                    {
                        model.TextureList.Add(TextureNames[pointer]);
                    }
                    else
                    {
                        model.TextureList.Add("bogus");
                    }
                }
                Console.Write("Model texture list: [");
                foreach (string texture in model.TextureList)
                {
                    Console.Write("{0} ", texture);
                }
                Console.WriteLine("]");
            }
        }
Ejemplo n.º 18
0
        public int WriteBBM(PIGImage image, Palette palette, bool overrideAlpha, BinaryWriter bw)
        {
            int bytesWritten = 0;

            byte[] data = image.GetData();

            //write FORM header
            bw.Write(0x4D524F46);
            //will update later on
            long loc = bw.BaseStream.Position;

            bw.Write(0);
            //Note it as a PBM
            bw.Write(0x204D4250);
            bytesWritten += 4;

            //Write the BITMAP header
            bw.Write(0x44484D42);// 42 4D 48 44
            WriteInt32BE(bw, 0x14);
            bytesWritten += 8;

            //resolution
            WriteUInt16BE(bw, (ushort)image.Width);
            WriteUInt16BE(bw, (ushort)image.Height);
            //offset
            WriteUInt16BE(bw, 0);
            WriteUInt16BE(bw, 0);
            //num planes
            bw.Write((byte)8);
            //mask mode
            if (overrideAlpha)
            {
                bw.Write((byte)2);
            }
            else
            {
                bw.Write((byte)0);
            }
            //no compression
            bw.Write((byte)0);
            //pad
            bw.Write((byte)0);
            //transparent index
            WriteUInt16BE(bw, 255);
            //aspect ratio
            bw.Write((byte)5);
            bw.Write((byte)6);
            //screen size
            WriteUInt16BE(bw, 320);
            WriteUInt16BE(bw, 200);
            bytesWritten += 0x14;

            //Write the palette
            //43 4D 41 50
            bw.Write(0x50414D43);
            WriteInt32BE(bw, 0x300);
            bytesWritten += 8;
            for (int c = 0; c < 256; c++)
            {
                bw.Write(palette[c, 0]);
                bw.Write(palette[c, 1]);
                bw.Write(palette[c, 2]);
            }
            bytesWritten += 0x300;
            //Write the body
            //42 4F 44 59
            int  pixelcount    = image.Width * image.Height;
            bool alignmentHack = false;

            //To this day I still have no clue what this hack is supposed to be for,
            //but the original game's IFF decoder seems to require it. It causes problems in DPaint,
            //which confuses me.
            if (image.Width % 2 != 0)
            {
                pixelcount    = (image.Width + 1) * image.Height;
                alignmentHack = true;
            }
            bw.Write(0x59444F42);
            WriteInt32BE(bw, pixelcount);
            bytesWritten += 8;
            if (alignmentHack)
            {
                for (int y = 0; y < image.Height; y++)
                {
                    for (int x = 0; x < image.Width; x++)
                    {
                        bw.Write(data[y * image.Width + x]);
                    }
                    bw.Write((byte)0);
                }
            }
            else
            {
                for (int i = 0; i < pixelcount; i++)
                {
                    bw.Write(data[i]);
                }
            }
            bytesWritten += pixelcount;

            long end = bw.BaseStream.Position;

            bw.BaseStream.Seek(loc, SeekOrigin.Begin);
            WriteInt32BE(bw, bytesWritten);
            bw.BaseStream.Seek(end, SeekOrigin.Begin);

            return(bytesWritten + 8);
        }
Ejemplo n.º 19
0
        public int WriteABMFrame(PIGImage image, Palette palette, BinaryWriter bw)
        {
            int bytesWritten = 0;

            byte[] data = image.GetData();

            //write FORM header
            bw.Write(0x4D524F46);
            //will update later on
            long loc = bw.BaseStream.Position;

            bw.Write(0);
            //Note it as a PBM
            bw.Write(0x204D4250);
            bytesWritten += 4;

            //Write the ANHD header
            //41 4E 48 44
            bw.Write(0x44484E41);
            WriteInt32BE(bw, 40);
            bytesWritten += 8;
            //delta mode
            bw.Write((byte)0);
            //mask
            bw.Write((byte)0);
            //wh for xor mode
            WriteInt16BE(bw, (short)image.Width);
            WriteInt16BE(bw, (short)image.Height);
            //xy for xor mode
            WriteInt16BE(bw, 0);
            WriteInt16BE(bw, 0);
            //abstime
            WriteInt32BE(bw, 1);
            //reltime
            WriteInt32BE(bw, 1);
            //interleave
            bw.Write((byte)0);
            //pad
            bw.Write((byte)0);
            //flags
            WriteInt32BE(bw, 0);
            //pad
            bw.Write(new byte[16]);
            bytesWritten += 40;

            //Write the body
            //42 4F 44 59
            int  pixelcount    = image.Width * image.Height;
            bool alignmentHack = false;

            //To this day I still have no clue what this hack is supposed to be for,
            //but the original game's IFF decoder seems to require it. It causes problems in DPaint,
            //which confuses me.
            if (image.Width % 2 != 0)
            {
                pixelcount    = (image.Width + 1) * image.Height;
                alignmentHack = true;
            }
            bw.Write(0x59444F42);
            WriteInt32BE(bw, pixelcount);
            bytesWritten += 8;
            if (alignmentHack)
            {
                for (int y = 0; y < image.Height; y++)
                {
                    for (int x = 0; x < image.Width; x++)
                    {
                        bw.Write(data[y * image.Width + x]);
                    }
                    bw.Write((byte)0);
                }
            }
            else
            {
                for (int i = 0; i < pixelcount; i++)
                {
                    bw.Write(data[i]);
                }
            }
            bytesWritten += pixelcount;

            long end = bw.BaseStream.Position;

            bw.BaseStream.Seek(loc, SeekOrigin.Begin);
            WriteInt32BE(bw, bytesWritten);
            bw.BaseStream.Seek(end, SeekOrigin.Begin);

            return(bytesWritten + 8);
        }