Beispiel #1
0
        /// <summary>
        /// Performs a vertical fast box blur on the collection of colors.
        /// <see href="http://blog.ivank.net/fastest-gaussian-blur.html"/>
        /// </summary>
        /// <param name="sourceColors">The source colors.</param>
        /// <param name="radius">The radius to which to blur.</param>
        /// <param name="fixGamma">Whether to blur the colors using the linear color space.</param>
        /// <returns>
        /// The <see cref="T:Color[,]"/>.
        /// </returns>
        private static Color[,] BoxBlurVertical(Color[,] sourceColors, int radius, bool fixGamma)
        {
            int width  = sourceColors.GetLength(0);
            int height = sourceColors.GetLength(1);

            Color[,] destination = new Color[width, height];

            // For each column
            for (int y = 0; y < height; y++)
            {
                // For each row
                for (int x = 0; x < width; x++)
                {
                    int fy    = Math.Max(0, y - radius);
                    int ty    = Math.Min(width, y + radius + 1);
                    int red   = 0;
                    int green = 0;
                    int blue  = 0;
                    int alpha = 0;

                    for (int yy = fy; yy < ty; yy++)
                    {
                        Color sourceColor = sourceColors[x, yy];

                        if (fixGamma)
                        {
                            sourceColor = PixelOperations.ToLinear(sourceColor);
                        }

                        red   += sourceColor.R;
                        green += sourceColor.G;
                        blue  += sourceColor.B;
                        alpha += sourceColor.A;
                    }

                    int divider = ty - fy;

                    red   /= divider;
                    green /= divider;
                    blue  /= divider;
                    alpha /= divider;

                    Color destinationColor = Color.FromArgb(alpha, red, green, blue);

                    if (fixGamma)
                    {
                        destinationColor = PixelOperations.ToSRGB(destinationColor);
                    }

                    destination[x, y] = destinationColor;
                }
            }

            return(destination);
        }
Beispiel #2
0
        /// <summary>
        /// Processes the given kernel to produce an array of pixels representing a bitmap.
        /// </summary>
        /// <param name="source">The image to process.</param>
        /// <param name="kernel">The Gaussian kernel to use when performing the method</param>
        /// <param name="fixGamma">Whether to process the image using the linear color space.</param>
        /// <returns>A processed bitmap.</returns>
        public Color[,] ProcessKernel(Color[,] source, double[,] kernel, bool fixGamma)
        {
            var width  = source.GetLength(0);
            var height = source.GetLength(1);

            var kernelLength = kernel.GetLength(0);
            var radius       = kernelLength >> 1;
            var kernelSize   = kernelLength * kernelLength;
            var threshold    = Threshold;

            var destination = new Color[width, height];

            // For each line
            Parallel.For(
                0,
                height,
                y =>
            {
                // For each pixel
                for (var x = 0; x < width; x++)
                {
                    // The number of kernel elements taken into account
                    int processedKernelSize;

                    // Colour sums
                    double blue;
                    double alpha;
                    double divider;
                    double green;
                    var red = green = blue = alpha = divider = processedKernelSize = 0;

                    // For each kernel row
                    for (var i = 0; i < kernelLength; i++)
                    {
                        var ir      = i - radius;
                        var offsetY = y + ir;

                        // Skip the current row
                        if (offsetY < 0)
                        {
                            continue;
                        }

                        // Outwith the current bounds so break.
                        if (offsetY >= height)
                        {
                            break;
                        }

                        // For each kernel column
                        for (var j = 0; j < kernelLength; j++)
                        {
                            var jr      = j - radius;
                            var offsetX = x + jr;

                            // Skip the column
                            if (offsetX < 0)
                            {
                                continue;
                            }

                            if (offsetX < width)
                            {
                                // ReSharper disable once AccessToDisposedClosure
                                var sourceColor = source[offsetX, offsetY];

                                if (fixGamma)
                                {
                                    sourceColor = PixelOperations.ToLinear(sourceColor);
                                }

                                var k    = kernel[i, j];
                                divider += k;

                                red   += k * sourceColor.R;
                                green += k * sourceColor.G;
                                blue  += k * sourceColor.B;
                                alpha += k * sourceColor.A;

                                processedKernelSize++;
                            }
                        }
                    }

                    // Check to see if all kernel elements were processed
                    if (processedKernelSize == kernelSize)
                    {
                        // All kernel elements are processed; we are not on the edge.
                        divider = Divider;
                    }
                    else
                    {
                        // We are on an edge; do we need to use dynamic divider or not?
                        if (!UseDynamicDividerForEdges)
                        {
                            // Apply the set divider.
                            divider = Divider;
                        }
                    }

                    // Check and apply the divider
                    if ((long)divider != 0)
                    {
                        red   /= divider;
                        green /= divider;
                        blue  /= divider;
                        alpha /= divider;
                    }

                    // Add any applicable threshold.
                    red   += threshold;
                    green += threshold;
                    blue  += threshold;
                    alpha += threshold;

                    var destinationColor = Color.FromArgb(alpha.ToByte(), red.ToByte(), green.ToByte(), blue.ToByte());

                    if (fixGamma)
                    {
                        destinationColor = PixelOperations.ToSRGB(destinationColor);
                    }

                    destination[x, y] = destinationColor;
                }
            });

            return(destination);
        }
