Пример #1
0
 /// <summary>
 /// Copy constructor. Performs a shallow copy, and creates a new,
 /// blank array of previous size in BitmapData
 /// </summary>
 /// <param name="old"></param>
 public BitmapBuilder(BitmapBuilder old)
 {
     PaletteSize      = old.PaletteSize;
     PaletteLocation  = old.PaletteLocation;
     DataLocation     = old.DataLocation;
     m_Width          = old.Width;
     m_Height         = old.Height;
     BitsPerPixel     = old.BitsPerPixel;
     m_BytesPerLine   = old.BytesPerLine;
     m_PaddingPerLine = old.PaddingPerLine;
     m_BitmapData     = new byte[old.BitmapData.Length];
 }
Пример #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="keyColor"></param>
        /// <param name="rawKeyColor"></param>
        /// <param name="dLeft"></param>
        /// <param name="dTop"></param>
        /// <returns></returns>
        public BitmapBuilder Crop(System.Drawing.Color keyColor, ushort rawKeyColor, out uint dLeft, out uint dTop)
        {
            BitmapBuilder newBB;

            switch (BitsPerPixel)
            {
            case 16:
                //
                // bottom cropping
                //
                uint cropBottom = 0;
                bool done       = false;

                for (long y = 0; y < Height; ++y)
                {
                    long i = DataLocation + BytesPerLine * y;
                    for (long x = 0; x < Width; ++x)
                    {
                        ushort color = (ushort)(BitmapData[i] + (BitmapData[i + 1] << 8));

                        if (color != rawKeyColor)
                        {
                            done = true;
                            break;
                        }
                        i += 2;
                    }
                    if (done)
                    {
                        break;
                    }
                    ++cropBottom;
                }

                // is the image all transparent?
                if (cropBottom == m_Height)
                {
                    // leave a 1x1 transparent image
                    newBB = new BitmapBuilder(BitsPerPixel, 1, 1);

                    newBB.BitmapData[BitmapHeaderSize] = (byte)(rawKeyColor & 0xFF);
                    newBB.BitmapData[BitmapHeaderSize] = (byte)((rawKeyColor >> 8) & 0xFF);
#if XDEBUG
                    rowsCropped    += m_Height - 1;
                    columnsCropped += m_Width - 1;
#endif
                    dLeft = 0;
                    dTop  = 0;
                    // done. exit
                    break;
                }

                //
                // top cropping
                //
                uint cropTop = 0;
                done = false;

                for (long y = Height - 1; y >= 0; --y)
                {
                    long i = DataLocation + BytesPerLine * y;
                    for (long x = 0; x < Width; ++x)
                    {
                        ushort color = (ushort)(BitmapData[i] + (BitmapData[i + 1] << 8));

                        if (color != rawKeyColor)
                        {
                            done = true;
                            break;
                        }
                        i += 2;
                    }
                    if (done)
                    {
                        break;
                    }
                    ++cropTop;
                }

                //
                // left cropping
                //
                uint cropLeft = 0;
                done = false;

                for (long x = 0; x < Width; ++x)
                {
                    for (long y = cropBottom; y < m_Height - cropTop; ++y)
                    {
                        long   i     = DataLocation + BytesPerLine * y + 2 * x;
                        ushort color = (ushort)(BitmapData[i] + (BitmapData[i + 1] << 8));

                        if (color != rawKeyColor)
                        {
                            done = true;
                            break;
                        }
                    }
                    if (done)
                    {
                        break;
                    }
                    ++cropLeft;
                }

                //
                // right cropping
                //
                uint cropRight = 0;
                done = false;

                for (long x = Width - 1; x >= 0; --x)
                {
                    for (long y = cropBottom; y < m_Height - cropTop; ++y)
                    {
                        long   i     = DataLocation + BytesPerLine * y + 2 * x;
                        ushort color = (ushort)(BitmapData[i] + (BitmapData[i + 1] << 8));

                        if (color != rawKeyColor)
                        {
                            done = true;
                            break;
                        }
                    }
                    if (done)
                    {
                        break;
                    }
                    ++cropRight;
                }

                //
                // do cropping
                //

                // do we have anything to crop?
                if (cropTop + cropBottom + cropLeft + cropRight > 0)
                {
                    uint newWidth  = (uint)(m_Width - cropLeft - cropRight);
                    uint newHeight = (uint)(m_Height - cropTop - cropBottom);

                    newBB = new BitmapBuilder(BitsPerPixel, newWidth, newHeight);

                    // bytes per line (to copy). without padding.
                    uint newBytesPerLine            = newBB.BytesPerLine - newBB.m_PaddingPerLine;
                    uint newBytesPerLineWithPadding = newBB.BytesPerLine;

                    for (int y = 0; y < newHeight; ++y)
                    {
                        Array.Copy(m_BitmapData, (int)(BitmapHeaderSize + (y + cropBottom) * BytesPerLine + 2 * cropLeft),
                                   newBB.BitmapData, (int)(BitmapHeaderSize + y * newBytesPerLineWithPadding),
                                   (int)newBytesPerLine);
                    }
                }
                else
                {
                    newBB = this;
                }

#if XDEBUG
                rowsCropped    += cropTop + cropBottom;
                columnsCropped += cropLeft + cropRight;
#endif

                dLeft = cropLeft;
                dTop  = cropTop;

                break;

            // TODO: image formats
            // we can and need currently only crop 16 bpp images
            // This might change when using custom animations
            case 4:
            case 8:
            case 24:
            default:
                throw new FormatException("Cannot remap unexpected"
                                          + " bitmap format "
                                          + BitsPerPixel + " bpp");
            }

#if XDEBUG
            bytesSavedByCropping += BitmapData.Length - newBB.BitmapData.Length;
            ++texturesCropped;
#endif
            return(newBB);
        }
