Exemple #1
0
        public static PmsHeader GetHeader(byte[] bytes)
        {
            if (bytes.Length < 44)
            {
                throw new InvalidDataException("PMS header is too short");
            }

            var ms = new MemoryStream(bytes);
            var br = new BinaryReader(ms);

            PmsHeader pms = new PmsHeader();

            pms.signature        = br.ReadUInt16();
            pms.version          = br.ReadUInt16();
            pms.headerSize       = br.ReadUInt16();
            pms.colorDepth       = br.ReadByte();
            pms.shadowDepth      = br.ReadByte();
            pms.isSprite         = br.ReadUInt16();
            pms.paletteBank      = br.ReadUInt16();
            pms.word0C           = br.ReadInt32();
            pms.xLocation        = br.ReadInt32();
            pms.yLocation        = br.ReadInt32();
            pms.width            = br.ReadInt32();
            pms.height           = br.ReadInt32();
            pms.addressOfData    = br.ReadInt32();
            pms.addressOfPalette = br.ReadInt32();
            pms.addressOfComment = br.ReadInt32();

            int lastHeaderAddress  = Math.Max(pms.headerSize, pms.addressOfPalette);
            int lastHeaderAddress2 = Math.Max(pms.headerSize, pms.addressOfData);

            lastHeaderAddress = Math.Min(lastHeaderAddress, lastHeaderAddress2);
            if (lastHeaderAddress > bytes.Length)
            {
                lastHeaderAddress = bytes.Length;
            }

            int extraDataSize = lastHeaderAddress - (int)ms.Position;

            if (extraDataSize >= 1024 * 1024)
            {
                throw new InvalidDataException("Too much extra data for PMS file");
            }

            if (extraDataSize >= 0)
            {
                pms.extraData = br.ReadBytes(extraDataSize);
            }

            /*
             * if (pms.addressOfComment != 0)
             * {
             * ms.Position = pms.addressOfComment;
             * pms.comment = br.ReadStringNullTerminated();
             * }
             */

            return(pms);
        }
Exemple #2
0
        /*
         * Get palette from raw data
         *   pal: palette to be stored
         *   b  : raw data (pointer to palette)
         */
        internal static void GetPalette(Palette palette, PmsHeader pmsHeader, byte[] bytes)
        {
            int address = pmsHeader.addressOfPalette;
            int i;

            for (i = 0; i < 256; i++)
            {
                palette[i] = Color.FromArgb(bytes[address + i * 3 + 0], bytes[address + i * 3 + 1], bytes[address + i * 3 + 2]);
            }
        }
Exemple #3
0
        public PmsHeader ToPmsHeader()
        {
            var pmsHeader = new PmsHeader();

            pmsHeader.addressOfData    = 0x320;
            pmsHeader.addressOfPalette = 0x20;
            pmsHeader.colorDepth       = 8;
            pmsHeader.headerSize       = 0x20;
            pmsHeader.paletteBank      = this.paletteBank;
            pmsHeader.height           = this.height;
            pmsHeader.width            = ((this.width + 7) / 8) * 8;
            pmsHeader.xLocation        = this.xLocation;
            pmsHeader.yLocation        = this.yLocation;
            return(pmsHeader);
        }
Exemple #4
0
        public static void SaveHeader(Stream stream, PmsHeader pms)
        {
            long startPosition = stream.Position;

            var bw = new BinaryWriter(stream);

            bw.Write((ushort)pms.signature);
            bw.Write((ushort)pms.version);
            bw.Write((ushort)pms.headerSize);
            bw.Write((byte)pms.colorDepth);
            bw.Write((byte)pms.shadowDepth);
            bw.Write((ushort)pms.isSprite);
            bw.Write((ushort)pms.paletteBank);
            bw.Write((int)pms.word0C);
            bw.Write((int)pms.xLocation);
            bw.Write((int)pms.yLocation);
            bw.Write((int)pms.width);
            bw.Write((int)pms.height);
            bw.Write((int)pms.addressOfData);
            bw.Write((int)pms.addressOfPalette);
            bw.Write((int)pms.addressOfComment);

            long endPosition   = stream.Position;
            int  currentLength = (int)(endPosition - startPosition);

            if (currentLength < pms.headerSize)
            {
                int extraDataLength = pms.headerSize - currentLength;
                if (pms.extraData != null && pms.extraData.Length >= extraDataLength)
                {
                    stream.Write(pms.extraData, 0, extraDataLength);
                }
                else if (pms.extraData != null)
                {
                    //shouldn't ever happen
                    int lengthFromArray = pms.extraData.Length;
                    stream.Write(pms.extraData, 0, lengthFromArray);
                    stream.WriteZeroes(extraDataLength - lengthFromArray);
                }
                else
                {
                    stream.WriteZeroes(extraDataLength);
                }
            }
        }