Beispiel #3
0
        /// <summary>
        /// Processes the given kernel to produce an array of pixels representing a bitmap.
        /// </summary>
        /// <param name="source">The image to process.</param>
        /// <param name="kernel">The Gaussian kernel to use when performing the method</param>
        /// <param name="fixGamma">Whether to process the image using the linear color space.</param>
        /// <returns>A processed bitmap.</returns>
        public Bitmap ProcessKernel(Bitmap source, double[,] kernel, bool fixGamma)
        {
            int    width       = source.Width;
            int    height      = source.Height;
            Bitmap destination = new Bitmap(width, height, PixelFormat.Format32bppPArgb);

            destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);

            using (FastBitmap sourceBitmap = new FastBitmap(source))
            {
                using (FastBitmap destinationBitmap = new FastBitmap(destination))
                {
                    int kernelLength = kernel.GetLength(0);
                    int radius       = kernelLength >> 1;
                    int kernelSize   = kernelLength * kernelLength;
                    int threshold    = this.Threshold;

                    // For each line
                    Parallel.For(
                        0,
                        height,
                        y =>
                    {
                        // For each pixel
                        for (int x = 0; x < width; x++)
                        {
                            // The number of kernel elements taken into account
                            int processedKernelSize;

                            // Colour sums
                            double blue;
                            double alpha;
                            double divider;
                            double green;
                            double red = green = blue = alpha = divider = processedKernelSize = 0;

                            // For each kernel row
                            for (int i = 0; i < kernelLength; i++)
                            {
                                int ir      = i - radius;
                                int offsetY = y + ir;

                                // Skip the current row
                                if (offsetY < 0)
                                {
                                    continue;
                                }

                                // Outwith the current bounds so break.
                                if (offsetY >= height)
                                {
                                    break;
                                }

                                // For each kernel column
                                for (int j = 0; j < kernelLength; j++)
                                {
                                    int jr      = j - radius;
                                    int offsetX = x + jr;

                                    // Skip the column
                                    if (offsetX < 0)
                                    {
                                        continue;
                                    }

                                    if (offsetX < width)
                                    {
                                        // ReSharper disable once AccessToDisposedClosure
                                        Color sourceColor = sourceBitmap.GetPixel(offsetX, offsetY);

                                        if (fixGamma)
                                        {
                                            sourceColor = PixelOperations.ToLinear(sourceColor);
                                        }

                                        double k = kernel[i, j];
                                        divider += k;

                                        red   += k * sourceColor.R;
                                        green += k * sourceColor.G;
                                        blue  += k * sourceColor.B;
                                        alpha += k * sourceColor.A;

                                        processedKernelSize++;
                                    }
                                }
                            }

                            // Check to see if all kernel elements were processed
                            if (processedKernelSize == kernelSize)
                            {
                                // All kernel elements are processed; we are not on the edge.
                                divider = this.Divider;
                            }
                            else
                            {
                                // We are on an edge; do we need to use dynamic divider or not?
                                if (!this.UseDynamicDividerForEdges)
                                {
                                    // Apply the set divider.
                                    divider = this.Divider;
                                }
                            }

                            // Check and apply the divider
                            if ((long)divider != 0)
                            {
                                red   /= divider;
                                green /= divider;
                                blue  /= divider;
                                alpha /= divider;
                            }

                            // Add any applicable threshold.
                            red   += threshold;
                            green += threshold;
                            blue  += threshold;
                            alpha += threshold;

                            Color destinationColor = Color.FromArgb(alpha.ToByte(), red.ToByte(), green.ToByte(), blue.ToByte());

                            if (fixGamma)
                            {
                                destinationColor = PixelOperations.ToSRGB(destinationColor);
                            }

                            // ReSharper disable once AccessToDisposedClosure
                            destinationBitmap.SetPixel(x, y, destinationColor);
                        }
                    });
                }
            }

            source.Dispose();
            return(destination);
        }