Пример #3
0
        /// <summary>
        /// Remaps all pixels in the specified sequence state's frame that have
        /// a hue value of OriginalHue ± 45 (and a lightness less than 340) to the
        /// new values specified by <c>changes</c>
        /// </summary>
        /// <param name="srcFrame">
        /// the animation frame is frame is to be remapped
        /// </param>
        /// <param name="changes">
        /// a ColorRemapInfo specifying the destination color range
        /// </param>
        /// <returns>
        /// A remapped copy of the frame, or the original frame if nothing
        /// is to be done
        /// </returns>
        /// <remarks>
        /// This is an O(width*height) operation - and pixel operations are slow!
        /// If no changes are specified in <paramref name="changes" />, or if
        /// only a hue change with the original hue and new hue being the same is
        /// specified, the source frame is returned.
        /// </remarks>
        public static AnimationFrame Remap(AnimationFrame srcFrame, ColorRemapInfo changes)
        {
            AnimationFrame destFrame = new AnimationFrame(srcFrame);

            // if nothing has to be changed, just use the original BB
            if (!changes.SetSaturation && changes.DiffLightness == 0 &&
                (!changes.SetHue || changes.NewHue == OriginalHue))
            {
                destFrame.BitmapBuilder = srcFrame.BitmapBuilder;
                return(destFrame);
            }

            BitmapBuilder src  = srcFrame.BitmapBuilder;
            BitmapBuilder dest = new BitmapBuilder(src.BitsPerPixel, src.Width, src.Height);

            destFrame.BitmapBuilder = dest;

            // choose a new key color to make sure our remapped values don't end up transparent
            // these are empirical values that seem to work well, but can be changed if any problems arise
            ushort newRawKeyColor = 0x7A38;
            Color  newKeyColor    = Color.FromArgb(247, 140, 198);

            if (changes.SetHue && (changes.NewHue > 220 || changes.NewHue < 60))
            {
                newRawKeyColor = 0x47D8;
                newKeyColor    = Color.FromArgb(140, 247, 198);
            }
            System.Diagnostics.Debug.Assert(newRawKeyColor == ColorToShort(newKeyColor));
            byte newKeyColorL = (byte)(newRawKeyColor & 0xFF);
            byte newKeyColorH = (byte)(newRawKeyColor >> 8);

            destFrame.SetKeyColor(newRawKeyColor, newKeyColor);

            switch (src.BitsPerPixel)
            {
            // X1R5G5B5 little endian 16 bit color
            // (as found in most animations)
            case 16:
            {
                uint lineSize;

                if ((src.Width & 1U) == 0)
                {
                    lineSize = src.Width;
                }
                else
                {
                    lineSize = src.Width + 1;
                }

                uint padding = (lineSize - src.Width) << 1;

                // TODO: finish optimizing Remap
                // copy everything that's not image data
                //Array.Copy(src.BitmapData, dest.BitmapData, (int)src.DataLocation);

                long i         = src.DataLocation;
                long copyStart = 0;

                for (int y = 0; y < src.Height; ++y, i += padding)
                {
                    for (int x = 0; x < src.Width; ++x, i += 2)
                    {
                        ushort c = (ushort)(src.BitmapData[i]
                                            + (src.BitmapData[i + 1] << 8));

                        if (c == srcFrame.RawKeyColor)
                        {
                            if (i > copyStart)
                            {
                            }                                              // Array.Copy(src.BitmapData, (int)copyStart, dest.BitmapData, (int)copyStart, (int)(i - copyStart));
                            copyStart              = i + 2;
                            dest.BitmapData[i]     = newKeyColorL;
                            dest.BitmapData[i + 1] = newKeyColorH;
                            continue;
                        }

                        int R = (c >> 10) << 3,
                            G = ((c >> 5) & 0x1F) << 3,
                            B = (c & 0x1F) << 3;
                        //int R = (c >> 7) & ~7,
                        //	G = (c >> 2) & 0xF8,
                        //	B = (c & 0x1F) << 3;

                        R += (int)Math.Ceiling(R * 6.0f / 239.0f);
                        G += (int)Math.Ceiling(G * 6.0f / 239.0f);
                        B += (int)Math.Ceiling(B * 6.0f / 239.0f);

                        int h, s, l;
                        RGBToHSL(R, G, B, out h, out s, out l);

                        // apply changes to all green color
                        if (h > OriginalHue - 45 && h < OriginalHue + 45 && l < 340)
                        {
                            if (i > copyStart)
                            {
                            }                                              // Array.Copy(src.BitmapData, (int)copyStart, dest.BitmapData, (int)copyStart, (int)(i - copyStart));
                            copyStart = i + 2;
                            if (changes.SetHue)
                            {
                                h += changes.NewHue - OriginalHue;

                                if (h < 0)
                                {
                                    h += 360;
                                }
                            }
                            if (changes.SetSaturation)
                            {
                                s = changes.NewSaturation;
                            }
                            l += changes.DiffLightness;
                            if (l < 0)
                            {
                                l = 0;
                            }
                            else if (l > 359)
                            {
                                l = 359;
                            }

                            ushort to  = ColorToShort(ColorFromHSL(h, s, l));
                            byte   toL = (byte)(to & 0xFF);
                            byte   toH = (byte)(to >> 8);

                            dest.BitmapData[i]     = toL;
                            dest.BitmapData[i + 1] = toH;
                        }
                        else
                        {
                            dest.BitmapData[i]     = src.BitmapData[i];
                            dest.BitmapData[i + 1] = src.BitmapData[i + 1];
                        }
                    }
                }

                break;
            }

            // images that are not 16 bpp are not supported and it is unlikely
            // they ever will, as the original graphics use only 16 bpp, and
            // new ones will use completely different formats (and probably 32 bpp)
            default:
                throw new FormatException("Cannot remap unexpected"
                                          + " bitmap format "
                                          + src.BitsPerPixel + " bpp");
            }

            return(destFrame);
        }