private void AdditiveMultiplicativeFilter(Bitmap source, Bitmap destination, double[] matrix) { var initData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat); var destData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, source.PixelFormat); int byteLength = 4; if (source.PixelFormat.ToString().Contains("24")) { byteLength = 3; } var pixelCount = 3; unsafe { byte *sourcePtr = (byte *)initData.Scan0.ToPointer(); byte *destPtr = (byte *)destData.Scan0.ToPointer(); int pixelOffset = pixelCount / 2; int byteOffset = pixelOffset * byteLength; for (int i = byteOffset; i < (initData.Stride - byteOffset); i += byteLength) { for (int j = pixelOffset; j < source.Height - pixelOffset; j++) { byte[][] window = PixelOperations.GetWindowOfPixels(sourcePtr, initData.Stride, i, j, byteLength, pixelCount); byte[] pixel = GetAdditiveMultiplicatedPixel(Transform2Dto1DArray(window, byteLength * pixelCount * pixelCount), byteLength, matrix); PixelOperations.SetPixelUnsafe(destPtr, pixel, initData.Stride, i, j, byteLength); } } } source.UnlockBits(initData); destination.UnlockBits(destData); }
public Bitmap TransformImage(Image source, Image destination) { unsafe { var bitMap = new Bitmap(source); BitmapData bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bitMap.PixelFormat) / 8; int heightInPixels = bitmapData.Height; int widthInBytes = bitmapData.Width * bytesPerPixel; byte * PtrFirstPixel = (byte *)bitmapData.Scan0; Parallel.For(0, heightInPixels, y => { byte *currentLine = PtrFirstPixel + (y * bitmapData.Stride); for (int x = 0; x < widthInBytes; x = x + bytesPerPixel) { var newPixel = PixelOperations.Sepia(Color.FromArgb(currentLine[x], currentLine[x + 1], currentLine[x + 2])); currentLine[x + 2] = newPixel.R; currentLine[x + 1] = newPixel.G; currentLine[x] = newPixel.B; } }); bitMap.UnlockBits(bitmapData); return(bitMap); } }
internal static void FromVector4 <TPixel>( Configuration configuration, PixelOperations <TPixel> pixelOperations, ReadOnlySpan <Vector4> sourceVectors, Span <TPixel> destPixels, bool scaled) where TPixel : struct, IPixel <TPixel> { Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); int count = sourceVectors.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { FromVector4Fallback(sourceVectors, destPixels, scaled); return; } // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, // so let's allocate a temporary buffer as usually: using (IMemoryOwner <Rgba32> tempBuffer = configuration.MemoryAllocator.Allocate <Rgba32>(count)) { Span <Rgba32> tempSpan = tempBuffer.Memory.Span; SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows( MemoryMarshal.Cast <Vector4, float>(sourceVectors), MemoryMarshal.Cast <Rgba32, byte>(tempSpan)); pixelOperations.FromRgba32(configuration, tempSpan, destPixels); } }
/// <summary> /// This method pre-seeds the PixelOperations engine for the AoT compiler on iOS. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> private static void AotCompilePixelOperations <TPixel>() where TPixel : struct, IPixel <TPixel> { var pixelOp = new PixelOperations <TPixel>(); pixelOp.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.Clear); }
private void MonohromeFilter(Bitmap source, Bitmap destination, Color firstColor, Color secondColor, int coefficient) { var initData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat); var destData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, source.PixelFormat); int byteLength = 4; if (source.PixelFormat.ToString().Contains("24")) { byteLength = 3; } unsafe { byte *sourcePtr = (byte *)initData.Scan0.ToPointer(); byte *destPtr = (byte *)destData.Scan0.ToPointer(); for (int i = 0; i < initData.Stride; i += byteLength) { for (int j = 0; j < source.Height; j++) { var pixel = PixelOperations.GetPixelUnsafe(sourcePtr, initData.Stride, i, j, byteLength); pixel = GetMonohromePixel(pixel, byteLength, coefficient); PixelOperations.SetPixelUnsafe(destPtr, pixel, initData.Stride, i, j, byteLength); } } } source.UnlockBits(initData); destination.UnlockBits(destData); }
private byte[] GetAdditiveMultiplicatedPixel(byte[] values, int byteLength, double[] matrix) { var RGBColors = PixelOperations.TransformPixelArrayToColorArray(values, byteLength); double red = 0; double green = 0; double blue = 0; double sum = 0; for (int i = 0; i < 9; i++) { red += RGBColors[i].R * matrix[i]; green += RGBColors[i].G * matrix[i]; blue += RGBColors[i].B * matrix[i]; sum += matrix[i]; } if (sum <= 0) { sum = 1; } red /= sum; if (red < 0) { red = 0; } if (red > 255) { red = 255; } green /= sum; if (green < 0) { green = 0; } if (green > 255) { green = 255; } blue /= sum; if (blue < 0) { blue = 0; } if (blue > 255) { blue = 255; } Color color = Color.FromArgb(RGBColors[4].A, (int)red, (int)green, (int)blue); byte[] pixel = PixelOperations.TransformColorToPixel(color, byteLength); return(pixel); }
private byte[] GetMedian(byte[] values, int byteLength, int pixelCount) { List <Color> RGBColors = PixelOperations.TransformPixelArrayToColorArray(values, byteLength).ToList(); RGBColors.Sort((x, y) => x.GetBrightness().CompareTo(y.GetBrightness())); Color color = RGBColors[pixelCount * pixelCount / 2]; byte[] pixel = PixelOperations.TransformColorToPixel(color, byteLength); return(pixel); }
/// <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); }
private Bitmap RotateImage(Bitmap source, double angle) { double radAngle = angle * Math.PI / 180; var cos = Math.Cos(radAngle); var sin = Math.Sin(radAngle); var widthAndHeight = CalculateNewBoundaries(bitmap.Width, bitmap.Height, radAngle); int newWidth = widthAndHeight.width; int newHeight = widthAndHeight.height; Bitmap destination = new Bitmap((int)newWidth, (int)newHeight); var SrcData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat); var DestData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, source.PixelFormat); int bytelength = 4; if (source.PixelFormat.ToString().Contains("24")) { bytelength = 3; } int x0 = (int)(newWidth / 2.0); int y0 = (int)(newHeight / 2.0); unsafe { byte *SrcPtr = (byte *)SrcData.Scan0.ToPointer(); byte *DestPtr = (byte *)DestData.Scan0.ToPointer(); var offset = GetOffsets(source.Width, source.Height, cos, sin, x0, y0, angle); for (double x = 0; x < source.Width; x += 1) { for (int y = 0; y < source.Height; y++) { var X = CalculateNewX((int)x, y, cos, sin, x0, y0); var Y = CalculateNewY((int)x, y, cos, sin, x0, y0); X += offset.xOffset; Y += offset.yOffset; if (Y >= 0 && Y < newHeight && X >= 0 && X < newWidth) { var pixel = PixelOperations.GetPixelUnsafe(SrcPtr, SrcData.Stride, (int)Math.Round(x * 4), y, bytelength); PixelOperations.SetPixelUnsafe(DestPtr, pixel, DestData.Stride, X * 4, Y, bytelength); PixelOperations.SetPixelUnsafe(DestPtr, pixel, DestData.Stride, (X + 1) * 4, Y, bytelength); } } } } source.UnlockBits(SrcData); destination.UnlockBits(DestData); return(destination); }
private void zielonyToolStripMenuItem_Click(object sender, EventArgs e) { savedBitmap.Push(new Bitmap(picture)); if (savedBitmap.Count() >= 0) { button1.Enabled = true; } PixelOperations pixelmod = new PixelOperations(); Picture = pixelmod.grayscale3(new Bitmap(picture)); }
public Image ProcessImage(ImageFactory factory) { Bitmap newImage = null; Image image = factory.Image; int parameter = DynamicParameter; if (parameter > 100 || parameter < 0) { throw new ArgumentOutOfRangeException(); } var bitMap = new Bitmap(image); try { using (Graphics graphics = Graphics.FromImage(image)) { using (ImageAttributes attributes = new ImageAttributes()) { unsafe { BitmapData bitmapData = bitMap.LockBits(new Rectangle(0, 0, bitMap.Width, bitMap.Height), ImageLockMode.ReadWrite, bitMap.PixelFormat); int bytesPerPixel = System.Drawing.Bitmap.GetPixelFormatSize(bitMap.PixelFormat) / 8; int heightInPixels = bitmapData.Height; int widthInBytes = bitmapData.Width * bytesPerPixel; byte *PtrFirstPixel = (byte *)bitmapData.Scan0; Parallel.For(0, heightInPixels, y => { byte *currentLine = PtrFirstPixel + (y * bitmapData.Stride); for (int x = 0; x < widthInBytes; x = x + bytesPerPixel) { var newPixel = PixelOperations.Threshold(Color.FromArgb(currentLine[x], currentLine[x + 1], currentLine[x + 2]), parameter); currentLine[x] = newPixel.R; currentLine[x + 1] = newPixel.G; currentLine[x + 2] = newPixel.B; } }); bitMap.UnlockBits(bitmapData); image = bitMap; } } } } catch (Exception ex) { newImage?.Dispose(); throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex); } return(image); }
private Color SetNewColor(Color color, Color drawingColor) { var b = drawingColor.B; var g = drawingColor.G; var r = drawingColor.R; Color newColor = Color.FromArgb(r, g, b); var newColorHSV = PixelOperations.ColorToHSV(newColor); newColorHSV.value = color.GetBrightness(); newColor = PixelOperations.ColorFromHSV(newColorHSV.hue, newColorHSV.saturation, newColorHSV.value); return(newColor); }
private byte[] GetMonohromePixel(byte[] pixel, int byteLength, int coefficient) { Color color = PixelOperations.TransformPixelToColor(pixel, byteLength); Color newColor; if ((color.B + color.G + color.R) / 3 < coefficient) { newColor = SetNewColor(color, secondColor); } else { newColor = SetNewColor(color, firstColor); } pixel = PixelOperations.TransformColorToPixel(newColor, byteLength); return(pixel); }
private void ZoomPicture(Bitmap source, Bitmap destination, double xZoom, double yZoom) { var initData = source.LockBits(new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, source.PixelFormat); var destData = destination.LockBits(new Rectangle(0, 0, destination.Width, destination.Height), ImageLockMode.WriteOnly, source.PixelFormat); int byteLength = 4; if (source.PixelFormat.ToString().Contains("24")) { byteLength = 3; } else if (source.PixelFormat.ToString().Contains("16")) { byteLength = 2; } // Get the address of the first line IntPtr ptr1 = initData.Scan0; IntPtr ptr2 = destData.Scan0; unsafe { byte *sourcePtr = (byte *)ptr1.ToPointer(); byte *destPtr = (byte *)ptr2.ToPointer(); for (int i = 0; i < destData.Stride; i += 4) { for (int j = 0; j < destination.Height; j++) { int newX = (int)(i / xZoom); int newY = (int)(j / yZoom); if (newX % byteLength != 0) { newX -= newX % byteLength; //offset to the first byte of four } var pixel = PixelOperations.GetPixelUnsafe(sourcePtr, initData.Stride, newX, newY, byteLength); PixelOperations.SetPixelUnsafe(destPtr, pixel, destData.Stride, i, j, byteLength); } } } source.UnlockBits(initData); destination.UnlockBits(destData); }
internal static void ToVector4 <TPixel>( Configuration configuration, PixelOperations <TPixel> pixelOperations, ReadOnlySpan <TPixel> sourcePixels, Span <Vector4> destVectors, PixelConversionModifiers modifiers) where TPixel : struct, IPixel <TPixel> { Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); int count = sourcePixels.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { Default.UnsafeToVector4(sourcePixels, destVectors, modifiers); return; } // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: int countWithoutLastItem = count - 1; ReadOnlySpan <TPixel> reducedSource = sourcePixels.Slice(0, countWithoutLastItem); Span <Rgba32> lastQuarterOfDestBuffer = MemoryMarshal.Cast <Vector4, Rgba32>(destVectors).Slice((3 * count) + 1, countWithoutLastItem); pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, // but we are always reading/writing at different positions: SimdUtils.BulkConvertByteToNormalizedFloat( MemoryMarshal.Cast <Rgba32, byte>(lastQuarterOfDestBuffer), MemoryMarshal.Cast <Vector4, float>(destVectors.Slice(0, countWithoutLastItem))); destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); // TODO: Investigate optimized 1-pass approach! ApplyForwardConversionModifiers(destVectors, modifiers); }
internal static void FromVector4 <TPixel>( Configuration configuration, PixelOperations <TPixel> pixelOperations, Span <Vector4> sourceVectors, Span <TPixel> destPixels, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel <TPixel> { Guard.NotNull(configuration, nameof(configuration)); Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); int count = sourceVectors.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { Default.UnsafeFromVector4(sourceVectors, destPixels, modifiers); return; } // TODO: Investigate optimized 1-pass approach! ApplyBackwardConversionModifiers(sourceVectors, modifiers); // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, // so let's allocate a temporary buffer as usually: using (IMemoryOwner <Rgba32> tempBuffer = configuration.MemoryAllocator.Allocate <Rgba32>(count)) { Span <Rgba32> tempSpan = tempBuffer.Memory.Span; SimdUtils.NormalizedFloatToByteSaturate( MemoryMarshal.Cast <Vector4, float>(sourceVectors), MemoryMarshal.Cast <Rgba32, byte>(tempSpan)); pixelOperations.FromRgba32(configuration, tempSpan, destPixels); } }
/// <summary> /// Processes the image. /// </summary> /// <param name="factory"> /// The current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class containing /// the image to process. /// </param> /// <returns> /// The processed image from the current instance of the <see cref="T:ImageProcessor.ImageFactory"/> class. /// </returns> public Image ProcessImage(ImageFactory factory) { Bitmap newImage = null; Image image = factory.Image; try { Tuple <Color, Color, int> parameters = this.DynamicParameter; Color original = parameters.Item1; Color replacement = parameters.Item2; // Ensure that color comparison takes any gamma adjustments into consideration. if (factory.FixGamma || Math.Abs(factory.CurrentGamma) > 0) { original = PixelOperations.Gamma(original, factory.CurrentGamma); replacement = PixelOperations.Gamma(replacement, factory.CurrentGamma); } byte originalR = original.R; byte originalG = original.G; byte originalB = original.B; byte originalA = original.A; byte replacementR = replacement.R; byte replacementG = replacement.G; byte replacementB = replacement.B; byte replacementA = replacement.A; int fuzziness = parameters.Item3; byte minR = (originalR - fuzziness).ToByte(); byte minG = (originalG - fuzziness).ToByte(); byte minB = (originalB - fuzziness).ToByte(); byte maxR = (originalR + fuzziness).ToByte(); byte maxG = (originalG + fuzziness).ToByte(); byte maxB = (originalB + fuzziness).ToByte(); newImage = new Bitmap(image); int width = image.Width; int height = image.Height; using (FastBitmap fastBitmap = new FastBitmap(newImage)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // Get the pixel color. // ReSharper disable once AccessToDisposedClosure Color currentColor = fastBitmap.GetPixel(x, y); byte currentR = currentColor.R; byte currentG = currentColor.G; byte currentB = currentColor.B; byte currentA = currentColor.A; // Test whether it is in the expected range. if (ImageMaths.InRange(currentR, minR, maxR)) { if (ImageMaths.InRange(currentG, minG, maxG)) { if (ImageMaths.InRange(currentB, minB, maxB)) { // Ensure the values are within an acceptable byte range // and set the new value. byte r = (originalR - currentR + replacementR).ToByte(); byte g = (originalG - currentG + replacementG).ToByte(); byte b = (originalB - currentB + replacementB).ToByte(); // Allow replacement with transparent color. byte a = currentA; if (originalA != replacementA) { a = replacementA; } // ReSharper disable once AccessToDisposedClosure fastBitmap.SetPixel(x, y, Color.FromArgb(a, r, g, b)); } } } } }); } image.Dispose(); image = newImage; } catch (Exception ex) { if (newImage != null) { newImage.Dispose(); } throw new ImageProcessingException("Error processing image with " + this.GetType().Name, ex); } return(image); }
private void DrawSegment(int x0, int x1, int y0, int y1, Color color1, Color color2) { var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); unsafe { byte *ptr = (byte *)data.Scan0.ToPointer(); int dx = (x1 > x0) ? (x1 - x0) : (x0 - x1); int dy = (y1 > y0) ? (y1 - y0) : (y0 - y1); //Направление приращения int sx = (x1 >= x0) ? (1) : (-1); int sy = (y1 >= y0) ? (1) : (-1); if (dy < dx) { int d = (dy << 1) - dx; int d1 = dy << 1; int d2 = (dy - dx) << 1; Color color = GetInterpolateColor(color1, color2, 0); PixelOperations.SetPixelUnsafe(ptr, new byte[] { color.B, color.G, color.R, 255 }, data.Stride, x0 * 4, y0, 4); int x = x0 + sx; int y = y0; for (int i = 1; i <= dx; i++) { if (d > 0) { d += d2; y += sy; } else { d += d1; } color = GetInterpolateColor(color1, color2, (i * 1.0 / dx)); PixelOperations.SetPixelUnsafe(ptr, new byte[] { color.B, color.G, color.R, 255 }, data.Stride, x * 4, y, 4); x += sx; } } else { int d = (dx << 1) - dy; int d1 = dx << 1; int d2 = (dx - dy) << 1; Color color = GetInterpolateColor(color1, color2, 0); PixelOperations.SetPixelUnsafe(ptr, new byte[] { color.B, color.G, color.R, 255 }, data.Stride, x0 * 4, y0, 4); int x = x0; int y = y0 + sy; for (int i = 1; i <= dy; i++) { if (d > 0) { d += d2; x += sx; } else { d += d1; } color = GetInterpolateColor(color1, color2, (i * 1.0 / dy)); PixelOperations.SetPixelUnsafe(ptr, new byte[] { color.B, color.G, color.R, 255 }, data.Stride, x * 4, y, 4); y += sy; } } } bitmap.UnlockBits(data); pictureBox1.Image = bitmap; }
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); }
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); }
/// <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); }
/// <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); }
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); }