/// <summary> /// Get a rectangle for the image which crops the image of all colors equal to that on 0,0 /// </summary> /// <param name="image"></param> /// <param name="cropDifference"></param> /// <returns>NativeRect</returns> public static NativeRect FindAutoCropRectangle(this Image image, int cropDifference) { var cropRectangle = NativeRect.Empty; var checkPoints = new List <NativePoint> { new NativePoint(0, 0), new NativePoint(0, image.Height - 1), new NativePoint(image.Width - 1, 0), new NativePoint(image.Width - 1, image.Height - 1) }; // Top Left // Bottom Left // Top Right // Bottom Right using (var fastBitmap = FastBitmapFactory.Create((Bitmap)image)) { // find biggest area foreach (var checkPoint in checkPoints) { var currentRectangle = fastBitmap.FindAutoCropRectangle(fastBitmap.GetColorAt(checkPoint.X, checkPoint.Y), cropDifference); if (currentRectangle.Width * currentRectangle.Height > cropRectangle.Width * cropRectangle.Height) { cropRectangle = currentRectangle; } } } return(cropRectangle); }
public virtual Bitmap Apply(Bitmap sourceBitmap, Matrix matrix) { var result = FastBitmapFactory.CreateCloneOf(sourceBitmap); result.ApplyBoxBlur(Range); return(result.UnlockAndReturnBitmap()); }
/// <summary> /// Apply BoxBlur to the destinationBitmap /// </summary> /// <param name="destinationBitmap">Bitmap to blur</param> /// <param name="range">Must be ODD, if not +1 is used</param> public static void ApplyBoxBlur(this Bitmap destinationBitmap, int range) { // We only need one fastbitmap as we use it as source and target (the reading is done for one line H/V, writing after "parsing" one line H/V) using (var fastBitmap = FastBitmapFactory.Create(destinationBitmap)) { fastBitmap.ApplyBoxBlur(range); } }
/// <summary> /// Create stitching information for this bitmap /// </summary> /// <param name="bitmap">Bitmap</param> public StitchInfo(Bitmap bitmap) { _bitmap = bitmap; using (var fastBitmap = FastBitmapFactory.Create(bitmap)) { _hashes = Enumerable.Range(0, fastBitmap.Height).Select(i => fastBitmap.HorizontalHash(i)).ToList(); } _sourceRect = new NativeRect(NativePoint.Empty, bitmap.Size); }
/// <summary> /// Use "Scale2x" algorithm to produce bitmap from the original. /// </summary> /// <param name="original">Bitmap to scale 2x</param> public static Bitmap Scale2X(this Bitmap original) { using (var source = (IFastBitmapWithClip)FastBitmapFactory.Create(original)) using (var destination = (IFastBitmapWithClip)FastBitmapFactory.CreateEmpty(new Size(original.Width << 1, original.Height << 1), original.PixelFormat)) { // Every pixel from input texture produces 4 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html Parallel.For(0, source.Height, y => { unsafe { var colorB = stackalloc byte[4]; var colorD = stackalloc byte[4]; var colorE = stackalloc byte[4]; var colorF = stackalloc byte[4]; var colorH = stackalloc byte[4]; var x = 0; while (x < source.Width) { source.GetColorAt(x, y - 1, colorB); source.GetColorAt(x, y + 1, colorH); source.GetColorAt(x - 1, y, colorD); source.GetColorAt(x + 1, y, colorF); source.GetColorAt(x, y, colorE); byte *colorE0, colorE1, colorE2, colorE3; if (!AreColorsSame(colorB, colorH) && !AreColorsSame(colorD, colorF)) { colorE0 = AreColorsSame(colorD, colorB) ? colorD : colorE; colorE1 = AreColorsSame(colorB, colorF) ? colorF : colorE; colorE2 = AreColorsSame(colorD, colorH) ? colorD : colorE; colorE3 = AreColorsSame(colorH, colorF) ? colorF : colorE; } else { colorE0 = colorE; colorE1 = colorE; colorE2 = colorE; colorE3 = colorE; } destination.SetColorAt(x << 1, y << 1, colorE0); destination.SetColorAt((x << 1) + 1, y << 1, colorE1); destination.SetColorAt(x << 1, (y << 1) + 1, colorE2); destination.SetColorAt((x << 1) + 1, (y << 1) + 1, colorE3); x++; } } }); return(destination.UnlockAndReturnBitmap()); } }
/// <summary> /// Helper method to remove the corners from a DMW capture /// </summary> /// <param name="image">The bitmap to remove the corners from.</param> private static void RemoveCorners(Bitmap image) { using (var fastBitmap = FastBitmapFactory.Create(image)) { for (var y = 0; y < CoreConfiguration.WindowCornerCutShape.Count; y++) { for (var x = 0; x < CoreConfiguration.WindowCornerCutShape[y]; x++) { fastBitmap.SetColorAt(x, y, ref _transparentColor); fastBitmap.SetColorAt(image.Width - 1 - x, y, ref _transparentColor); fastBitmap.SetColorAt(image.Width - 1 - x, image.Height - 1 - y, ref _transparentColor); fastBitmap.SetColorAt(x, image.Height - 1 - y, ref _transparentColor); } } } }
/// <summary> /// Apply transparency by comparing a transparent capture with a black and white background /// A "Math.min" makes sure there is no overflow, but this could cause the picture to have shifted colors. /// The pictures should have been taken without differency, except for the colors. /// </summary> /// <param name="blackBitmap">Bitmap with the black image</param> /// <param name="whiteBitmap">Bitmap with the black image</param> /// <returns>Bitmap with transparency</returns> private static Bitmap ApplyTransparency(Bitmap blackBitmap, Bitmap whiteBitmap) { using (var targetBuffer = FastBitmapFactory.CreateEmpty(blackBitmap.Size, PixelFormat.Format32bppArgb, Color.Transparent)) { targetBuffer.SetResolution(blackBitmap.HorizontalResolution, blackBitmap.VerticalResolution); using (var blackBuffer = FastBitmapFactory.Create(blackBitmap)) { using (var whiteBuffer = FastBitmapFactory.Create(whiteBitmap)) { for (var y = 0; y < blackBuffer.Height; y++) { for (var x = 0; x < blackBuffer.Width; x++) { var c0 = blackBuffer.GetColorAt(x, y); var c1 = whiteBuffer.GetColorAt(x, y); // Calculate alpha as double in range 0-1 var alpha = c0.R - c1.R + 255; if (alpha == 255) { // Alpha == 255 means no change! targetBuffer.SetColorAt(x, y, ref c0); } else if (alpha == 0) { // Complete transparency, use transparent pixel targetBuffer.SetColorAt(x, y, ref _transparentColor); } else { // Calculate original color var originalAlpha = (byte)Math.Min(255, alpha); var alphaFactor = alpha / 255d; //Log.Debug().WriteLine("Alpha {0} & c0 {1} & c1 {2}", alpha, c0, c1); var originalRed = (byte)Math.Min(255, c0.R / alphaFactor); var originalGreen = (byte)Math.Min(255, c0.G / alphaFactor); var originalBlue = (byte)Math.Min(255, c0.B / alphaFactor); var originalColor = Color.FromArgb(originalAlpha, originalRed, originalGreen, originalBlue); //Color originalColor = Color.FromArgb(originalAlpha, originalRed, c0.G, c0.B); targetBuffer.SetColorAt(x, y, ref originalColor); } } } } } return(targetBuffer.UnlockAndReturnBitmap()); } }
/// <summary> /// Returns a b/w of Bitmap /// </summary> /// <param name="sourceBitmap">Bitmap to create a b/w of</param> /// <param name="threshold">Threshold for monochrome filter (0 - 255), lower value means less black</param> /// <returns>b/w bitmap</returns> public static Bitmap CreateMonochrome(Bitmap sourceBitmap, byte threshold) { using (var fastBitmap = FastBitmapFactory.CreateCloneOf(sourceBitmap, sourceBitmap.PixelFormat)) { Parallel.For(0, fastBitmap.Height, y => { // TODO: use stackalloc / unsafe for (var x = 0; x < fastBitmap.Width; x++) { var color = fastBitmap.GetColorAt(x, y); var colorBrightness = (color.R + color.G + color.B) / 3 > threshold ? 255 : 0; var monoColor = Color.FromArgb(color.A, colorBrightness, colorBrightness, colorBrightness); fastBitmap.SetColorAt(x, y, ref monoColor); } }); return(fastBitmap.UnlockAndReturnBitmap()); } }
/// <summary> /// Check if the bitmaps are equal /// </summary> /// <param name="bitmap1">Bitmap</param> /// <param name="bitmap2">Bitmap</param> /// <returns>bool true if they are equal</returns> public static bool IsEqualTo(this Bitmap bitmap1, Bitmap bitmap2) { if (bitmap1.Width != bitmap2.Width || bitmap1.Height != bitmap2.Height) { Log.Debug().WriteLine("Different sizes 1={0}, 2={1}", bitmap1.Size, bitmap2.Size); // Different sizes return(false); } if (bitmap1.PixelFormat != bitmap2.PixelFormat) { // Different pixel formats Log.Debug().WriteLine("Different pixel formats 1={0}, 2={1}", bitmap1.PixelFormat, bitmap2.PixelFormat); return(false); } bool result = true; using (var fastBitmap1 = FastBitmapFactory.Create(bitmap1)) using (var fastBitmap2 = FastBitmapFactory.Create(bitmap2)) { Parallel.For(0, fastBitmap1.Height, (y, state) => { unsafe { var tmpColor1 = stackalloc byte[4]; var tmpColor2 = stackalloc byte[4]; for (int x = 0; x < fastBitmap1.Width; x++) { fastBitmap1.GetColorAt(x, y, tmpColor1); fastBitmap2.GetColorAt(x, y, tmpColor2); if (AreColorsSame(tmpColor1, tmpColor2)) { continue; } Log.Debug().WriteLine("Different colors at {0},{1}", x, y); result = false; state.Break(); } } }); } return(result); }
/// <summary> /// Count how many times the supplied color exists /// </summary> /// <param name="sourceImage">Image to count the pixels of</param> /// <param name="colorToCount">Color to count</param> /// <param name="includeAlpha">true if Alpha needs to be checked</param> /// <returns>int with the number of pixels which have colorToCount</returns> public static int CountColor(this Image sourceImage, Color colorToCount, bool includeAlpha = true) { var lockObject = new object(); var colors = 0; var toCount = colorToCount.ToArgb(); if (!includeAlpha) { toCount = toCount & 0xffffff; } using (var bb = FastBitmapFactory.Create((Bitmap)sourceImage)) { Parallel.For(0, bb.Height, () => 0, (y, state, initialColorCount) => { var currentColors = initialColorCount; for (var x = 0; x < bb.Width; x++) { var bitmapcolor = bb.GetColorAt(x, y).ToArgb(); if (!includeAlpha) { bitmapcolor = bitmapcolor & 0xffffff; } if (bitmapcolor == toCount) { currentColors++; } } return(currentColors); }, lineColorCount => { lock (lockObject) { colors += lineColorCount; } }); return(colors); } }
/// <summary> /// Implements the Apply code for the Brightness Filet /// </summary> /// <param name="graphics"></param> /// <param name="applyBitmap"></param> /// <param name="rect"></param> /// <param name="renderMode"></param> public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { var applyRect = BitmapHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { // nothing to do return; } var graphicsState = graphics.Save(); if (Invert) { graphics.SetClip(applyRect); graphics.ExcludeClip(rect); } using (var fastBitmap = FastBitmapFactory.CreateCloneOf(applyBitmap, area: applyRect)) { var highlightColor = GetFieldValueAsColor(FieldType.FILL_COLOR); Parallel.For(fastBitmap.Top, fastBitmap.Bottom, y => { unsafe { var tmpColor = stackalloc byte[4]; for (var x = fastBitmap.Left; x < fastBitmap.Right; x++) { fastBitmap.GetColorAt(x, y, tmpColor); tmpColor[FastBitmapBase.ColorIndexR] = Math.Min(highlightColor.R, tmpColor[FastBitmapBase.ColorIndexR]); tmpColor[FastBitmapBase.ColorIndexG] = Math.Min(highlightColor.G, tmpColor[FastBitmapBase.ColorIndexG]); tmpColor[FastBitmapBase.ColorIndexB] = Math.Min(highlightColor.B, tmpColor[FastBitmapBase.ColorIndexB]); fastBitmap.SetColorAt(x, y, tmpColor); } } }); fastBitmap.DrawTo(graphics, applyRect.Location); } graphics.Restore(graphicsState); }
public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { var blurRadius = GetFieldValueAsInt(FieldType.BLUR_RADIUS); var applyRect = BitmapHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (applyRect.Width == 0 || applyRect.Height == 0) { return; } var state = graphics.Save(); if (Invert) { graphics.SetClip(applyRect); graphics.ExcludeClip(rect); } using (var fastBitmap = FastBitmapFactory.CreateCloneOf(applyBitmap, area: applyRect)) { fastBitmap.ApplyBoxBlur(blurRadius); fastBitmap.DrawTo(graphics, applyRect); } graphics.Restore(state); }
/// <summary> /// Get the image /// </summary> public Bitmap GetQuantizedImage(int allowedColorCount = 256) { if (allowedColorCount > 256) { throw new ArgumentOutOfRangeException(nameof(allowedColorCount), "Quantizing muss be done to get less than 256 colors"); } if (_colorCount < allowedColorCount) { // Simple logic to reduce to 8 bit Log.Info().WriteLine("Colors in the image are already less as whished for, using simple copy to indexed image, no quantizing needed!"); return(SimpleReindex()); } // preprocess the colors CalculateMoments(); Log.Info().WriteLine("Calculated the moments..."); var next = 0; var volumeVariance = new float[Maxcolor]; // processes the cubes for (var cubeIndex = 1; cubeIndex < allowedColorCount; ++cubeIndex) { // if cut is possible; make it if (Cut(_cubes[next], _cubes[cubeIndex])) { volumeVariance[next] = _cubes[next].Volume > 1 ? CalculateVariance(_cubes[next]) : 0.0f; volumeVariance[cubeIndex] = _cubes[cubeIndex].Volume > 1 ? CalculateVariance(_cubes[cubeIndex]) : 0.0f; } else { // the cut was not possible, revert the index volumeVariance[next] = 0.0f; cubeIndex--; } next = 0; var temp = volumeVariance[0]; for (var index = 1; index <= cubeIndex; ++index) { if (volumeVariance[index] <= temp) { continue; } temp = volumeVariance[index]; next = index; } if (temp > 0.0) { continue; } allowedColorCount = cubeIndex + 1; break; } var lookupRed = new int[Maxcolor]; var lookupGreen = new int[Maxcolor]; var lookupBlue = new int[Maxcolor]; _tag = new byte[Maxvolume]; // precalculates lookup tables for (var k = 0; k < allowedColorCount; ++k) { Mark(_cubes[k], k, _tag); var weight = Volume(_cubes[k], _weights); if (weight > 0) { lookupRed[k] = (int)(Volume(_cubes[k], _momentsRed) / weight); lookupGreen[k] = (int)(Volume(_cubes[k], _momentsGreen) / weight); lookupBlue[k] = (int)(Volume(_cubes[k], _momentsBlue) / weight); } else { lookupRed[k] = 0; lookupGreen[k] = 0; lookupBlue[k] = 0; } } _reds = new int[allowedColorCount + 1]; _greens = new int[allowedColorCount + 1]; _blues = new int[allowedColorCount + 1]; _sums = new int[allowedColorCount + 1]; Log.Info().WriteLine("Starting bitmap reconstruction..."); using (var dest = FastBitmapFactory.Create(_resultBitmap) as FastChunkyBitmap) { using (var src = FastBitmapFactory.Create(_sourceBitmap)) { var srcBlend = src as IFastBitmapWithBlend; var lookup = new Dictionary <Color, byte>(); for (var y = 0; y < src.Height; y++) { for (var x = 0; x < src.Width; x++) { Color color; if (srcBlend != null) { // WithoutAlpha, this makes it possible to ignore the alpha color = srcBlend.GetBlendedColorAt(x, y); } else { color = src.GetColorAt(x, y); } // Check if we already matched the color byte bestMatch; if (!lookup.ContainsKey(color)) { // If not we need to find the best match // First get initial match bestMatch = dest.GetColorIndexAt(x, y); bestMatch = _tag[bestMatch]; var bestDistance = 100000000; for (var lookupIndex = 0; lookupIndex < allowedColorCount; lookupIndex++) { var foundRed = lookupRed[lookupIndex]; var foundGreen = lookupGreen[lookupIndex]; var foundBlue = lookupBlue[lookupIndex]; var deltaRed = color.R - foundRed; var deltaGreen = color.G - foundGreen; var deltaBlue = color.B - foundBlue; var distance = deltaRed * deltaRed + deltaGreen * deltaGreen + deltaBlue * deltaBlue; if (distance < bestDistance) { bestDistance = distance; bestMatch = (byte)lookupIndex; } } lookup.Add(color, bestMatch); } else { // Already matched, so we just use the lookup bestMatch = lookup[color]; } _reds[bestMatch] += color.R; _greens[bestMatch] += color.G; _blues[bestMatch] += color.B; _sums[bestMatch]++; dest.SetColorIndexAt(x, y, bestMatch); } } } } // generates palette var imagePalette = _resultBitmap.Palette; var entries = imagePalette.Entries; for (var paletteIndex = 0; paletteIndex < allowedColorCount; paletteIndex++) { if (_sums[paletteIndex] > 0) { _reds[paletteIndex] /= _sums[paletteIndex]; _greens[paletteIndex] /= _sums[paletteIndex]; _blues[paletteIndex] /= _sums[paletteIndex]; } entries[paletteIndex] = Color.FromArgb(255, _reds[paletteIndex], _greens[paletteIndex], _blues[paletteIndex]); } _resultBitmap.Palette = imagePalette; // Make sure the bitmap is not disposed, as we return it. var tmpBitmap = _resultBitmap; _resultBitmap = null; return(tmpBitmap); }
public WuQuantizer(Bitmap sourceBitmap) { _sourceBitmap = sourceBitmap; // Make sure the color count variables are reset var bitArray = new BitArray((int)Math.Pow(2, 24)); _colorCount = 0; // creates all the cubes _cubes = new WuColorCube[Maxcolor]; // initializes all the cubes for (var cubeIndex = 0; cubeIndex < Maxcolor; cubeIndex++) { _cubes[cubeIndex] = new WuColorCube(); } // resets the reference minimums _cubes[0].RedMinimum = 0; _cubes[0].GreenMinimum = 0; _cubes[0].BlueMinimum = 0; // resets the reference maximums _cubes[0].RedMaximum = Maxsideindex; _cubes[0].GreenMaximum = Maxsideindex; _cubes[0].BlueMaximum = Maxsideindex; _weights = new long[Sidesize, Sidesize, Sidesize]; _momentsRed = new long[Sidesize, Sidesize, Sidesize]; _momentsGreen = new long[Sidesize, Sidesize, Sidesize]; _momentsBlue = new long[Sidesize, Sidesize, Sidesize]; _moments = new float[Sidesize, Sidesize, Sidesize]; var table = new int[256]; for (var tableIndex = 0; tableIndex < 256; ++tableIndex) { table[tableIndex] = tableIndex * tableIndex; } // Use a bitmap to store the initial match, which is just as good as an array and saves us 2x the storage using (var sourceFastBitmap = FastBitmapFactory.Create(sourceBitmap)) { var sourceFastBitmapWithBlend = sourceFastBitmap as IFastBitmapWithBlend; sourceFastBitmap.Lock(); using (var destinationFastBitmap = FastBitmapFactory.CreateEmpty(sourceBitmap.Size, PixelFormat.Format8bppIndexed, Color.White) as FastChunkyBitmap) { for (var y = 0; y < sourceFastBitmap.Height; y++) { for (var x = 0; x < sourceFastBitmap.Width; x++) { Color color; if (sourceFastBitmapWithBlend == null) { color = sourceFastBitmap.GetColorAt(x, y); } else { color = sourceFastBitmapWithBlend.GetBlendedColorAt(x, y); } // To count the colors var index = color.ToArgb() & 0x00ffffff; // Check if we already have this color if (!bitArray.Get(index)) { // If not, add 1 to the single colors _colorCount++; bitArray.Set(index, true); } var indexRed = (color.R >> 3) + 1; var indexGreen = (color.G >> 3) + 1; var indexBlue = (color.B >> 3) + 1; _weights[indexRed, indexGreen, indexBlue]++; _momentsRed[indexRed, indexGreen, indexBlue] += color.R; _momentsGreen[indexRed, indexGreen, indexBlue] += color.G; _momentsBlue[indexRed, indexGreen, indexBlue] += color.B; _moments[indexRed, indexGreen, indexBlue] += table[color.R] + table[color.G] + table[color.B]; // Store the initial "match" var paletteIndex = (indexRed << 10) + (indexRed << 6) + indexRed + (indexGreen << 5) + indexGreen + indexBlue; destinationFastBitmap.SetColorIndexAt(x, y, (byte)(paletteIndex & 0xff)); } } _resultBitmap = destinationFastBitmap.UnlockAndReturnBitmap(); } } }
public override void Apply(Graphics graphics, Bitmap applyBitmap, NativeRect rect, RenderMode renderMode) { var pixelSize = GetFieldValueAsInt(FieldTypes.PIXEL_SIZE); BitmapHelper.CreateIntersectRectangle(applyBitmap.Size, rect, Invert); if (pixelSize <= 1 || rect.Width == 0 || rect.Height == 0) { // Nothing to do return; } if (rect.Width < pixelSize) { pixelSize = rect.Width; } if (rect.Height < pixelSize) { pixelSize = rect.Height; } using (var dest = FastBitmapFactory.CreateCloneOf(applyBitmap, area: rect)) { using (var src = FastBitmapFactory.Create(applyBitmap, rect)) { var halbPixelSize = pixelSize / 2; // Create a list of x values var xValues = new List <int>(); for (var x = src.Left - halbPixelSize; x <= src.Right + halbPixelSize; x = x + pixelSize) { xValues.Add(x); } for (var y = src.Top - halbPixelSize; y < src.Bottom + halbPixelSize; y = y + pixelSize) { Parallel.ForEach(xValues, x => { // TODO: Use stackalloc, or byte[]? var colors = new List <Color>(); for (var yy = y; yy < y + pixelSize; yy++) { if (yy < src.Top || yy >= src.Bottom) { continue; } for (var xx = x; xx < x + pixelSize; xx++) { if (xx < src.Left || xx >= src.Right) { continue; } colors.Add(src.GetColorAt(xx, yy)); } } var currentAvgColor = Colors.Mix(colors); for (var yy = y; yy <= y + pixelSize; yy++) { if (yy < src.Top || yy >= src.Bottom) { continue; } for (var xx = x; xx <= x + pixelSize; xx++) { if (xx < src.Left || xx >= src.Right) { continue; } dest.SetColorAt(xx, yy, ref currentAvgColor); } } }); } } dest.DrawTo(graphics, rect.Location); } }
public static Bitmap Scale3X(this Bitmap original) { using (var source = (IFastBitmapWithClip)FastBitmapFactory.Create(original)) using (var destination = (IFastBitmapWithClip)FastBitmapFactory.CreateEmpty(new Size(original.Width * 3, original.Height * 3), original.PixelFormat)) { // Every pixel from input texture produces 6 output pixels, for more details check out http://scale2x.sourceforge.net/algorithm.html Parallel.For(0, source.Height, y => { unsafe { var x = 0; var colorA = stackalloc byte[4]; var colorB = stackalloc byte[4]; var colorC = stackalloc byte[4]; var colorD = stackalloc byte[4]; var colorE = stackalloc byte[4]; var colorF = stackalloc byte[4]; var colorG = stackalloc byte[4]; var colorH = stackalloc byte[4]; var colorI = stackalloc byte[4]; while (x < source.Width) { source.GetColorAt(x - 1, y - 1, colorA); source.GetColorAt(x, y - 1, colorB); source.GetColorAt(x + 1, y - 1, colorC); source.GetColorAt(x - 1, y, colorD); source.GetColorAt(x, y, colorE); source.GetColorAt(x + 1, y, colorF); source.GetColorAt(x - 1, y + 1, colorG); source.GetColorAt(x, y + 1, colorH); source.GetColorAt(x + 1, y + 1, colorI); byte *colorE0, colorE1, colorE2, colorE3, colorE4, colorE5, colorE6, colorE7, colorE8; if (!AreColorsSame(colorB, colorH) && !AreColorsSame(colorD, colorF)) { colorE0 = AreColorsSame(colorD, colorB) ? colorD : colorE; colorE1 = AreColorsSame(colorD, colorB) && !AreColorsSame(colorE, colorC) || AreColorsSame(colorB, colorF) && !AreColorsSame(colorE, colorA) ? colorB : colorE; colorE2 = AreColorsSame(colorB, colorF) ? colorF : colorE; colorE3 = AreColorsSame(colorD, colorB) && !AreColorsSame(colorE, colorG) || AreColorsSame(colorD, colorH) && !AreColorsSame(colorE, colorA) ? colorD : colorE; colorE4 = colorE; colorE5 = AreColorsSame(colorB, colorF) && !AreColorsSame(colorE, colorI) || AreColorsSame(colorH, colorF) && !AreColorsSame(colorE, colorC) ? colorF : colorE; colorE6 = AreColorsSame(colorD, colorH) ? colorD : colorE; colorE7 = AreColorsSame(colorD, colorH) && !AreColorsSame(colorE, colorI) || AreColorsSame(colorH, colorF) && !AreColorsSame(colorE, colorG) ? colorH : colorE; colorE8 = AreColorsSame(colorH, colorF) ? colorF : colorE; } else { colorE0 = colorE; colorE1 = colorE; colorE2 = colorE; colorE3 = colorE; colorE4 = colorE; colorE5 = colorE; colorE6 = colorE; colorE7 = colorE; colorE8 = colorE; } var multipliedX = 3 * x; var multipliedY = 3 * y; destination.SetColorAt(multipliedX, multipliedY, colorE0); destination.SetColorAt(multipliedX + 1, multipliedY, colorE1); destination.SetColorAt(multipliedX + 2, multipliedY, colorE2); multipliedY++; destination.SetColorAt(multipliedX, multipliedY, colorE3); destination.SetColorAt(multipliedX + 1, multipliedY, colorE4); destination.SetColorAt(multipliedX + 2, multipliedY, colorE5); multipliedY++; destination.SetColorAt(multipliedX, multipliedY, colorE6); destination.SetColorAt(multipliedX + 1, multipliedY, colorE7); destination.SetColorAt(multipliedX + 2, multipliedY, colorE8); x++; } } }); return(destination.UnlockAndReturnBitmap()); } }
/// <summary> /// Reindex the 24/32 BPP (A)RGB image to a 8BPP /// </summary> /// <returns>Bitmap</returns> public Bitmap SimpleReindex() { var colors = new List <Color>(); var lookup = new Dictionary <Color, byte>(); using (var bbbDest = FastBitmapFactory.Create(_resultBitmap) as FastChunkyBitmap) { bbbDest.Lock(); using (var bbbSrc = FastBitmapFactory.Create(_sourceBitmap)) { var bbbSrcBlend = bbbSrc as IFastBitmapWithBlend; bbbSrc.Lock(); for (var y = 0; y < bbbSrc.Height; y++) { for (var x = 0; x < bbbSrc.Width; x++) { Color color; if (bbbSrcBlend != null) { color = bbbSrcBlend.GetBlendedColorAt(x, y); } else { color = bbbSrc.GetColorAt(x, y); } byte index; if (lookup.ContainsKey(color)) { index = lookup[color]; } else { colors.Add(color); index = (byte)(colors.Count - 1); lookup.Add(color, index); } bbbDest.SetColorIndexAt(x, y, index); } } } } // generates palette var imagePalette = _resultBitmap.Palette; var entries = imagePalette.Entries; for (var paletteIndex = 0; paletteIndex < 256; paletteIndex++) { if (paletteIndex < _colorCount) { entries[paletteIndex] = colors[paletteIndex]; } else { entries[paletteIndex] = Color.Black; } } _resultBitmap.Palette = imagePalette; // Make sure the bitmap is not disposed, as we return it. var tmpBitmap = _resultBitmap; _resultBitmap = null; return(tmpBitmap); }