Exemple #5
0
        internal static ushort[] GetImageData16Bit(PmsHeader pmsHeader, byte[] bytes)
        {
            ushort[] pic          = new ushort[pmsHeader.width * pmsHeader.height];
            int      bytePosition = pmsHeader.addressOfData;

            int c0, c1, pc0, pc1;
            int x, y, i, l, loc;
            int scanline = pmsHeader.width;

            for (y = 0; y < pmsHeader.height; y++)
            {
                for (x = 0; x < pmsHeader.width;)
                {
                    loc = y * scanline + x;
                    c0  = bytes[bytePosition++];
                    if (c0 <= 0xf7)
                    {
                        c1       = bytes[bytePosition++]; x++;
                        pic[loc] = (ushort)(c0 | (c1 << 8));
                    }
                    else if (c0 == 0xff)
                    {
                        l = bytes[bytePosition] + 2; x += l; bytePosition++;
                        for (i = 0; i < l; i++)
                        {
                            pic[loc + i] = pic[loc + i - scanline];
                        }
                    }
                    else if (c0 == 0xfe)
                    {
                        l = bytes[bytePosition] + 2; x += l; bytePosition++;
                        for (i = 0; i < l; i++)
                        {
                            pic[loc + i] = pic[loc + i - scanline * 2];
                        }
                    }
                    else if (c0 == 0xfd)
                    {
                        l   = bytes[bytePosition] + 3; x += l; bytePosition++;
                        c0  = bytes[bytePosition++]; c1 = bytes[bytePosition++];
                        pc0 = c0 | (c1 << 8);
                        for (i = 0; i < l; i++)
                        {
                            pic[loc + i] = (ushort)pc0;
                        }
                    }
                    else if (c0 == 0xfc)
                    {
                        l  = (bytes[bytePosition] + 2) * 2; x += l; bytePosition++;
                        c0 = bytes[bytePosition++]; c1 = bytes[bytePosition++]; pc0 = c0 | (c1 << 8);
                        c0 = bytes[bytePosition++]; c1 = bytes[bytePosition++]; pc1 = c0 | (c1 << 8);
                        for (i = 0; i < l; i += 2)
                        {
                            pic[loc + i]     = (ushort)pc0;
                            pic[loc + i + 1] = (ushort)pc1;
                        }
                    }
                    else if (c0 == 0xfb)
                    {
                        x++;
                        pic[loc] = pic[loc - scanline - 1];
                    }
                    else if (c0 == 0xfa)
                    {
                        x++;
                        pic[loc] = pic[loc - scanline + 1];
                    }
                    else if (c0 == 0xf9)
                    {
                        l        = bytes[bytePosition] + 1; x += l; bytePosition++;
                        c0       = bytes[bytePosition++]; c1 = bytes[bytePosition++];
                        pc0      = ((c0 & 0xe0) << 8) + ((c0 & 0x18) << 6) + ((c0 & 0x07) << 2);
                        pc1      = ((c1 & 0xc0) << 5) + ((c1 & 0x3c) << 3) + (c1 & 0x03);
                        pic[loc] = (ushort)(pc0 + pc1);
                        for (i = 1; i < l; i++)
                        {
                            c1           = bytes[bytePosition++];
                            pc1          = ((c1 & 0xc0) << 5) + ((c1 & 0x3c) << 3) + (c1 & 0x03);
                            pic[loc + i] = (ushort)(pc0 | pc1);
                        }
                    }
                    else
                    {
                        c0       = bytes[bytePosition++]; c1 = bytes[bytePosition++]; x++;
                        pic[loc] = (ushort)(c0 | (c1 << 8));
                    }
                }
            }
            return(pic);
        }
