Пример #1
0
        /// <summary>
        /// Copies a rectangular block of pixel data from a source image to a this image (Blt = BlockTransfer).
        /// </summary>
        /// <param name="xDst">The x destination coordinate (where to place the block within dst).</param>
        /// <param name="yDst">The y destination coordinate (where to place the block within dst).</param>
        /// <param name="src">The source image.</param>
        /// <param name="xSrc">The x source coordinate (where to start copying from within src).</param>
        /// <param name="ySrc">The y source coordinate (where to start copying from within src).</param>
        /// <param name="width">The width of the block to copy. (default is src.Width).</param>
        /// <param name="height">The height of the block to copy (default is src.Height).</param>
        /// <remarks>
        ///     All specified parameters are clipped to avoid out-of-bounds indices. No warnings or exceptions are issued
        ///     in case clipping results in a smaller or an empty block.
        /// </remarks>
        public void Blt(int xDst, int yDst, IImageData src, int xSrc = 0, int ySrc = 0, int width = 0, int height = 0)
        {
            if (width == 0)
            {
                width = src.Width;
            }
            if (height == 0)
            {
                height = src.Height;
            }

            ClipBlt(ref xDst, Width, ref xSrc, src.Width, ref width);
            ClipBlt(ref yDst, Height, ref ySrc, src.Height, ref height);

            if (width <= 0 || height <= 0)
            {
                return;
            }

            CopyFunc copyLine;

            if (PixelFormat.ColorFormat.Equals(src.PixelFormat.ColorFormat))
            {
                // Case: same color space, just loop over scanlines from src and copy line-wise into this ImageData
                copyLine = delegate(byte[] srcScanLineBytes, int destinationIndex)
                {
                    Array.Copy(srcScanLineBytes, 0, PixelData, destinationIndex, srcScanLineBytes.Length);
                };
            }
            else
            {
                // Wee need to perform pixel-conversion while copying. -> still GetLineBytes and then perform pixel conversion

                switch (PixelFormat.ColorFormat)
                {
                case ColorFormat.RGBA:
                    switch (src.PixelFormat.ColorFormat)
                    {
                    case ColorFormat.RGB:
                        copyLine = delegate(byte[] srcLineBytes, int destinationIndex)
                        {
                            for (int i = 0; i < srcLineBytes.Length; i += 3)         // jump 3 units per loop because we want to copy src RGB to dst RGBA
                            {
                                PixelData[destinationIndex + i + 0] = srcLineBytes[i + 0];
                                PixelData[destinationIndex + i + 1] = srcLineBytes[i + 1];
                                PixelData[destinationIndex + i + 2] = srcLineBytes[i + 2];
                                PixelData[destinationIndex + i + 3] = byte.MaxValue;
                            }
                        };
                        break;

                    case ColorFormat.Intensity:
                        copyLine = delegate(byte[] srcLineBytes, int destinationIndex)
                        {
                            for (int i = 0; i < srcLineBytes.Length; i++)         // jump 1 unit per loop because we want to copy src Intensity to dst RGBA
                            {
                                PixelData[destinationIndex + i + 0] = srcLineBytes[i];
                                PixelData[destinationIndex + i + 1] = srcLineBytes[i];
                                PixelData[destinationIndex + i + 2] = srcLineBytes[i];
                                PixelData[destinationIndex + i + 3] = byte.MaxValue;
                            }
                        };
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(src), "Unknown source pixel format to copy to RGBA");
                    }
                    break;

                case ColorFormat.RGB:
                    switch (src.PixelFormat.ColorFormat)
                    {
                    case ColorFormat.RGBA:

                        copyLine = delegate(byte[] srcLineBytes, int destinationIndex)
                        {
                            for (int i = 0; i < srcLineBytes.Length; i += 4)         // jump 4 units per loop because we want to copy src RGBA to dst RGB
                            {
                                PixelData[destinationIndex + i + 0] = srcLineBytes[i + 0];
                                PixelData[destinationIndex + i + 1] = srcLineBytes[i + 1];
                                PixelData[destinationIndex + i + 2] = srcLineBytes[i + 2];
                                // skip source alpha
                            }
                        };

                        break;

                    case ColorFormat.Intensity:
                        copyLine = delegate(byte[] srcLineBytes, int destinationIndex)
                        {
                            for (int i = 0; i < srcLineBytes.Length; i++)         // jump 1 unit per loop because we want to copy src Intensity to dst RGB
                            {
                                PixelData[destinationIndex + i + 0] = srcLineBytes[i];
                                PixelData[destinationIndex + i + 1] = srcLineBytes[i];
                                PixelData[destinationIndex + i + 2] = srcLineBytes[i];
                            }
                        };
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(src), "Unknown source pixel format to copy to RGB");
                    }
                    break;

                case ColorFormat.Intensity:
                    switch (src.PixelFormat.ColorFormat)
                    {
                    case ColorFormat.RGB:
                        copyLine = delegate(byte[] srcLineBytes, int destinationIndex)
                        {
                            for (int i = 0; i < srcLineBytes.Length; i += 3)         // jump 3 units per loop because we want to copy src RGB to dst Intensity
                            {
                                // Quick integer Luma conversion (not accurate)
                                // See http://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
                                int r = srcLineBytes[destinationIndex + i + 0];
                                int g = srcLineBytes[destinationIndex + i + 1];
                                int b = srcLineBytes[destinationIndex + i + 2];
                                PixelData[destinationIndex + i] = (byte)((r + r + b + g + g + g) / 6);
                            }
                        };
                        break;

                    case ColorFormat.RGBA:
                        copyLine = delegate(byte[] srcLineBytes, int destinationIndex)
                        {
                            for (int i = 0; i < srcLineBytes.Length; i += 4)         // jump 4 units per loop because we want to copy src RGBA to dst Intensity
                            {
                                // Quick integer Luma conversion (not accurate)
                                // See http://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
                                int r = srcLineBytes[destinationIndex + i + 0];
                                int g = srcLineBytes[destinationIndex + i + 1];
                                int b = srcLineBytes[destinationIndex + i + 2];
                                PixelData[destinationIndex + i] = (byte)((r + r + b + g + g + g) / 6);
                            }
                        };
                        break;

                    default:
                        throw new ArgumentOutOfRangeException(nameof(src), "Unknown source pixel format to copy to RGB");
                    }
                    break;

                default:
                    throw new ArgumentOutOfRangeException(ToString(), "Unknown destination pixel format");
                } // end switch
            }     // end else block

            // loop over the ScanLineEnumerator and call CopyLine delegate
            var srcEnumerator = src.ScanLines(xSrc, ySrc, width, height);

            while (srcEnumerator.MoveNext())
            {
                var srcScanLine = srcEnumerator.Current;
                if (srcScanLine != null)
                {
                    byte[] srcScanLineBytes = srcScanLine.GetScanLineBytes();
                    int    destinationIndex = yDst * PixelFormat.BytesPerPixel * Width + xDst * PixelFormat.BytesPerPixel; // move down by yDst and add (move right) xDst
                    copyLine(srcScanLineBytes, destinationIndex);
                    yDst++;                                                                                                // increment yDst == move to the next line
                }
            }
        }