Beispiel #4
0
        internal static Bitmap ResizeLanczos(Bitmap source, int width, int height, Rectangle destinationRectangle, bool fixGamma = true)
        {
            int sourceWidth  = source.Width;
            int sourceHeight = source.Height;
            int startX       = destinationRectangle.X;
            int startY       = destinationRectangle.Y;
            int endX         = destinationRectangle.Width + startX;
            int endY         = destinationRectangle.Height + startY;

            Bitmap destination = new Bitmap(width, height, PixelFormat.Format32bppPArgb);

            destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);

            using (FastBitmap sourceBitmap = new FastBitmap(source))
            {
                using (FastBitmap destinationBitmap = new FastBitmap(destination))
                {
                    // Scaling factors
                    double widthFactor  = sourceWidth / (double)destinationRectangle.Width;
                    double heightFactor = sourceHeight / (double)destinationRectangle.Height;

                    // Width and height decreased by 1
                    int maxHeight = sourceHeight - 1;
                    int maxWidth  = sourceWidth - 1;

                    // For each column
                    Parallel.For(
                        startY,
                        endY,
                        y =>
                    {
                        if (y >= 0 && y < height)
                        {
                            // Y coordinates of source points.
                            double originY = ((y - startY) * heightFactor) - 0.5;
                            int originY1   = (int)originY;
                            double dy      = originY - originY1;

                            // For each row.
                            for (int x = startX; x < endX; x++)
                            {
                                if (x >= 0 && x < width)
                                {
                                    // X coordinates of source points.
                                    double originX = ((x - startX) * widthFactor) - 0.5f;
                                    int originX1   = (int)originX;
                                    double dx      = originX - originX1;

                                    // Destination color components
                                    double r = 0;
                                    double g = 0;
                                    double b = 0;
                                    double a = 0;

                                    for (int n = -3; n < 6; n++)
                                    {
                                        // Get Y cooefficient
                                        double k1 = Interpolation.LanczosKernel3(dy - n);

                                        int originY2 = originY1 + n;
                                        if (originY2 < 0)
                                        {
                                            originY2 = 0;
                                        }

                                        if (originY2 > maxHeight)
                                        {
                                            originY2 = maxHeight;
                                        }

                                        for (int m = -3; m < 6; m++)
                                        {
                                            // Get X cooefficient
                                            double k2 = k1 * Interpolation.LanczosKernel3(m - dx);

                                            int originX2 = originX1 + m;
                                            if (originX2 < 0)
                                            {
                                                originX2 = 0;
                                            }

                                            if (originX2 > maxWidth)
                                            {
                                                originX2 = maxWidth;
                                            }

                                            // ReSharper disable once AccessToDisposedClosure
                                            Color sourceColor = sourceBitmap.GetPixel(originX2, originY2);

                                            if (fixGamma)
                                            {
                                                sourceColor = PixelOperations.ToLinear(sourceColor);
                                            }

                                            r += k2 * sourceColor.R;
                                            g += k2 * sourceColor.G;
                                            b += k2 * sourceColor.B;
                                            a += k2 * sourceColor.A;
                                        }
                                    }

                                    Color destinationColor = Color.FromArgb(
                                        a.ToByte(),
                                        r.ToByte(),
                                        g.ToByte(),
                                        b.ToByte());

                                    if (fixGamma)
                                    {
                                        destinationColor = PixelOperations.ToSRGB(destinationColor);
                                    }

                                    // ReSharper disable once AccessToDisposedClosure
                                    destinationBitmap.SetPixel(x, y, destinationColor);
                                }
                            }
                        }
                    });
                }
            }

            source.Dispose();
            return(destination);
        }
