/// <summary> /// Return negative of Bitmap /// </summary> /// <param name="sourceBitmap">Bitmap to create a negative off</param> /// <returns>Negative bitmap</returns> public static Bitmap CreateNegative(Bitmap sourceBitmap) { using (BitmapBuffer bb = new BitmapBuffer(sourceBitmap, true)) { bb.Lock(); for (int y = 0; y < bb.Height; y++) { for (int x = 0; x < bb.Width; x++) { Color color = bb.GetColorAt(x, y); Color invertedColor = Color.FromArgb(color.A, color.R ^ 255, color.G ^ 255, color.B ^ 255); bb.SetColorAt(x, y, invertedColor); } } bb.Unlock(); return bb.Bitmap; } }
/// <summary> /// Create a new bitmap with the sourceBitmap blurred /// </summary> /// <param name="sourceBitmap">Source to blur</param> /// <param name="applyRect">Area to blur</param> /// <param name="useExportQuality">Use best quality</param> /// <param name="blurRadius">Radius of the blur</param> /// <param name="previewQuality">Quality, use 1d for normal anything less skipps calculations</param> /// <param name="invert">true if the blur needs to occur outside of the area</param> /// <param name="parentBounds">Rectangle limiting the area when using invert</param> public static unsafe Bitmap CreateBlur(Bitmap sourceBitmap, Rectangle applyRect, bool useExportQuality, int blurRadius, double previewQuality, bool invert, Rectangle parentBounds) { if (applyRect.Height <= 0 || applyRect.Width <= 0) { return null; } // do nothing when nothing can be done! if (blurRadius < 1) { return null; } byte[] nullColor = new byte[] { 255, 255, 255, 255 }; if (sourceBitmap.PixelFormat == PixelFormat.Format32bppArgb) { nullColor = new byte[] { 0, 0, 0, 0 }; } byte[] settingColor = new byte[4]; byte[] readingColor = new byte[4]; using (BitmapBuffer bbbDest = new BitmapBuffer(sourceBitmap, applyRect, true)) { bbbDest.Lock(); using (BitmapBuffer bbbSrc = new BitmapBuffer(sourceBitmap, applyRect, false)) { bbbSrc.Lock(); Random rand = new Random(); unchecked { int r = blurRadius; int[] w = CreateGaussianBlurRow(r); int wlen = w.Length; long* waSums = stackalloc long[wlen]; long* wcSums = stackalloc long[wlen]; long* aSums = stackalloc long[wlen]; long* rSums = stackalloc long[wlen]; long* gSums = stackalloc long[wlen]; long* bSums = stackalloc long[wlen]; for (int y = 0; y < applyRect.Height; ++y) { long waSum = 0; long wcSum = 0; long aSum = 0; long rSum = 0; long gSum = 0; long bSum = 0; for (int wx = 0; wx < wlen; ++wx) { int srcX = wx - r; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; rSums[wx] = 0; gSums[wx] = 0; bSums[wx] = 0; if (srcX >= 0 && srcX < bbbDest.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; if (srcY >= 0 && srcY < bbbDest.Height) { bbbSrc.GetColorIn(srcX, srcY, readingColor); int wp = w[wy]; waSums[wx] += wp; wp *= readingColor[0] + (readingColor[0] >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * readingColor[0]; rSums[wx] += wp * readingColor[1]; gSums[wx] += wp * readingColor[2]; bSums[wx] += wp * readingColor[3]; } } int wwx = w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; rSum += wwx * rSums[wx]; gSum += wwx * gSums[wx]; bSum += wwx * bSums[wx]; } } wcSum >>= 8; if (parentBounds.Contains(applyRect.Left, applyRect.Top + y) ^ invert) { if (waSum == 0 || wcSum == 0) { bbbDest.SetUncheckedColorArrayAt(0, y, nullColor); } else { settingColor[0] = (byte)(aSum / waSum); settingColor[1] = (byte)(rSum / wcSum); settingColor[2] = (byte)(gSum / wcSum); settingColor[3] = (byte)(bSum / wcSum); bbbDest.SetUncheckedColorArrayAt(0, y, settingColor); } } for (int x = 1; x < applyRect.Width; ++x) { for (int i = 0; i < wlen - 1; ++i) { waSums[i] = waSums[i + 1]; wcSums[i] = wcSums[i + 1]; aSums[i] = aSums[i + 1]; rSums[i] = rSums[i + 1]; gSums[i] = gSums[i + 1]; bSums[i] = bSums[i + 1]; } waSum = 0; wcSum = 0; aSum = 0; rSum = 0; gSum = 0; bSum = 0; int wx; for (wx = 0; wx < wlen - 1; ++wx) { long wwx = (long)w[wx]; waSum += wwx * waSums[wx]; wcSum += wwx * wcSums[wx]; aSum += wwx * aSums[wx]; rSum += wwx * rSums[wx]; gSum += wwx * gSums[wx]; bSum += wwx * bSums[wx]; } wx = wlen - 1; waSums[wx] = 0; wcSums[wx] = 0; aSums[wx] = 0; rSums[wx] = 0; gSums[wx] = 0; bSums[wx] = 0; int srcX = x + wx - r; if (srcX >= 0 && srcX < applyRect.Width) { for (int wy = 0; wy < wlen; ++wy) { int srcY = y + wy - r; // only when in EDIT mode, ignore some pixels depending on preview quality if ((useExportQuality || rand.NextDouble() < previewQuality) && srcY >= 0 && srcY < applyRect.Height) { int wp = w[wy]; waSums[wx] += wp; bbbSrc.GetColorIn(srcX, srcY, readingColor); wp *= readingColor[0] + (readingColor[0] >> 7); wcSums[wx] += wp; wp >>= 8; aSums[wx] += wp * readingColor[0]; rSums[wx] += wp * readingColor[1]; gSums[wx] += wp * readingColor[2]; bSums[wx] += wp * readingColor[3]; } } int wr = w[wx]; waSum += wr * waSums[wx]; wcSum += wr * wcSums[wx]; aSum += wr * aSums[wx]; rSum += wr * rSums[wx]; gSum += wr * gSums[wx]; bSum += wr * bSums[wx]; } wcSum >>= 8; if (parentBounds.Contains(applyRect.Left + x, applyRect.Top + y) ^ invert) { if (waSum == 0 || wcSum == 0) { bbbDest.SetUncheckedColorArrayAt(x, y, nullColor); } else { settingColor[0] = (byte)(aSum / waSum); settingColor[1] = (byte)(rSum / wcSum); settingColor[2] = (byte)(gSum / wcSum); settingColor[3] = (byte)(bSum / wcSum); bbbDest.SetUncheckedColorArrayAt(x, y, settingColor); } } } } } } bbbDest.Unlock(); return bbbDest.Bitmap; } }