Exemple #6
0
        internal static byte[] GetImageData8Bit(PmsHeader pms, byte[] bytes, int addressOfData)
        {
            byte[] pic = new byte[pms.width * pms.height];
            int    address = addressOfData;
            int    c0, c1;
            int    x, y, loc, l, i;
            int    scanline = pms.width;

            for (y = 0; y < pms.height; y++)
            {
                for (x = 0; x < pms.width;)
                {
                    int a0 = address;
                    loc = y * scanline + x;
                    if (bytes.Length >= address)
                    {
                        break;
                    }
                    c0 = bytes[address++];

                    if (c0 <= 0xf7)
                    {
                        //literal
                        pic[loc] = (byte)c0; x++;
                    }
                    else if (c0 == 0xff)
                    {
                        //copy N+3 bytes from previous scanline
                        l = bytes[address] + 3; x += l; address++;
                        //if (loc - scanline > 0)
                        memcpy(pic, loc, pic, loc - scanline, l);
                    }
                    else if (c0 == 0xfe)
                    {
                        //copy N+3 bytes from two scanlines ago
                        l = bytes[address] + 3; x += l; address++;
                        //if (loc - scanline * 2 > 0)
                        memcpy(pic, loc, pic, loc - scanline * 2, l);
                    }
                    else if (c0 == 0xfd)
                    {
                        //fill with N+4 bytes of the next value
                        l  = bytes[address] + 4; x += l; address++;
                        c0 = bytes[address++];
                        memset(pic, loc, (byte)c0, l);
                    }
                    else if (c0 == 0xfc)
                    {
                        //fill with alternating bytes N+3 times
                        l  = (bytes[address] + 3) * 2; x += l; address++;
                        c0 = bytes[address++]; c1 = bytes[address++];
                        for (i = 0; i < l; i += 2)
                        {
                            pic[loc + i]     = (byte)c0;
                            pic[loc + i + 1] = (byte)c1;
                        }
                    }
                    else
                    {
                        //copy byte
                        pic[loc] = bytes[address++]; x++;
                    }
                    if (x > pms.width)
                    {
                    }
                }
            }
            return(pic);
        }
Exemple #7
0
 /*
  * Do extract 8bit pms image
  *   pms: pms header information
  *   pic: pixel to be stored
  *   b  : raw data (pointer to pixel)
  */
 internal static byte[] GetImageData8Bit(PmsHeader pms, byte[] bytes)
 {
     return(GetImageData8Bit(pms, bytes, pms.addressOfData));
 }