Beispiel #5
0
        public static Bitmap ResizeBilinear(Bitmap source, int width, int height, Rectangle destinationRectangle, bool fixGamma)
        {
            int sourceWidth  = source.Width;
            int sourceHeight = source.Height;
            int startX       = destinationRectangle.X;
            int startY       = destinationRectangle.Y;
            int endX         = destinationRectangle.Width + startX;
            int endY         = destinationRectangle.Height + startY;

            // Scaling factors
            double widthFactor  = sourceWidth / (double)destinationRectangle.Width;
            double heightFactor = sourceHeight / (double)destinationRectangle.Height;

            // Width and height decreased by 1
            int maxHeight = sourceHeight - 1;
            int maxWidth  = sourceWidth - 1;

            Bitmap destination = new Bitmap(width, height, PixelFormat.Format32bppPArgb);

            destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);

            using (FastBitmap sourceBitmap = new FastBitmap(source))
            {
                using (FastBitmap destinationBitmap = new FastBitmap(destination))
                {
                    // For each column
                    Parallel.For(
                        startY,
                        endY,
                        y =>
                    {
                        if (y >= 0 && y < height)
                        {
                            // Y coordinates of source points
                            double originY = (y - startY) * heightFactor;
                            int originY1   = (int)originY;
                            int originY2   = (originY1 == maxHeight) ? originY1 : originY1 + 1;
                            double dy1     = originY - originY1;
                            double dy2     = 1.0 - dy1;

                            // Get temp pointers
                            int temp1 = originY1;
                            int temp2 = originY2;

                            // For every column.
                            for (int x = startX; x < endX; x++)
                            {
                                if (x >= 0 && x < width)
                                {
                                    // X coordinates of source points
                                    double originX = (x - startX) * widthFactor;
                                    int originX1   = (int)originX;
                                    int originX2   = (originX1 == maxWidth) ? originX1 : originX1 + 1;
                                    double dx1     = originX - originX1;
                                    double dx2     = 1.0 - dx1;

                                    // Get four pixels to sample from.
                                    Color sourceColor1 = sourceBitmap.GetPixel(originX1, temp1);
                                    Color sourceColor2 = sourceBitmap.GetPixel(originX2, temp1);
                                    Color sourceColor3 = sourceBitmap.GetPixel(originX1, temp2);
                                    Color sourceColor4 = sourceBitmap.GetPixel(originX2, temp2);

                                    if (fixGamma)
                                    {
                                        sourceColor1 = PixelOperations.ToLinear(sourceColor1);
                                        sourceColor2 = PixelOperations.ToLinear(sourceColor2);
                                        sourceColor3 = PixelOperations.ToLinear(sourceColor3);
                                        sourceColor4 = PixelOperations.ToLinear(sourceColor4);
                                    }

                                    // Get four points in red channel.
                                    int p1 = sourceColor1.R;
                                    int p2 = sourceColor2.R;
                                    int p3 = sourceColor3.R;
                                    int p4 = sourceColor4.R;

                                    int r = (int)((dy2 * ((dx2 * p1) + (dx1 * p2))) + (dy1 * ((dx2 * p3) + (dx1 * p4))));

                                    // Get four points in green channel.
                                    p1 = sourceColor1.G;
                                    p2 = sourceColor2.G;
                                    p3 = sourceColor3.G;
                                    p4 = sourceColor4.G;

                                    int g = (int)((dy2 * ((dx2 * p1) + (dx1 * p2))) + (dy1 * ((dx2 * p3) + (dx1 * p4))));

                                    // Get four points in blue channel
                                    p1 = sourceColor1.B;
                                    p2 = sourceColor2.B;
                                    p3 = sourceColor3.B;
                                    p4 = sourceColor4.B;

                                    int b = (int)((dy2 * ((dx2 * p1) + (dx1 * p2))) + (dy1 * ((dx2 * p3) + (dx1 * p4))));

                                    // Get four points in alpha channel
                                    p1 = sourceColor1.A;
                                    p2 = sourceColor2.A;
                                    p3 = sourceColor3.A;
                                    p4 = sourceColor4.A;

                                    int a = (int)((dy2 * ((dx2 * p1) + (dx1 * p2))) + (dy1 * ((dx2 * p3) + (dx1 * p4))));

                                    Color destinationColor = Color.FromArgb(
                                        a.ToByte(),
                                        r.ToByte(),
                                        g.ToByte(),
                                        b.ToByte());

                                    if (fixGamma)
                                    {
                                        destinationColor = PixelOperations.ToSRGB(destinationColor);
                                    }

                                    destinationBitmap.SetPixel(x, y, destinationColor);
                                }
                            }
                        }
                    });
                }
            }

            source.Dispose();
            return(destination);
        }
