Esempio n. 1
0
        /// <summary>
        ///     Copies a region of the source bitmap into this fast bitmap
        /// </summary>
        /// <param name="source">The source image to copy</param>
        /// <param name="srcRect">The region on the source bitmap that will be copied over</param>
        /// <param name="destRect">The region on this fast bitmap that will be changed</param>
        /// <exception cref="ArgumentException">The provided source bitmap is the same bitmap locked in this FastBitmap</exception>
        public void CopyRegion(Bitmap source, Rectangle srcRect, Rectangle destRect)
        {
            // Throw exception when trying to copy same bitmap over
            if (source == _bitmap)
            {
                throw new ArgumentException(@"Copying regions across the same bitmap is not supported", nameof(source));
            }

            var srcBitmapRect  = new Rectangle(0, 0, source.Width, source.Height);
            var destBitmapRect = new Rectangle(0, 0, Width, Height);

            // Check if the rectangle configuration doesn't generate invalid states or does not affect the target image
            if (srcRect.Width <= 0 || srcRect.Height <= 0 || destRect.Width <= 0 || destRect.Height <= 0 ||
                !srcBitmapRect.IntersectsWith(srcRect) || !destRect.IntersectsWith(destBitmapRect))
            {
                return;
            }

            // Find the areas of the first and second bitmaps that are going to be affected
            srcBitmapRect = Rectangle.Intersect(srcRect, srcBitmapRect);

            // Clip the source rectangle on top of the destination rectangle in a way that clips out the regions of the original bitmap
            // that will not be drawn on the destination bitmap for being out of bounds
            srcBitmapRect = Rectangle.Intersect(srcBitmapRect
                                                , new Rectangle(srcRect.X, srcRect.Y, destRect.Width, destRect.Height));

            destBitmapRect = Rectangle.Intersect(destRect, destBitmapRect);

            // Clip the source bitmap region yet again here
            srcBitmapRect = Rectangle.Intersect(srcBitmapRect
                                                , new Rectangle(-destRect.X + srcRect.X, -destRect.Y + srcRect.Y, Width, Height));

            // Calculate the rectangle containing the maximum possible area that is supposed to be affected by the copy region operation
            int copyWidth  = Math.Min(srcBitmapRect.Width, destBitmapRect.Width);
            int copyHeight = Math.Min(srcBitmapRect.Height, destBitmapRect.Height);

            if (copyWidth == 0 || copyHeight == 0)
            {
                return;
            }

            int srcStartX = srcBitmapRect.Left;
            int srcStartY = srcBitmapRect.Top;

            int destStartX = destBitmapRect.Left;
            int destStartY = destBitmapRect.Top;

            using (var fastSource = source.FastLock()) {
                ulong strideWidth = (ulong)copyWidth * BytesPerPixel;

                // Perform copies of whole pixel rows
                for (int y = 0; y < copyHeight; y++)
                {
                    int destX = destStartX;
                    int destY = destStartY + y;

                    int srcX = srcStartX;
                    int srcY = srcStartY + y;

                    long offsetSrc  = srcX + srcY * fastSource.Stride;
                    long offsetDest = destX + destY * Stride;

                    NativeMethod.Memcpy(_scan0 + offsetDest, fastSource._scan0 + offsetSrc, strideWidth);
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        ///     Clears a square region of this image w/ a given color
        /// </summary>
        /// <param name="region"></param>
        /// <param name="color"></param>
        public void ClearRegion(Rectangle region, int color)
        {
            var thisReg = new Rectangle(0, 0, Width, Height);

            if (!region.IntersectsWith(thisReg))
            {
                return;
            }

            // If the region covers the entire image, use faster Clear().
            if (region == thisReg)
            {
                Clear(color);
                return;
            }

            var minX = region.X;
            var maxX = region.X + region.Width;

            var minY = region.Y;
            var maxY = region.Y + region.Height;

            // Bail out of optimization if there's too few rows to make this worth it
            if (maxY - minY < 16)
            {
                for (int y = minY; y < maxY; y++)
                {
                    for (int x = minX; x < maxX; x++)
                    {
                        *(_scan0 + x + y * Stride) = color;
                    }
                }

                return;
            }

            ulong strideWidth = (ulong)region.Width * BytesPerPixel;

            // Uniform color pixel values can be mem-set straight away
            int component = color & 0xFF;

            if (component == ((color >> 8) & 0xFF) && component == ((color >> 16) & 0xFF) &&
                component == ((color >> 24) & 0xFF))
            {
                for (int y = minY; y < maxY; y++)
                {
                    NativeMethod.Memset(_scan0 + minX + y * Stride, component, strideWidth);
                }
            }
            else
            {
                // Prepare a horizontal slice of pixels that will be copied over each horizontal row down.
                int[] row = new int[region.Width];

                fixed(int *pRow = row)
                {
                    int count = region.Width;
                    int rem   = count % 8;

                    count /= 8;
                    int *pSrc = pRow;

                    while (count-- > 0)
                    {
                        *pSrc++ = color;
                        *pSrc++ = color;
                        *pSrc++ = color;
                        *pSrc++ = color;

                        *pSrc++ = color;
                        *pSrc++ = color;
                        *pSrc++ = color;
                        *pSrc++ = color;
                    }

                    while (rem-- > 0)
                    {
                        *pSrc++ = color;
                    }

                    int *sx = _scan0 + minX;

                    for (int y = minY; y < maxY; y++)
                    {
                        NativeMethod.Memcpy(sx + y * Stride, pRow, strideWidth);
                    }
                }
            }
        }