/// <summary> /// Adjusts the alpha component of the given image. /// </summary> /// <param name="source"> /// The <see cref="Image"/> source to adjust. /// </param> /// <param name="percentage"> /// The percentage value between 0 and 100 for adjusting the opacity. /// </param> /// <param name="rectangle">The rectangle to define the bounds of the area to adjust the opacity. /// If null then the effect is applied to the entire image.</param> /// <returns> /// The <see cref="Bitmap"/> with the alpha component adjusted. /// </returns> /// <exception cref="ArgumentOutOfRangeException"> /// Thrown if the percentage value falls outside the acceptable range. /// </exception> public static Bitmap Alpha(Image source, int percentage, Rectangle? rectangle = null) { if (percentage > 100 || percentage < 0) { throw new ArgumentOutOfRangeException(nameof(percentage), "Percentage should be between 0 and 100."); } float factor = (float)percentage / 100; int width = source.Width; int height = source.Height; // Traditional examples using a color matrix alter the rgb values also. using (FastBitmap bitmap = new FastBitmap(source)) { // Loop through the pixels. Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable AccessToDisposedClosure Color color = bitmap.GetPixel(x, y); bitmap.SetPixel(x, y, Color.FromArgb(Convert.ToInt32(color.A * factor), color.R, color.G, color.B)); // ReSharper restore AccessToDisposedClosure } }); } return (Bitmap)source; }
/// <summary> /// Processes the given bitmap to apply the threshold. /// </summary> /// <param name="source"> /// The image to process. /// </param> /// <returns> /// A processed bitmap. /// </returns> public Bitmap ProcessFilter(Bitmap source) { int width = source.Width; int height = source.Height; using (FastBitmap sourceBitmap = new FastBitmap(source)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable AccessToDisposedClosure Color color = sourceBitmap.GetPixel(x, y); sourceBitmap.SetPixel(x, y, color.B >= this.threshold ? Color.White : Color.Black); // ReSharper restore AccessToDisposedClosure } }); } return source; }
/// <summary> /// Applies the given image mask to the source. /// </summary> /// <param name="source"> /// The source <see cref="Image"/>. /// </param> /// <param name="mask"> /// The mask <see cref="Image"/>. /// </param> /// <exception cref="ArgumentException"> /// Thrown if the two images are of different size. /// </exception> /// <returns> /// The masked <see cref="Bitmap"/>. /// </returns> public static Bitmap ApplyMask(Image source, Image mask) { if (mask.Size != source.Size) { throw new ArgumentException(); } int width = mask.Width; int height = mask.Height; Bitmap toMask = new Bitmap(source); toMask.SetResolution(source.HorizontalResolution, source.VerticalResolution); // Loop through and replace the alpha channel using (FastBitmap maskBitmap = new FastBitmap(mask)) { using (FastBitmap sourceBitmap = new FastBitmap(toMask)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable AccessToDisposedClosure Color maskColor = maskBitmap.GetPixel(x, y); Color sourceColor = sourceBitmap.GetPixel(x, y); if (sourceColor.A != 0) { sourceBitmap.SetPixel(x, y, Color.FromArgb(maskColor.A, sourceColor.R, sourceColor.G, sourceColor.B)); } // ReSharper restore AccessToDisposedClosure } }); } } // Ensure the background is cleared out on non alpha supporting formats. Bitmap clear = new Bitmap(width, height, PixelFormat.Format32bppPArgb); clear.SetResolution(source.HorizontalResolution, source.VerticalResolution); using (Graphics graphics = Graphics.FromImage(clear)) { graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.Clear(Color.Transparent); graphics.DrawImageUnscaled(toMask, 0, 0, width, height); } toMask.Dispose(); return clear; }
public Bitmap DrawImage(Color[] colors) { if (Width < 1 || Height < 1) { return null; } var image = new Bitmap(Width, Height); var fastBmp = new FastBitmap(image); fastBmp.LockImage(); for (int y = 0, i = 0; y < Height; y++) { for (var x = 0; x < Width; x++) { fastBmp.SetPixel(x, y, colors[(int)Cells[i++].Type]); } } fastBmp.UnlockImage(); return image; }
public Bitmap DrawImage(Color[] Colors) { if (Width < 1 || Height < 1) { return null; } Bitmap Image = new Bitmap(Width, Height); FastBitmap fastBmp = new FastBitmap(Image); using (Graphics g = Graphics.FromImage(Image)) { fastBmp.LockImage(); for (int y = 0, i = 0; y < Height; y++) { for (int x = 0; x < Width; x++) { fastBmp.SetPixel(x, y, Colors[(int)Cells[i++].Type]); } } fastBmp.UnlockImage(); } return Image; }
/// <summary> /// Processes the given bitmap to apply the current instance of <see cref="IEdgeFilter"/>. /// </summary> /// <param name="source">The image to process.</param> /// <returns>A processed bitmap.</returns> public Bitmap ProcessFilter(Image source) { int width = source.Width; int height = source.Height; int maxWidth = width + 1; int maxHeight = height + 1; int bufferedWidth = width + 2; int bufferedHeight = height + 2; Bitmap destination = new Bitmap(width, height, PixelFormat.Format32bppPArgb); Bitmap input = new Bitmap(bufferedWidth, bufferedHeight, PixelFormat.Format32bppPArgb); destination.SetResolution(source.HorizontalResolution, source.VerticalResolution); input.SetResolution(source.HorizontalResolution, source.VerticalResolution); using (Graphics graphics = Graphics.FromImage(input)) { // Fixes an issue with transparency not converting properly. graphics.Clear(Color.Transparent); Rectangle destinationRectangle = new Rectangle(0, 0, bufferedWidth, bufferedHeight); Rectangle rectangle = new Rectangle(0, 0, width, height); // If it's greyscale apply a colormatrix to the image. using (ImageAttributes attributes = new ImageAttributes()) { if (this.greyscale) { attributes.SetColorMatrix(ColorMatrixes.GreyScale); } // We use a trick here to detect right to the edges of the image. // flip/tile the image with a pixel in excess in each direction to duplicate pixels. // Later on we draw pixels without that excess. using (TextureBrush tb = new TextureBrush(source, rectangle, attributes)) { tb.WrapMode = WrapMode.TileFlipXY; tb.TranslateTransform(1, 1); graphics.FillRectangle(tb, destinationRectangle); } } } try { double[,] horizontalFilter = this.edgeFilter.HorizontalGradientOperator; int kernelLength = horizontalFilter.GetLength(0); int radius = kernelLength >> 1; using (FastBitmap sourceBitmap = new FastBitmap(input)) { using (FastBitmap destinationBitmap = new FastBitmap(destination)) { // Loop through the pixels. Parallel.For( 0, bufferedHeight, y => { for (int x = 0; x < bufferedWidth; x++) { double rX = 0; double gX = 0; double bX = 0; // Apply each matrix multiplier to the color components for each pixel. for (int fy = 0; fy < kernelLength; fy++) { int fyr = fy - radius; int offsetY = y + fyr; // Skip the current row if (offsetY < 0) { continue; } // Outwith the current bounds so break. if (offsetY >= bufferedHeight) { break; } for (int fx = 0; fx < kernelLength; fx++) { int fxr = fx - radius; int offsetX = x + fxr; // Skip the column if (offsetX < 0) { continue; } if (offsetX < bufferedWidth) { // ReSharper disable once AccessToDisposedClosure Color currentColor = sourceBitmap.GetPixel(offsetX, offsetY); double r = currentColor.R; double g = currentColor.G; double b = currentColor.B; rX += horizontalFilter[fy, fx] * r; gX += horizontalFilter[fy, fx] * g; bX += horizontalFilter[fy, fx] * b; } } } // Apply the equation and sanitize. byte red = rX.ToByte(); byte green = gX.ToByte(); byte blue = bX.ToByte(); Color newColor = Color.FromArgb(red, green, blue); if (y > 0 && x > 0 && y < maxHeight && x < maxWidth) { // ReSharper disable once AccessToDisposedClosure destinationBitmap.SetPixel(x - 1, y - 1, newColor); } } }); } } } finally { // We created a new image. Cleanup. input.Dispose(); } return destination; }
public static void GenerateBitmap(byte[] data, FastBitmap bmp, int startY, int dataAddress, List<Color> fourColors, int addY) { int index = 0; bool onlyHalf = false; int y = startY; int x = 0; int colorZeroValue = fourColors[0].ToArgb(); while (y < bmp.Height && dataAddress + index + 2 < data.Length) { int runLength; int color; bool restOfLine; index += DecodeRle(dataAddress + index, data, out color, out runLength, ref onlyHalf, out restOfLine); if (restOfLine) runLength = bmp.Width - x; Color c = fourColors[color]; // set color via the four colors for (int i = 0; i < runLength; i++, x++) { if (x >= bmp.Width - 1) { if (y < bmp.Height && x < bmp.Width && c != fourColors[0]) bmp.SetPixel(x, y, c); if (onlyHalf) { onlyHalf = false; index++; } x = 0; y += addY; break; } if (y < bmp.Height && c.ToArgb() != colorZeroValue) bmp.SetPixel(x, y, c); } } }
/// <summary> /// Applies the halftone filter. /// </summary> /// <param name="source"> /// The <see cref="Bitmap"/> to apply the filter to. /// </param> /// <returns> /// The <see cref="Bitmap"/> with the filter applied. /// </returns> public Bitmap ApplyFilter(Bitmap source) { // TODO: Make this class implement an interface? Bitmap padded = null; Bitmap cyan = null; Bitmap magenta = null; Bitmap yellow = null; Bitmap keyline = null; Bitmap newImage = null; try { int sourceWidth = source.Width; int sourceHeight = source.Height; int width = source.Width + this.distance; int height = source.Height + this.distance; // Draw a slightly larger image, flipping the top/left pixels to prevent // jagged edge of output. padded = new Bitmap(width, height, PixelFormat.Format32bppPArgb); padded.SetResolution(source.HorizontalResolution, source.VerticalResolution); using (Graphics graphicsPadded = Graphics.FromImage(padded)) { graphicsPadded.Clear(Color.White); Rectangle destinationRectangle = new Rectangle(0, 0, sourceWidth + this.distance, source.Height + this.distance); using (TextureBrush tb = new TextureBrush(source)) { tb.WrapMode = WrapMode.TileFlipXY; tb.TranslateTransform(this.distance, this.distance); graphicsPadded.FillRectangle(tb, destinationRectangle); } } // Calculate min and max widths/heights. Rectangle rotatedBounds = this.GetBoundingRectangle(width, height); int minY = -(rotatedBounds.Height + height); int maxY = rotatedBounds.Height + height; int minX = -(rotatedBounds.Width + width); int maxX = rotatedBounds.Width + width; Point center = Point.Empty; // Yellow oversaturates the output. int offset = this.distance; float yellowMultiplier = this.distance * 1.587f; float magentaMultiplier = this.distance * 2.176f; float multiplier = this.distance * 2.2f; float max = this.distance * (float)Math.Sqrt(2); float magentaMax = this.distance * (float)Math.Sqrt(1.4545); // Bump up the keyline max so that black looks black. float keylineMax = max * (float)Math.Sqrt(2); // Color sampled process colours from Wikipedia pages. // Keyline brush is declared separately. Brush cyanBrush = new SolidBrush(Color.FromArgb(0, 183, 235)); Brush magentaBrush = new SolidBrush(Color.FromArgb(255, 0, 144)); Brush yellowBrush = new SolidBrush(Color.FromArgb(255, 239, 0)); // Create our images. cyan = new Bitmap(width, height, PixelFormat.Format32bppPArgb); magenta = new Bitmap(width, height, PixelFormat.Format32bppPArgb); yellow = new Bitmap(width, height, PixelFormat.Format32bppPArgb); keyline = new Bitmap(width, height, PixelFormat.Format32bppPArgb); newImage = new Bitmap(sourceWidth, sourceHeight, PixelFormat.Format32bppPArgb); // Ensure the correct resolution is set. cyan.SetResolution(source.HorizontalResolution, source.VerticalResolution); magenta.SetResolution(source.HorizontalResolution, source.VerticalResolution); yellow.SetResolution(source.HorizontalResolution, source.VerticalResolution); keyline.SetResolution(source.HorizontalResolution, source.VerticalResolution); newImage.SetResolution(source.HorizontalResolution, source.VerticalResolution); // Check bounds against this. Rectangle rectangle = new Rectangle(0, 0, width, height); using (Graphics graphicsCyan = Graphics.FromImage(cyan)) using (Graphics graphicsMagenta = Graphics.FromImage(magenta)) using (Graphics graphicsYellow = Graphics.FromImage(yellow)) using (Graphics graphicsKeyline = Graphics.FromImage(keyline)) { // Set the quality properties. graphicsCyan.PixelOffsetMode = PixelOffsetMode.Half; graphicsMagenta.PixelOffsetMode = PixelOffsetMode.Half; graphicsYellow.PixelOffsetMode = PixelOffsetMode.Half; graphicsKeyline.PixelOffsetMode = PixelOffsetMode.Half; graphicsCyan.SmoothingMode = SmoothingMode.AntiAlias; graphicsMagenta.SmoothingMode = SmoothingMode.AntiAlias; graphicsYellow.SmoothingMode = SmoothingMode.AntiAlias; graphicsKeyline.SmoothingMode = SmoothingMode.AntiAlias; graphicsCyan.CompositingQuality = CompositingQuality.HighQuality; graphicsMagenta.CompositingQuality = CompositingQuality.HighQuality; graphicsYellow.CompositingQuality = CompositingQuality.HighQuality; graphicsKeyline.CompositingQuality = CompositingQuality.HighQuality; // Set up the canvas. graphicsCyan.Clear(Color.White); graphicsMagenta.Clear(Color.White); graphicsYellow.Clear(Color.White); graphicsKeyline.Clear(Color.White); // This is too slow. The graphics object can't be called within a parallel // loop so we have to do it old school. :( using (FastBitmap sourceBitmap = new FastBitmap(padded)) { for (int y = minY; y < maxY; y += offset) { for (int x = minX; x < maxX; x += offset) { Color color; CmykColor cmykColor; float brushWidth; // Cyan Point rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.cyanAngle, center); int angledX = rotatedPoint.X; int angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = Math.Min((cmykColor.C / 100f) * multiplier, max); graphicsCyan.FillEllipse(cyanBrush, angledX, angledY, brushWidth, brushWidth); } // Magenta rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.magentaAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = Math.Min((cmykColor.M / 100f) * magentaMultiplier, magentaMax); graphicsMagenta.FillEllipse(magentaBrush, angledX, angledY, brushWidth, brushWidth); } // Yellow rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.yellowAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = Math.Min((cmykColor.Y / 100f) * yellowMultiplier, max); graphicsYellow.FillEllipse(yellowBrush, angledX, angledY, brushWidth, brushWidth); } // Keyline rotatedPoint = ImageMaths.RotatePoint(new Point(x, y), this.keylineAngle, center); angledX = rotatedPoint.X; angledY = rotatedPoint.Y; if (rectangle.Contains(new Point(angledX, angledY))) { color = sourceBitmap.GetPixel(angledX, angledY); cmykColor = color; brushWidth = Math.Min((cmykColor.K / 100f) * multiplier, keylineMax); // Just using black is too dark. Brush keylineBrush = new SolidBrush(CmykColor.FromCmykColor(0, 0, 0, cmykColor.K)); graphicsKeyline.FillEllipse(keylineBrush, angledX, angledY, brushWidth, brushWidth); } } } } // Set our white background. using (Graphics graphics = Graphics.FromImage(newImage)) { graphics.Clear(Color.White); } // Blend the colors now to mimic adaptive blending. using (FastBitmap cyanBitmap = new FastBitmap(cyan)) using (FastBitmap magentaBitmap = new FastBitmap(magenta)) using (FastBitmap yellowBitmap = new FastBitmap(yellow)) using (FastBitmap keylineBitmap = new FastBitmap(keyline)) using (FastBitmap destinationBitmap = new FastBitmap(newImage)) { Parallel.For( offset, height, y => { for (int x = offset; x < width; x++) { // ReSharper disable AccessToDisposedClosure Color cyanPixel = cyanBitmap.GetPixel(x, y); Color magentaPixel = magentaBitmap.GetPixel(x, y); Color yellowPixel = yellowBitmap.GetPixel(x, y); Color keylinePixel = keylineBitmap.GetPixel(x, y); // Negate the offset. int xBack = x - offset; int yBack = y - offset; CmykColor blended = cyanPixel.AddAsCmykColor(magentaPixel, yellowPixel, keylinePixel); if (rectangle.Contains(new Point(xBack, yBack))) { destinationBitmap.SetPixel(xBack, yBack, blended); } // ReSharper restore AccessToDisposedClosure } }); } } padded.Dispose(); cyan.Dispose(); magenta.Dispose(); yellow.Dispose(); keyline.Dispose(); source.Dispose(); source = newImage; } catch { if (padded != null) { padded.Dispose(); } if (cyan != null) { cyan.Dispose(); } if (magenta != null) { magenta.Dispose(); } if (yellow != null) { yellow.Dispose(); } if (keyline != null) { keyline.Dispose(); } if (newImage != null) { newImage.Dispose(); } } return source; }
/// <summary> /// Adjust the gamma (intensity of the light) component of the given image. /// </summary> /// <param name="source"> /// The <see cref="Image"/> source to adjust. /// </param> /// <param name="value"> /// The value to adjust the gamma by (typically between .2 and 5). /// </param> /// <returns> /// The <see cref="Bitmap"/> with the gamma adjusted. /// </returns> /// <exception cref="ArgumentOutOfRangeException"> /// Thrown if the value falls outside the acceptable range. /// </exception> public static Bitmap Gamma(Image source, float value) { if (value > 5 || value < .1) { throw new ArgumentOutOfRangeException("value", "Value should be between .1 and 5."); } int width = source.Width; int height = source.Height; Bitmap destination = new Bitmap(width, height); destination.SetResolution(source.HorizontalResolution, source.VerticalResolution); byte[] ramp = new byte[256]; for (int x = 0; x < 256; ++x) { byte val = ((255.0 * Math.Pow(x / 255.0, value)) + 0.5).ToByte(); ramp[x] = val; } using (FastBitmap fastSource = new FastBitmap(source)) { using (FastBitmap fastDestination = new FastBitmap(destination)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable once AccessToDisposedClosure Color color = fastSource.GetPixel(x, y); byte r = ramp[color.R]; byte g = ramp[color.G]; byte b = ramp[color.B]; // ReSharper disable once AccessToDisposedClosure fastDestination.SetPixel(x, y, Color.FromArgb(color.A, r, g, b)); } }); } } //Rectangle rectangle = new Rectangle(0, 0, width, height); //using (Graphics graphics = Graphics.FromImage(destination)) //{ // using (ImageAttributes attributes = new ImageAttributes()) // { // attributes.SetGamma(value); // graphics.DrawImage(source, rectangle, 0, 0, width, height, GraphicsUnit.Pixel, attributes); // } //} source.Dispose(); return destination; }
public void TestFastBitmapLocker() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); // Immediate lock and dispose fastBitmap.Lock().Dispose(); Assert.IsFalse(fastBitmap.Locked, "After disposing of the FastBitmapLocker object, the underlying fast bitmap must be unlocked"); using (var locker = fastBitmap.Lock()) { fastBitmap.SetPixel(0, 0, 0); Assert.AreEqual(fastBitmap, locker.FastBitmap, "The fast bitmap referenced in the fast bitmap locker must be the one that had the original Lock() call"); } Assert.IsFalse(fastBitmap.Locked, "After disposing of the FastBitmapLocker object, the underlying fast bitmap must be unlocked"); // Test the conditional unlocking of the fast bitmap locker by unlocking the fast bitmap before exiting the 'using' block using (fastBitmap.Lock()) { fastBitmap.SetPixel(0, 0, 0); fastBitmap.Unlock(); } }
/// <summary> /// Traces the edges of a given <see cref="Image"/>. /// </summary> /// <param name="source"> /// The source <see cref="Image"/>. /// </param> /// <param name="destination"> /// The destination <see cref="Image"/>. /// </param> /// <param name="threshold"> /// The threshold (between 0 and 255). /// </param> /// <returns> /// The a new instance of <see cref="Bitmap"/> traced. /// </returns> public static Bitmap Trace(Image source, Image destination, byte threshold = 0) { int width = source.Width; int height = source.Height; // Grab the edges converting to greyscale, and invert the colors. ConvolutionFilter filter = new ConvolutionFilter(new SobelEdgeFilter(), true); using (Bitmap temp = filter.Process2DFilter(source)) { destination = new InvertMatrixFilter().TransformImage(temp, destination); // Darken it slightly to aid detection destination = Adjustments.Brightness(destination, -5); } // Loop through and replace any colors more white than the threshold // with a transparent one. using (FastBitmap destinationBitmap = new FastBitmap(destination)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable AccessToDisposedClosure Color color = destinationBitmap.GetPixel(x, y); if (color.B >= threshold) { destinationBitmap.SetPixel(x, y, Color.Transparent); } // ReSharper restore AccessToDisposedClosure } }); } // Darken it again to average out the color. destination = Adjustments.Brightness(destination, -5); return (Bitmap)destination; }
public Bitmap GetImageTransparentPal(int index) { if (ImagesPal == null || ImagesPal.Count <= index) { return null; } if (IsDrawnPal(index) == false) { if (DrawPalImage(index) == false) { throw new Exception("Failed to draw pal-image on index #" + index); } } var img = ImagesPal[index].Image.Clone() as Bitmap; if (img == null) { throw new Exception("Invalid pal image on index #" + index); } var bg = Palette[0]; var fb = new FastBitmap(img); fb.LockImage(); for (var x = 0; x < img.Width; x++) { for (var y = 0; y < img.Height; y++) { if (fb.GetPixel(x, y) == bg) { fb.SetPixel(x, y, Color.Transparent); } } } fb.UnlockImage(); return img; }
public Bitmap GetImageTransparentPal(int index) { if (ImagesPal == null || ImagesPal.Count <= index) { return null; } if (IsDrawnPal(index) == false) { if (DrawPalImage(index) == false) { // TODO: Exception? return null; } } Bitmap img = ImagesPal[index].Image.Clone() as Bitmap; Color bg = Palette[0]; FastBitmap fb = new FastBitmap(img); fb.LockImage(); for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { if (fb.GetPixel(x, y) == bg) { fb.SetPixel(x, y, Color.Transparent); } } } fb.UnlockImage(); return img; }
public bool DrawRgbaImage(int imageIndex) { if (ImagesRgba == null || ImagesRgba.Count <= imageIndex) { return false; } if (imageIndex < 0 || imageIndex >= ImagesRgba.Count) { return false; } RoSpriteImageRgba sprImg = ImagesRgba[imageIndex]; if (sprImg == null || sprImg.Data == null || sprImg.Data.Length == 0 || sprImg.Width < 1 || sprImg.Height < 1) { return false; } sprImg.Image = new Bitmap(sprImg.Width, sprImg.Height); FastBitmap fb = new FastBitmap(sprImg.Image); int index = 0, alpha = 0, red = 0, green = 0, blue = 0; Color col; fb.LockImage(); for (int y = 0; y < sprImg.Height; y++) { for (int x = 0; x < sprImg.Width; x++, index += 4) { // A B G R alpha = sprImg.Data[index]; blue = sprImg.Data[index + 1]; green = sprImg.Data[index + 2]; red = sprImg.Data[index + 3]; col = Color.FromArgb(alpha, red, green, blue); fb.SetPixel(x, y, col); } } fb.UnlockImage(); return true; }
public bool DrawPalImage(int imageIndex) { if (ImagesPal == null || ImagesPal.Count <= imageIndex) { return false; } if (imageIndex < 0 || imageIndex >= ImagesPal.Count) { return false; } RoSpriteImagePal sprImg = ImagesPal[imageIndex]; if (Version >= 0x201 && sprImg.Decoded == false) { sprImg.Data = RLE.Decode(sprImg.Data); sprImg.Decoded = true; } if (sprImg.Data == null || sprImg.Data.Length == 0 || sprImg.Width < 1 || sprImg.Height < 1) { return false; } sprImg.Image = new Bitmap(sprImg.Width, sprImg.Height); FastBitmap fb = new FastBitmap(sprImg.Image); int index; fb.LockImage(); for (int x = 0; x < sprImg.Width; x++) { for (int y = 0; y < sprImg.Height; y++) { index = (x + (y * sprImg.Width)); if (index >= sprImg.Data.Length) { fb.SetPixel(x, y, Color.Transparent); continue; } fb.SetPixel(x, y, Palette[sprImg.Data[index]]); } } fb.UnlockImage(); return true; }
public Bitmap GetImageTransparentRgba(int index) { if (ImagesRgba == null || ImagesRgba.Count <= index) { return null; } if (IsDrawnRgba(index) == false) { DrawRgbaImage(index); } var img = ImagesRgba[index].Image.Clone() as Bitmap; if (img == null) { throw new Exception("Invalid rgba image on index #" + index); } var bg = Color.Fuchsia; var fb = new FastBitmap(img); fb.LockImage(); for (var x = 0; x < img.Width; x++) { for (var y = 0; y < img.Height; y++) { if (fb.GetPixel(x, y) == bg) { fb.SetPixel(x, y, Color.Transparent); } } } fb.UnlockImage(); return img; }
/// <summary> /// Generates a frame image with a given set of parameters. /// The seed is used to randomize the frame, and any call with the same width, height and seed will generate the same image /// </summary> /// <param name="width">The width of the image to generate</param> /// <param name="height">The height of the image to generate</param> /// <param name="seed">The seed for the image, used to seed the random number generator that will generate the image contents</param> /// <returns>An image with the passed parameters</returns> public static Bitmap GenerateRandomBitmap(int width, int height, int seed = -1) { if (seed == -1) { seed = _seedRandom.Next(); } Bitmap bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); // Plot the image with random pixels now Random r = new Random(seed); for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { uint pixelColor = (uint)(r.NextDouble() * 0xFFFFFFFF); fastBitmap.SetPixel(x, y, pixelColor); } } fastBitmap.Unlock(); return bitmap; }
public void TestFastBitmapSetPixelBoundsException() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); try { fastBitmap.SetPixel(-1, -1, 0); Assert.Fail("When trying to access a coordinate that is out of bounds via GetPixel, an exception must be thrown"); } catch (ArgumentOutOfRangeException) { } try { fastBitmap.SetPixel(fastBitmap.Width, 0, 0); Assert.Fail("When trying to access a coordinate that is out of bounds via GetPixel, an exception must be thrown"); } catch (ArgumentOutOfRangeException) { } try { fastBitmap.SetPixel(0, fastBitmap.Height, 0); Assert.Fail("When trying to access a coordinate that is out of bounds via GetPixel, an exception must be thrown"); } catch (ArgumentOutOfRangeException) { } fastBitmap.SetPixel(fastBitmap.Width - 1, fastBitmap.Height - 1, 0); }
public void TestFastBitmapUnlockedSetAccessException() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.SetPixel(0, 0, 0); }
/// <summary> /// Adjust the gamma (intensity of the light) component of the given image. /// </summary> /// <param name="source"> /// The <see cref="Image"/> source to adjust. /// </param> /// <param name="value"> /// The value to adjust the gamma by (typically between .2 and 5). /// </param> /// <returns> /// The <see cref="Bitmap"/> with the gamma adjusted. /// </returns> /// <exception cref="ArgumentOutOfRangeException"> /// Thrown if the value falls outside the acceptable range. /// </exception> public static Bitmap Gamma(Image source, float value) { if (value > 5 || value < .1) { throw new ArgumentOutOfRangeException(nameof(value), "Value should be between .1 and 5."); } byte[] ramp = new byte[256]; for (int x = 0; x < 256; ++x) { byte val = ((255.0 * Math.Pow(x / 255.0, value)) + 0.5).ToByte(); ramp[x] = val; } int width = source.Width; int height = source.Height; using (FastBitmap bitmap = new FastBitmap(source)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable once AccessToDisposedClosure Color composite = bitmap.GetPixel(x, y); Color linear = Color.FromArgb(composite.A, ramp[composite.R], ramp[composite.G], ramp[composite.B]); // ReSharper disable once AccessToDisposedClosure bitmap.SetPixel(x, y, linear); } }); } return (Bitmap)source; }
/// <summary> /// Converts an image from a linear color-space to the equivalent sRGB color-space. /// </summary> /// <param name="source"> /// The <see cref="Image"/> source to convert. /// </param> /// <returns> /// The <see cref="Bitmap"/>. /// </returns> public static Bitmap ToSRGB(Image source) { // Create only once and lazily. byte[] ramp = SRGBBytes.Value; int width = source.Width; int height = source.Height; using (FastBitmap bitmap = new FastBitmap(source)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable once AccessToDisposedClosure Color composite = bitmap.GetPixel(x, y); Color linear = Color.FromArgb(composite.A, ramp[composite.R], ramp[composite.G], ramp[composite.B]); // ReSharper disable once AccessToDisposedClosure bitmap.SetPixel(x, y, linear); } }); } return (Bitmap)source; }
private static void PutPixel(FastBitmap bmp, int index, int color, BluRaySupPalette palette) { int x = index % bmp.Width; int y = index / bmp.Width; if (x < bmp.Width && y < bmp.Height) bmp.SetPixel(x, y, Color.FromArgb(palette.GetArgb(color))); }
/// <summary> /// Applies the oil painting filter. /// </summary> /// <param name="source"> /// The source. /// </param> /// <returns> /// The <see cref="Bitmap"/>. /// </returns> public Bitmap ApplyFilter(Bitmap source) { // TODO: Make this class implement an interface? int width = source.Width; int height = source.Height; int radius = this.brushSize >> 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)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { int maxIntensity = 0; int maxIndex = 0; int[] intensityBin = new int[this.levels]; int[] blueBin = new int[this.levels]; int[] greenBin = new int[this.levels]; int[] redBin = new int[this.levels]; byte sourceAlpha = 255; for (int i = 0; i <= radius; 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 (int fx = 0; fx <= radius; fx++) { int jr = fx - radius; int offsetX = x + jr; // Skip the column if (offsetX < 0) { continue; } if (offsetX < width) { // ReSharper disable once AccessToDisposedClosure Color color = sourceBitmap.GetPixel(offsetX, offsetY); byte sourceBlue = color.B; byte sourceGreen = color.G; byte sourceRed = color.R; sourceAlpha = color.A; int currentIntensity = (int)Math.Round(((sourceBlue + sourceGreen + sourceRed) / 3.0 * (this.levels - 1)) / 255.0); intensityBin[currentIntensity] += 1; blueBin[currentIntensity] += sourceBlue; greenBin[currentIntensity] += sourceGreen; redBin[currentIntensity] += sourceRed; if (intensityBin[currentIntensity] > maxIntensity) { maxIntensity = intensityBin[currentIntensity]; maxIndex = currentIntensity; } } } } byte blue = Math.Abs(blueBin[maxIndex] / maxIntensity).ToByte(); byte green = Math.Abs(greenBin[maxIndex] / maxIntensity).ToByte(); byte red = Math.Abs(redBin[maxIndex] / maxIntensity).ToByte(); // ReSharper disable once AccessToDisposedClosure destinationBitmap.SetPixel(x, y, Color.FromArgb(sourceAlpha, red, green, blue)); } }); } } return destination; }
public static Image ReplaceColor(this Image image, Color oldColor, Color newColor) { if (image == null) { throw new ArgumentNullException("image"); } Image clone = image.Clone() as Image; // If they try to replace a color with itself (sneaky, sneaky!) then just return our cloned image immediately if (oldColor.ToArgb() == newColor.ToArgb()) { return clone; } FastBitmap fastBitmap = new FastBitmap(clone); fastBitmap.Lock(); for (int x = 0; x < image.Width; x++) { for (int y = 0; y < image.Height; y++) { // We use ToArgb because Colors are compared on more than their ARGB values - see Color class documentation on MSDN if (fastBitmap.GetPixel(x, y).ToArgb() == oldColor.ToArgb()) { fastBitmap.SetPixel(x, y, newColor); } } } fastBitmap.Unlock(); return fastBitmap.Image; }
public Bitmap GetImageTransparentRgba(int index) { if (ImagesRgba == null || ImagesRgba.Count <= index) { return null; } if (IsDrawnRgba(index) == false) { DrawRgbaImage(index); } Bitmap img = ImagesRgba[index].Image.Clone() as Bitmap; Color bg = Color.Fuchsia; FastBitmap fb = new FastBitmap(img); fb.LockImage(); for (int x = 0; x < img.Width; x++) { for (int y = 0; y < img.Height; y++) { if (fb.GetPixel(x, y) == bg) { fb.SetPixel(x, y, Color.Transparent); } } } fb.UnlockImage(); return img; }
public void TestSetPixelInt() { Bitmap bitmap1 = new Bitmap(64, 64); Bitmap bitmap2 = new Bitmap(64, 64); FastBitmap fastBitmap1 = new FastBitmap(bitmap1); fastBitmap1.Lock(); Random r = new Random(); for (int y = 0; y < bitmap1.Height; y++) { for (int x = 0; x < bitmap1.Width; x++) { int intColor = r.Next(0xFFFFFF); Color color = Color.FromArgb(intColor); fastBitmap1.SetPixel(x, y, intColor); bitmap2.SetPixel(x, y, color); } } fastBitmap1.Unlock(); AssertBitmapEquals(bitmap1, bitmap2, "Calls to FastBitmap.SetPixel() with an integer overload must be equivalent to calls to Bitmap.SetPixel() with a Color with the same ARGB value as the interger"); }
private static void PutPixel(FastBitmap bmp, int index, Color color) { if (color.A > 0) { int x = index % bmp.Width; int y = index / bmp.Width; if (x < bmp.Width && y < bmp.Height) bmp.SetPixel(x, y, color); } }
private FastBitmap ApplyMask(byte[] mask, FastBitmap img) { Bitmap result = new Bitmap(img.Width, img.Height); FastBitmap fb = new FastBitmap(result); fb.LockBits(); img.LockBits(); int n = 0; for (int j = 0; j < img.Height; j++) { for (int i = 0; i < img.Width; i++) { if (mask[n] > VibeModel.BackgroundByte) { fb.SetPixel(i, j, img.GetPixel(i, j)); } n++; } } img.UnlockBits(); fb.UnlockBits(); return fb; }