Exemple #8
0
        public static void SaveImage(Stream stream, FreeImageBitmap bitmap)
        {
            string comment     = bitmap.Comment;
            var    pmsHeader   = new PmsHeader();
            bool   readComment = false;

            if (!string.IsNullOrEmpty(comment))
            {
                if (pmsHeader.ParseComment(comment))
                {
                    readComment = true;
                }
            }

            if (pmsHeader.colorDepth == 0)
            {
                pmsHeader.colorDepth = 8;
            }

            bool is8Bit = !readComment || pmsHeader.colorDepth == 8;

            if (!readComment)
            {
                pmsHeader.version    = 1;
                pmsHeader.headerSize = 48;
            }
            if (pmsHeader.signature == 0)
            {
                pmsHeader.signature = 0x00004d50;
            }
            if (pmsHeader.version == 2 && pmsHeader.headerSize == 0)
            {
                pmsHeader.headerSize = 64;
            }
            if (pmsHeader.headerSize < 48)
            {
                pmsHeader.headerSize = 48;
            }
            if (pmsHeader.headerSize > 64)
            {
                pmsHeader.headerSize = 64;
            }
            pmsHeader.addressOfComment = 0;
            pmsHeader.height           = bitmap.Height;
            pmsHeader.width            = bitmap.Width;

            if (is8Bit)
            {
                if (bitmap.ColorDepth > 8)
                {
                    if (bitmap.ColorDepth == 32)
                    {
                        bitmap.ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_24_BPP);
                    }
                    bitmap.Quantize(FREE_IMAGE_QUANTIZE.FIQ_WUQUANT, 256);
                    //throw new ArgumentException("image must be 8-bit");
                }

                pmsHeader.addressOfPalette = pmsHeader.headerSize;
                pmsHeader.addressOfData    = pmsHeader.addressOfPalette + 768;
                pmsHeader.colorDepth       = 8;

                SaveHeader(stream, pmsHeader);
                SavePalette(stream, bitmap.Palette);
                SaveImageData8Bit(stream, bitmap);
            }
            else
            {
                bool hasAlphaChannel      = false;
                var  existingAlphaChannel = bitmap.GetChannel(FREE_IMAGE_COLOR_CHANNEL.FICC_ALPHA);
                if (existingAlphaChannel != null)
                {
                    bool allPixelsOpaque = AllPixelsOpaque(existingAlphaChannel);
                    hasAlphaChannel = !allPixelsOpaque;
                }
                if (bitmap.ColorDepth != 32)
                {
                    bitmap.ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_32_BPP);
                }

                bool usingAlphaChannel = pmsHeader.shadowDepth == 8 || (pmsHeader.shadowDepth == 0 && hasAlphaChannel);

                pmsHeader.addressOfPalette = 0;
                pmsHeader.addressOfData    = pmsHeader.headerSize;
                pmsHeader.colorDepth       = 16;

                ushort[] image16 = new ushort[pmsHeader.width * pmsHeader.height];
                byte[]   image8  = null;
                if (usingAlphaChannel)
                {
                    image8 = new byte[pmsHeader.width * pmsHeader.height];
                }
                int o = 0;
                for (int y = 0; y < pmsHeader.height; y++)
                {
                    var scanline = bitmap.GetScanlineFromTop32Bit(y);

                    if (image8 == null)
                    {
                        for (int x = 0; x < pmsHeader.width; x++)
                        {
                            unchecked
                            {
                                int p = scanline[x];
                                int b = (p >> 0) & 0xFF;
                                int g = (p >> 8) & 0xFF;
                                int r = (p >> 16) & 0xFF;
                                //int a = (p >> 24) & 0xFF;
                                b = (b * 0x1F1F + 0x8000) >> 16;
                                g = (g * 0x3F3F + 0x8000) >> 16;
                                r = (r * 0x1F1F + 0x8000) >> 16;
                                p = (b << 0) |
                                    (g << 5) |
                                    (r << 11);
                                image16[o] = (ushort)p;
                                o++;
                            }
                        }
                    }
                    else
                    {
                        for (int x = 0; x < pmsHeader.width; x++)
                        {
                            unchecked
                            {
                                int p = scanline[x];
                                int b = (p >> 0) & 0xFF;
                                int g = (p >> 8) & 0xFF;
                                int r = (p >> 16) & 0xFF;
                                int a = (p >> 24) & 0xFF;
                                b = (b * 0x1F1F + 0x8000) >> 16;
                                g = (g * 0x3F3F + 0x8000) >> 16;
                                r = (r * 0x1F1F + 0x8000) >> 16;
                                p = (b << 0) |
                                    (g << 5) |
                                    (r << 11);
                                image16[o] = (ushort)p;
                                image8[o]  = (byte)a;
                                o++;
                            }
                        }
                    }
                }
                MemoryStream ms = new MemoryStream();

                SaveImageData16Bit(ms, image16, pmsHeader.width, pmsHeader.height);
                int imageSize = (int)ms.Length;
                if (usingAlphaChannel)
                {
                    pmsHeader.addressOfPalette = imageSize + pmsHeader.addressOfData;
                }
                SaveHeader(stream, pmsHeader);
                ms.WriteTo(stream);
                ms.SetLength(0);
                if (usingAlphaChannel)
                {
                    SaveImageData8Bit(stream, image8, pmsHeader.width, pmsHeader.height);
                }
            }
        }