public void Apply(FastBitmap surface, Rectangle[] roi, int startIndex, int length) { Rectangle regionBounds = Utility.GetRegionBounds (roi, startIndex, length); if (regionBounds != Rectangle.Intersect (surface.GetBounds (), regionBounds)) throw new ArgumentOutOfRangeException ("roi", "Region is out of bounds"); unsafe { for (int x = startIndex; x < startIndex + length; ++x) ApplyRectangle (surface, roi[x]); } }
/// <summary> /// Returns the color count from the palette of the given image. /// </summary> /// <param name="image"> /// The <see cref="System.Drawing.Image"/> to get the colors from. /// </param> /// <returns> /// The <see cref="int"/> representing the color count. /// </returns> public static int GetColorCount(Image image) { ConcurrentDictionary<Color, Color> colors = new ConcurrentDictionary<Color, Color>(); int width = image.Width; int height = image.Height; using (FastBitmap fastBitmap = new FastBitmap(image)) { Parallel.For( 0, height, y => { for (int x = 0; x < width; x++) { // ReSharper disable once AccessToDisposedClosure Color color = fastBitmap.GetPixel(x, y); colors.TryAdd(color, color); } }); } int count = colors.Count; colors.Clear(); return count; }
public static int CountColors(this Image image) { if (image == null) { throw new ArgumentNullException("image"); } HashSet<int> colors = new HashSet<int>(); FastBitmap fastBitmap = new FastBitmap(image); fastBitmap.Lock(); // Loop through all the pixels of the image // and add the colors to the HashSet - duplicates // are automatically ignored by that collection type 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 colors.Add(fastBitmap.GetPixel(x, y).ToArgb()); } } fastBitmap.Unlock(); return colors.Count; }
/// <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; }
public void TestFastBitmapCreation() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); fastBitmap.Unlock(); // Try creating a FastBitmap with different 32bpp depths try { // ReSharper disable once ObjectCreationAsStatement new FastBitmap(new Bitmap(1, 1, PixelFormat.Format32bppArgb)); // ReSharper disable once ObjectCreationAsStatement new FastBitmap(new Bitmap(1, 1, PixelFormat.Format32bppPArgb)); // ReSharper disable once ObjectCreationAsStatement new FastBitmap(new Bitmap(1, 1, PixelFormat.Format32bppRgb)); } catch (ArgumentException) { Assert.Fail("The FastBitmap should accept any type of 32bpp pixel format bitmap"); } // Try creating a FastBitmap with a bitmap of a bit depth different from 32bpp Bitmap invalidBitmap = new Bitmap(64, 64, PixelFormat.Format4bppIndexed); // ReSharper disable once ObjectCreationAsStatement new FastBitmap(invalidBitmap); }
/// <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> Disposes the atlas bitmap that contains animation frames, and clears /// the list of defined animations. </summary> public void Dispose() { animations.Clear(); if( bmp == null ) return; fastBmp.Dispose(); fastBmp = null; bmp.Dispose(); bmp = null; }
/// <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; }
/// <summary> Disposes the atlas bitmap that contains animation frames, and clears /// the list of defined animations. </summary> public void Clear() { animations.Clear(); if( animBmp == null ) return; animsBuffer.Dispose(); animsBuffer = null; animBmp.Dispose(); animBmp = null; validated = false; }
protected unsafe virtual void RenderEffect(FastBitmap src, FastBitmap dst, Rectangle roi) { PixelData* src_data_ptr = (PixelData*)src.DataPtr; int src_width = src.Width; PixelData* dst_data_ptr = (PixelData*)dst.DataPtr; int dst_width = dst.Width; for (int y = roi.Y; y < roi.Bottom; ++y) { PixelData* srcPtr = src.GetPointAddressUnchecked (src_data_ptr, src_width, roi.X, y); PixelData* dstPtr = dst.GetPointAddressUnchecked (dst_data_ptr, dst_width, roi.X, y); RenderLine (srcPtr, dstPtr, roi.Width); } }
/// <summary> /// Provides a default implementation for performing dst = F(dst, src) or F(src) over some rectangle /// of interest. May be slightly faster than calling the other multi-parameter Apply method, as less /// variables are used in the implementation, thus inducing less register pressure. /// </summary> /// <param name="dst">The Surface to write pixels to, and from which pixels are read and used as the lhs parameter for calling the method <b>PixelData Apply(PixelData, PixelData)</b>.</param> /// <param name="dstOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the dst Surface.</param> /// <param name="src">The Surface to read pixels from for the rhs parameter given to the method <b>PixelData Apply(PixelData, PixelData)</b>b>.</param></param> /// <param name="srcOffset">The pixel offset that defines the upper-left of the rectangle-of-interest for the src Surface.</param> /// <param name="roiSize">The size of the rectangles-of-interest for all Surfaces.</param> public void ApplyBase(FastBitmap dst, Point dstOffset, FastBitmap src, Point srcOffset, Size roiSize) { // Create bounding rectangles for each Surface Rectangle dstRect = new Rectangle (dstOffset, roiSize); if (dstRect.Width == 0 || dstRect.Height == 0) return; Rectangle srcRect = new Rectangle (srcOffset, roiSize); if (srcRect.Width == 0 || srcRect.Height == 0) return; // Clip those rectangles to those Surface's bounding rectangles Rectangle dstClip = Rectangle.Intersect (dstRect, dst.GetBounds ()); Rectangle srcClip = Rectangle.Intersect (srcRect, src.GetBounds ()); // If any of those Rectangles actually got clipped, then throw an exception if (dstRect != dstClip) throw new ArgumentOutOfRangeException ( "roiSize", "Destination roi out of bounds" + string.Format (", dst.Size=({0},{1}", dst.Width, dst.Height) + ", dst.Bounds=" + dst.GetBounds ().ToString () + ", dstOffset=" + dstOffset.ToString () + string.Format (", src.Size=({0},{1}", src.Width, src.Height) + ", srcOffset=" + srcOffset.ToString () + ", roiSize=" + roiSize.ToString () + ", dstRect=" + dstRect.ToString () + ", dstClip=" + dstClip.ToString () + ", srcRect=" + srcRect.ToString () + ", srcClip=" + srcClip.ToString () ); if (srcRect != srcClip) throw new ArgumentOutOfRangeException ("roiSize", "Source roi out of bounds"); // Cache the width and height properties int width = roiSize.Width; int height = roiSize.Height; // Do the work. unsafe { for (int row = 0; row < roiSize.Height; ++row) { PixelData* dstPtr = dst.GetPointAddress (dstOffset.X, dstOffset.Y + row); PixelData* srcPtr = src.GetPointAddress (srcOffset.X, srcOffset.Y + row); Apply (dstPtr, srcPtr, width); } } }
//tiles = 16 means 16 x 16 atlas public List<Bitmap> Atlas2dInto1d(Bitmap atlas2d, int tiles, int atlassizezlimit) { FastBitmap orig = new FastBitmap(); orig.bmp = atlas2d; int tilesize = atlas2d.Width / tiles; int atlasescount = Math.Max(1, (tiles * tiles * tilesize) / atlassizezlimit); List<Bitmap> atlases = new List<Bitmap>(); orig.Lock(); //256 x 1 FastBitmap atlas1d = null; for (int i = 0; i < tiles * tiles; i++) { int x = i % tiles; int y = i / tiles; int tilesinatlas = (tiles * tiles / atlasescount); if (i % tilesinatlas == 0) { if (atlas1d != null) { atlas1d.Unlock(); atlases.Add(atlas1d.bmp); } atlas1d = new FastBitmap(); atlas1d.bmp = new Bitmap(tilesize, atlassizezlimit); atlas1d.Lock(); } for (int xx = 0; xx < tilesize; xx++) { for (int yy = 0; yy < tilesize; yy++) { int c = orig.GetPixel(x * tilesize + xx, y * tilesize + yy); atlas1d.SetPixel(xx, (i % tilesinatlas) * tilesize + yy, c); } } } atlas1d.Unlock(); atlases.Add(atlas1d.bmp); orig.Unlock(); return atlases; }
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 void TestSequentialFastBitmapLocking() { Bitmap bitmap = new Bitmap(64, 64); FastBitmap fastBitmap = new FastBitmap(bitmap); Assert.IsFalse(fastBitmap.Locked, "Immediately after creation, the FastBitmap.Locked property must be false"); fastBitmap.Lock(); Assert.IsTrue(fastBitmap.Locked, "After a successful call to .Lock(), the .Locked property must be true"); fastBitmap.Unlock(); Assert.IsFalse(fastBitmap.Locked, "After a successful call to .Lock(), the .Locked property must be false"); fastBitmap = new FastBitmap(bitmap); fastBitmap.Lock(); fastBitmap.Unlock(); }
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; }
public static bool CompareColors(this Image image, Image other) { if (image == null || other == null) { throw new ArgumentNullException(image == null ? "image" : "other"); } if (image.Size != other.Size) { return false; } FastBitmap fastImage = new FastBitmap(image); FastBitmap fastOther = new FastBitmap(other); try { fastImage.Lock(); fastOther.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 (fastImage.GetPixel(x, y).ToArgb() != fastOther.GetPixel(x, y).ToArgb()) { return false; } } } } finally { fastImage.Unlock(); fastOther.Unlock(); } return true; }
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> /// Decode caption from the input stream /// </summary> /// <returns>bitmap of the decoded caption</returns> public static Bitmap DecodeImage(PcsObject pcs, IList<OdsData> data, List<PaletteInfo> palettes) { if (pcs == null || data == null || data.Count == 0) return new Bitmap(1, 1); int w = data[0].Size.Width; int h = data[0].Size.Height; var bm = new FastBitmap(new Bitmap(w, h)); bm.LockImage(); BluRaySupPalette pal = DecodePalette(palettes); int index = 0; int ofs = 0; int xpos = 0; byte[] buf = data[0].Fragment.ImageBuffer; index = 0; do { int b = buf[index++] & 0xff; if (b == 0 && index < buf.Length) { b = buf[index++] & 0xff; if (b == 0) { // next line ofs = (ofs / w) * w; if (xpos < w) ofs += w; xpos = 0; } else { int size; if ((b & 0xC0) == 0x40) { if (index < buf.Length) { // 00 4x xx -> xxx zeroes size = ((b - 0x40) << 8) + (buf[index++] & 0xff); Color c = Color.FromArgb(pal.GetArgb(0)); for (int i = 0; i < size; i++) PutPixel(bm, ofs++, c); xpos += size; } } else if ((b & 0xC0) == 0x80) { if (index < buf.Length) { // 00 8x yy -> x times value y size = (b - 0x80); b = buf[index++] & 0xff; Color c = Color.FromArgb(pal.GetArgb(b)); for (int i = 0; i < size; i++) PutPixel(bm, ofs++, c); xpos += size; } } else if ((b & 0xC0) != 0) { if (index < buf.Length) { // 00 cx yy zz -> xyy times value z size = ((b - 0xC0) << 8) + (buf[index++] & 0xff); b = buf[index++] & 0xff; Color c = Color.FromArgb(pal.GetArgb(b)); for (int i = 0; i < size; i++) PutPixel(bm, ofs++, c); xpos += size; } } else { // 00 xx -> xx times 0 Color c = Color.FromArgb(pal.GetArgb(0)); for (int i = 0; i < b; i++) PutPixel(bm, ofs++, c); xpos += b; } } } else { PutPixel(bm, ofs++, b, pal); xpos++; } } while (index < buf.Length); bm.UnlockImage(); return bm.GetBitmap(); }
public void SetAtlas( Bitmap bmp ) { Dispose(); this.bmp = bmp; fastBmp = new FastBitmap( bmp, true ); }
unsafe void ApplyAnimation( AnimationData data ) { data.Tick--; if( data.Tick >= 0 ) return; data.CurrentState++; data.CurrentState %= data.StatesCount; data.Tick = data.TickDelay; TerrainAtlas1D atlas = game.TerrainAtlas1D; int texId = ( data.TileY << 4 ) | data.TileX; int index = atlas.Get1DIndex( texId ); int rowNum = atlas.Get1DRowId( texId ); int size = data.FrameSize; byte* temp = stackalloc byte[size * size * 4]; FastBitmap part = new FastBitmap( size, size, size * 4, (IntPtr)temp ); FastBitmap.MovePortion( data.FrameX + data.CurrentState * size, data.FrameY, 0, 0, fastBmp, part, size ); api.UpdateTexturePart( atlas.TexIds[index], 0, rowNum * game.TerrainAtlas.elementSize, part ); }
/// <summary> /// Performs object detection on the given frame. /// </summary> /// //public Rectangle[] ProcessFrame(Bitmap frame) //{ // using (FastBitmap fastBitmap = new FastBitmap(frame)) // { // return ProcessFrame(fastBitmap); // } //} /// <summary> /// Performs object detection on the given frame. /// </summary> /// public Rectangle[] ProcessFrame(Bitmap image) { // int colorChannel = // image.PixelFormat == PixelFormat.Format8bppIndexed ? 0 : channel; Rectangle[] objects; // Creates an integral image representation of the frame using (FastBitmap fastBitmap = new FastBitmap(image, this.classifier.Cascade.HasTiltedFeatures)) { // Creates a new list of detected objects. this.detectedObjects.Clear(); int width = fastBitmap.Width; int height = fastBitmap.Height; // Update parameters only if different size if (steps == null || width != lastWidth || height != lastHeight) update(width, height); Rectangle window = Rectangle.Empty; // For each scaling step for (int i = 0; i < steps.Length; i++) { float scaling = steps[i]; // Set the classifier window scale classifier.Scale = scaling; // Get the scaled window size window.Width = (int)(baseWidth * scaling); window.Height = (int)(baseHeight * scaling); // Check if the window is lesser than the minimum size if (window.Width < minSize.Width || window.Height < minSize.Height) { // If we are searching in greater to smaller mode, if (scalingMode == ObjectDetectorScalingMode.GreaterToSmaller) { break; // it won't get bigger, so we should stop. } else continue; // continue until it gets greater. } // Check if the window is greater than the maximum size else if (window.Width > maxSize.Width || window.Height > maxSize.Height) { // If we are searching in greater to smaller mode, if (scalingMode == ObjectDetectorScalingMode.GreaterToSmaller) { continue; // continue until it gets smaller. } break; // it won't get smaller, so we should stop. } // Grab some scan loop parameters int xStep = window.Width >> 3; int yStep = window.Height >> 3; int xEnd = width - window.Width; int yEnd = height - window.Height; // Parallel mode. Scan the integral image searching // for objects in the window with parallelization. var bag = new System.Collections.Concurrent.ConcurrentBag<Rectangle>(); int numSteps = (int)Math.Ceiling((double)yEnd / yStep); // For each pixel in the window column var window1 = window; Parallel.For( 0, numSteps, (j, options) => { int y = j * yStep; // Create a local window reference Rectangle localWindow = window1; localWindow.Y = y; // For each pixel in the window row for (int x = 0; x < xEnd; x += xStep) { if (options.ShouldExitCurrentIteration) return; localWindow.X = x; // Try to detect and object inside the window if (classifier.Compute(fastBitmap, localWindow)) { // an object has been detected bag.Add(localWindow); if (searchMode == ObjectDetectorSearchMode.Single) options.Stop(); } } }); // If required, avoid adding overlapping objects at // the expense of extra computation. Otherwise, only // add objects to the detected objects collection. if (searchMode == ObjectDetectorSearchMode.NoOverlap) { foreach (Rectangle obj in bag) { if (!overlaps(obj)) { detectedObjects.Add(obj); } } } else if (searchMode == ObjectDetectorSearchMode.Single) { if (bag.TryPeek(out window)) { detectedObjects.Add(window); break; } } else { foreach (Rectangle obj in bag) { detectedObjects.Add(obj); } } } } objects = detectedObjects.ToArray(); if (searchMode == ObjectDetectorSearchMode.Average) { objects = match.Group(objects); } checkSteadiness(objects); lastObjects = objects; return objects; // Returns the array of detected objects. }
/// <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; }
/// <summary> /// Initializes a new instance of the FastBitmapLocker struct with an initial fast bitmap object. /// The fast bitmap object passed will be unlocked after calling Dispose() on this struct /// </summary> /// <param name="fastBitmap">A fast bitmap to attach to this locker which will be released after a call to Dispose</param> public FastBitmapLocker(FastBitmap fastBitmap) { _fastBitmap = fastBitmap; }
/// <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; }
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> /// 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; }
/// <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> /// 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; }
void Convert2DTo1D( TerrainAtlas2D atlas2D, int atlasesCount, int atlas1DHeight ) { TexIds = new int[atlasesCount]; Utils.LogDebug( "Loaded new atlas: {0} bmps, {1} per bmp", atlasesCount, elementsPerAtlas1D ); int index = 0; using( FastBitmap atlas = new FastBitmap( atlas2D.AtlasBitmap, true, true ) ) { for( int i = 0; i < TexIds.Length; i++ ) Make1DTexture( i, atlas, atlas2D, atlas1DHeight, ref index ); } }
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); } }
void Make1DTexture( int i, FastBitmap atlas, TerrainAtlas2D atlas2D, int atlas1DHeight, ref int index ) { int elemSize = atlas2D.elementSize; using( Bitmap atlas1d = new Bitmap( atlas2D.elementSize, atlas1DHeight ) ) using( FastBitmap dst = new FastBitmap( atlas1d, true, false ) ) { for( int index1D = 0; index1D < elementsPerAtlas1D; index1D++ ) { FastBitmap.MovePortion( (index & 0x0F) * elemSize, (index >> 4) * elemSize, 0, index1D * elemSize, atlas, dst, elemSize ); index++; } TexIds[i] = graphics.CreateTexture( dst ); } }