예제 #1
0
        public static unsafe void RemapPalette(FreeImageBitmap bitmap, FreeImageBitmap referenceImage, int numberOfColors)
        {
            using (FreeImageBitmap bitmap32 = bitmap.GetColorConvertedInstance(FREE_IMAGE_COLOR_DEPTH.FICD_32_BPP))
            {
                if (referenceImage.Height < bitmap.Height || referenceImage.Width < bitmap.Width)
                {
                    int h2 = referenceImage.Height;
                    if (h2 < bitmap.Height)
                    {
                        h2 = bitmap.Height;
                    }
                    int w2 = referenceImage.Width;
                    if (w2 < bitmap.Width)
                    {
                        w2 = bitmap.Width;
                    }
                    referenceImage.EnlargeCanvas <byte>(0, 0, w2 - referenceImage.Width, h2 - referenceImage.Height, 0);
                }

                //FreeImageBitmap reference32 = bitmap.GetColorConvertedInstance(FREE_IMAGE_COLOR_DEPTH.FICD_32_BPP);

                if (bitmap.ColorDepth != 8)
                {
                    bitmap.ConvertColorDepth(FREE_IMAGE_COLOR_DEPTH.FICD_08_BPP);
                }
                int *newPalette = (int *)(referenceImage.Palette.BaseAddress);

                int h = bitmap.Height;
                int w = bitmap.Width;

                //Ties are broken in ColorToIndex by popularity in the original image
                Dictionary <int, int> ColorToIndex = new Dictionary <int, int>();
                int[] ColorHistogram = new int[256];
                for (int y = 0; y < h; y++)
                {
                    byte *srcScanline = (byte *)(referenceImage.GetScanlineFromTop8Bit(y).BaseAddress);
                    for (int x = 0; x < w; x++)
                    {
                        int c = srcScanline[x];
                        ColorHistogram[c]++;
                    }
                }

                //add each palette color to the dictionary
                for (int i = 0; i < numberOfColors; i++)
                {
                    int c = newPalette[i] & 0xFFFFFF;
                    if (ColorToIndex.ContainsKey(c))
                    {
                        int otherIndex = ColorToIndex[c];
                        if (ColorHistogram[i] > ColorHistogram[otherIndex])
                        {
                            ColorToIndex[c] = i;
                        }
                    }
                    else
                    {
                        ColorToIndex[c] = i;
                    }
                }

                for (int y = 0; y < h; y++)
                {
                    int * trueColorScanline = (int *)(bitmap32.GetScanlineFromTop32Bit(y).BaseAddress);
                    byte *srcScanline       = (byte *)(bitmap.GetScanlineFromTop8Bit(y).BaseAddress);
                    byte *referenceScanline = (byte *)(referenceImage.GetScanlineFromTop8Bit(y).BaseAddress);

                    for (int x = 0; x < w; x++)
                    {
                        int srcColor = trueColorScanline[x] & 0xFFFFFF;
                        int refIndex = referenceScanline[x];
                        int refColor = newPalette[refIndex] & 0xFFFFFF;
                        if (srcColor == refColor)
                        {
                            srcScanline[x] = (byte)refIndex;
                        }
                        else
                        {
                            if (ColorToIndex.ContainsKey(srcColor))
                            {
                                int newColorIndex = ColorToIndex[srcColor];
                                if (refColor == (newPalette[newColorIndex] & 0xFFFFFF))
                                {
                                    srcScanline[x] = (byte)refIndex;
                                }
                                else
                                {
                                    srcScanline[x] = (byte)newColorIndex;
                                }
                            }
                            else
                            {
                                float minDistance = float.MaxValue;
                                int   minIndex    = 0;
                                for (int i = 0; i < numberOfColors; i++)
                                {
                                    int   c        = newPalette[i] & 0xFFFFFF;
                                    float distance = GetDistanceF(srcColor, c);
                                    if (distance < minDistance)
                                    {
                                        minIndex    = i;
                                        minDistance = distance;
                                    }
                                    else if (distance == minDistance && ColorHistogram[i] > ColorHistogram[minIndex])
                                    {
                                        minIndex = i;
                                    }
                                }
                                if (refColor == (newPalette[minIndex] & 0xFFFFFF))
                                {
                                    srcScanline[x] = (byte)refIndex;
                                }
                                else
                                {
                                    srcScanline[x] = (byte)minIndex;
                                }
                                ColorToIndex.Add(srcColor, minIndex);
                            }
                        }
                    }
                }
                bitmap.Palette.AsArray = referenceImage.Palette.AsArray;
            }
        }
예제 #2
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);
                }
            }
        }