Beispiel #6
0
        public static Bitmap ResizeBicubicHighQuality(Bitmap source, int width, int height, Rectangle destinationRectangle, bool fixGamma)
        {
            int sourceWidth  = source.Width;
            int sourceHeight = source.Height;
            int startX       = destinationRectangle.X;
            int startY       = destinationRectangle.Y;
            int endX         = destinationRectangle.Width + startX;
            int endY         = destinationRectangle.Height + startY;

            // Scaling factors
            double widthFactor  = sourceWidth / (double)destinationRectangle.Width;
            double heightFactor = sourceHeight / (double)destinationRectangle.Height;

            // Width and height decreased by 1
            int maxHeight = sourceHeight - 1;
            int maxWidth  = sourceWidth - 1;

            Bitmap destination = new Bitmap(width, height, PixelFormat.Format32bppPArgb);

            destination.SetResolution(source.HorizontalResolution, source.VerticalResolution);

            // The radius for pre blurring the images.
            // We only apply this for very small images.
            int radius = 0;

            if (width <= 150 && height <= 150)
            {
                radius = 4;
            }

            using (FastBitmap sourceBitmap = new FastBitmap(source))
            {
                using (FastBitmap destinationBitmap = new FastBitmap(destination))
                {
                    // For each column
                    Parallel.For(
                        startY,
                        endY,
                        y =>
                    {
                        if (y >= 0 && y < height)
                        {
                            // Y coordinates of source points.
                            double originY = ((y - startY) * heightFactor) - 0.5;
                            int originY1   = (int)originY;
                            double dy      = originY - originY1;

                            // Houses colors for blurring.
                            Color[,] sourceColors = new Color[4, 4];

                            // For each row.
                            for (int x = startX; x < endX; x++)
                            {
                                if (x >= 0 && x < width)
                                {
                                    // X coordinates of source points.
                                    double originX = ((x - startX) * widthFactor) - 0.5f;
                                    int originX1   = (int)originX;
                                    double dx      = originX - originX1;

                                    // Destination color components
                                    double r = 0;
                                    double g = 0;
                                    double b = 0;
                                    double a = 0;

                                    for (int yy = -1; yy < 3; yy++)
                                    {
                                        int originY2 = originY1 + yy;
                                        if (originY2 < 0)
                                        {
                                            originY2 = 0;
                                        }

                                        if (originY2 > maxHeight)
                                        {
                                            originY2 = maxHeight;
                                        }

                                        for (int xx = -1; xx < 3; xx++)
                                        {
                                            int originX2 = originX1 + xx;
                                            if (originX2 < 0)
                                            {
                                                originX2 = 0;
                                            }

                                            if (originX2 > maxWidth)
                                            {
                                                originX2 = maxWidth;
                                            }

                                            Color sourceColor = sourceBitmap.GetPixel(originX2, originY2);

                                            sourceColors[xx + 1, yy + 1] = sourceColor;
                                        }
                                    }

                                    // Blur the colors.
                                    if (radius > 0)
                                    {
                                        sourceColors = BoxBlur(sourceColors, radius, fixGamma);
                                    }

                                    // Do the resize.
                                    for (int yy = -1; yy < 3; yy++)
                                    {
                                        // Get Y cooefficient
                                        double kernel1 = Interpolation.BiCubicBSplineKernel(dy - yy);

                                        for (int xx = -1; xx < 3; xx++)
                                        {
                                            // Get X cooefficient
                                            double kernel2 = kernel1 * Interpolation.BiCubicBSplineKernel(xx - dx);

                                            Color sourceColor = sourceColors[xx + 1, yy + 1];

                                            if (fixGamma)
                                            {
                                                sourceColor = PixelOperations.ToLinear(sourceColor);
                                            }

                                            r += kernel2 * sourceColor.R;
                                            g += kernel2 * sourceColor.G;
                                            b += kernel2 * sourceColor.B;
                                            a += kernel2 * sourceColor.A;
                                        }
                                    }

                                    Color destinationColor = Color.FromArgb(
                                        a.ToByte(),
                                        r.ToByte(),
                                        g.ToByte(),
                                        b.ToByte());

                                    if (fixGamma)
                                    {
                                        destinationColor = PixelOperations.ToSRGB(destinationColor);
                                    }

                                    destinationBitmap.SetPixel(x, y, destinationColor);
                                }
                            }
                        }
                    });
                }
            }

            source.Dispose();
            return(destination);
        }