public static void ToSepia(BitmapHolder bmp) { var nWidth = bmp.Width; var nHeight = bmp.Height; var len = bmp.PixelCount; for (var i = 0; i < len; i++) { var c = bmp.GetPixelAsInt(i); var a = (c >> 24) & 0x000000FF; var r = (c >> 16) & 0x000000FF; var g = (c >> 8) & 0x000000FF; var b = (c) & 0x000000FF; var rNew = (int)Math.Min((.393 * r) + (.769 * g) + (.189 * (b)), 255.0); var gNew = (int)Math.Min((.349 * r) + (.686 * g) + (.168 * (b)), 255.0); var bNew = (int)Math.Min((.272 * r) + (.534 * g) + (.131 * (b)), 255.0); if (rNew > 255) rNew = 255; if (gNew > 255) gNew = 255; if (bNew > 255) bNew = 255; bmp.SetPixel(i, (a << 24) | (rNew << 16) | (gNew << 8) | bNew); } }
public static void ToReplacedColor(BitmapHolder bmp, int r, int g, int b, int a) { var nWidth = bmp.Width; var nHeight = bmp.Height; var len = bmp.PixelCount; for (var i = 0; i < len; i++) { var c = bmp.GetPixelAsInt(i); var currentAlpha = (c >> 24) & 0x000000FF; var aNew = (int)(currentAlpha * (a / currentAlpha)); var rNew = r; var gNew = g; var bNew = b; if (rNew > 255) rNew = 255; if (gNew > 255) gNew = 255; if (bNew > 255) bNew = 255; bmp.SetPixel(i, (aNew << 24) | (rNew << 16) | (gNew << 8) | bNew); } }
public static BitmapHolder ToFlipped(BitmapHolder bmp, FlipType flipMode) { // Use refs for faster access (really important!) speeds up a lot! var w = bmp.Width; var h = bmp.Height; var i = 0; BitmapHolder result = new BitmapHolder(new byte[bmp.PixelData.Length], w, h); if (flipMode == FlipType.Vertical) { var rp = result.PixelData; for (var y = h - 1; y >= 0; y--) { for (var x = 0; x < w; x++) { var srcInd = y * w + x; result.SetPixel(i, bmp.GetPixelAsInt(srcInd)); i++; } } } else { var rp = result.PixelData; for (var y = 0; y < h; y++) { for (var x = w - 1; x >= 0; x--) { var srcInd = y * w + x; result.SetPixel(i, bmp.GetPixelAsInt(srcInd)); i++; } } } return result; }
public static void ToGrayscale(BitmapHolder bmp) { var nWidth = bmp.Width; var nHeight = bmp.Height; var len = bmp.PixelCount; for (var i = 0; i < len; i++) { var c = bmp.GetPixelAsInt(i); var a = (c >> 24) & 0x000000FF; var r = (c >> 16) & 0x000000FF; var g = (c >> 8) & 0x000000FF; var b = (c) & 0x000000FF; // Convert to gray with constant factors 0.2126, 0.7152, 0.0722 var gray = (r * 6966 + g * 23436 + b * 2366) >> 15; r = g = b = gray; bmp.SetPixel(i, (a << 24) | (r << 16) | (g << 8) | b); } }
public static void ToColorSpace(BitmapHolder bmp, float[][] rgbawMatrix) { var r0 = rgbawMatrix[0][0]; var r1 = rgbawMatrix[0][1]; var r2 = rgbawMatrix[0][2]; var r3 = rgbawMatrix[0][3]; var g0 = rgbawMatrix[1][0]; var g1 = rgbawMatrix[1][1]; var g2 = rgbawMatrix[1][2]; var g3 = rgbawMatrix[1][3]; var b0 = rgbawMatrix[2][0]; var b1 = rgbawMatrix[2][1]; var b2 = rgbawMatrix[2][2]; var b3 = rgbawMatrix[2][3]; var a0 = rgbawMatrix[3][0]; var a1 = rgbawMatrix[3][1]; var a2 = rgbawMatrix[3][2]; var a3 = rgbawMatrix[3][3]; var rOffset = rgbawMatrix[4][0]; var gOffset = rgbawMatrix[4][1]; var bOffset = rgbawMatrix[4][2]; var aOffset = rgbawMatrix[4][3]; var nWidth = bmp.Width; var nHeight = bmp.Height; var len = bmp.PixelCount; for (var i = 0; i < len; i++) { var c = bmp.GetPixelAsInt(i); var a = (c >> 24) & 0x000000FF; var r = (c >> 16) & 0x000000FF; var g = (c >> 8) & 0x000000FF; var b = (c) & 0x000000FF; var rNew = (int)(r * r0 + g * g0 + b * b0 + a * a0 + rOffset); var gNew = (int)(r * r1 + g * g1 + b * b1 + a * a1 + gOffset); var bNew = (int)(r * r2 + g * g2 + b * b2 + a * a2 + bOffset); var aNew = (int)(r * r3 + g * g3 + b * b3 + a * a3 + aOffset); if (rNew > 255) rNew = 255; if (gNew > 255) gNew = 255; if (bNew > 255) bNew = 255; if (aNew > 255) aNew = 255; if (rNew < 0) rNew = 0; if (gNew < 0) gNew = 0; if (bNew < 0) bNew = 0; if (aNew < 0) aNew = 0; bmp.SetPixel(i, (aNew << 24) | (rNew << 16) | (gNew << 8) | bNew); } }
// Source: http://incubator.quasimondo.com/processing/superfast_blur.php public static void ToLegacyBlurred(BitmapHolder source, int radius) { int w = source.Width; int h = source.Height; int wm = w - 1; int hm = h - 1; int wh = w * h; int div = radius + radius + 1; int[] r = new int[wh]; int[] g = new int[wh]; int[] b = new int[wh]; int rsum, gsum, bsum, x, y, i, p, p1, p2, yp, yi, yw; int[] vmin = new int[Math.Max(w, h)]; int[] vmax = new int[Math.Max(w, h)]; int[] dv = new int[256 * div]; for (i = 0; i < 256 * div; i++) { dv[i] = (i / div); } yw = yi = 0; for (y = 0; y < h; y++) { rsum = gsum = bsum = 0; for (i = -radius; i <= radius; i++) { p = source.GetPixelAsInt(yi + Math.Min(wm, Math.Max(i, 0))); rsum += (p & 0xff0000) >> 16; gsum += (p & 0x00ff00) >> 8; bsum += p & 0x0000ff; } for (x = 0; x < w; x++) { r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum]; if (y == 0) { vmin[x] = Math.Min(x + radius + 1, wm); vmax[x] = Math.Max(x - radius, 0); } p1 = source.GetPixelAsInt(yw + vmin[x]); p2 = source.GetPixelAsInt(yw + vmax[x]); rsum += ((p1 & 0xff0000) - (p2 & 0xff0000)) >> 16; gsum += ((p1 & 0x00ff00) - (p2 & 0x00ff00)) >> 8; bsum += (p1 & 0x0000ff) - (p2 & 0x0000ff); yi++; } yw += w; } for (x = 0; x < w; x++) { rsum = gsum = bsum = 0; yp = -radius * w; for (i = -radius; i <= radius; i++) { yi = Math.Max(0, yp) + x; rsum += r[yi]; gsum += g[yi]; bsum += b[yi]; yp += w; } yi = x; for (y = 0; y < h; y++) { // Preserve alpha channel: ( 0xff000000 & pix[yi] ) source.SetPixel(yi, (int)((0xff000000 & (uint)source.GetPixelAsInt(yi)) | (uint)(dv[rsum] << 16) | (uint)(dv[gsum] << 8) | (uint)dv[bsum])); if (x == 0) { vmin[y] = Math.Min(y + radius + 1, hm) * w; vmax[y] = Math.Max(y - radius, 0) * w; } p1 = x + vmin[y]; p2 = x + vmax[y]; rsum += r[p1] - r[p2]; gsum += g[p1] - g[p2]; bsum += b[p1] - b[p2]; yi += w; } } }
public static BitmapHolder ToRotated(BitmapHolder source, double degrees, bool ccw, bool resize) { if (degrees == 0 || degrees % 360 == 0) return source; if (ccw) degrees = 360d - degrees; // rotating clockwise, so it's negative relative to Cartesian quadrants double cnAngle = -1.0 * (Math.PI / 180) * degrees; // general iterators int i, j; // calculated indices in Cartesian coordinates int x, y; double fDistance, fPolarAngle; // for use in neighboring indices in Cartesian coordinates int iFloorX, iCeilingX, iFloorY, iCeilingY; // calculated indices in Cartesian coordinates with trailing decimals double fTrueX, fTrueY; // for interpolation double fDeltaX, fDeltaY; // interpolated "top" pixels double fTopRed, fTopGreen, fTopBlue, fTopAlpha; // interpolated "bottom" pixels double fBottomRed, fBottomGreen, fBottomBlue, fBottomAlpha; // final interpolated color components int iRed, iGreen, iBlue, iAlpha; int iCentreX, iCentreY; int iDestCentreX, iDestCentreY; int iWidth, iHeight, newWidth, newHeight; iWidth = source.Width; iHeight = source.Height; if (!resize || (degrees % 180 == 0)) { newWidth = iWidth; newHeight = iHeight; } else { var rad = degrees / (180 / Math.PI); newWidth = (int)Math.Ceiling(Math.Abs(Math.Sin(rad) * iHeight) + Math.Abs(Math.Cos(rad) * iWidth)); newHeight = (int)Math.Ceiling(Math.Abs(Math.Sin(rad) * iWidth) + Math.Abs(Math.Cos(rad) * iHeight)); } iCentreX = iWidth / 2; iCentreY = iHeight / 2; iDestCentreX = newWidth / 2; iDestCentreY = newHeight / 2; var newSource = new BitmapHolder(new byte[newWidth * newHeight * 4], newWidth, newHeight); var oldw = source.Width; // assigning pixels of destination image from source image // with bilinear interpolation for (i = 0; i < newHeight; ++i) { for (j = 0; j < newWidth; ++j) { // convert raster to Cartesian x = j - iDestCentreX; y = iDestCentreY - i; // convert Cartesian to polar fDistance = Math.Sqrt(x * x + y * y); if (x == 0) { if (y == 0) { // center of image, no rotation needed newSource.SetPixel(i * newWidth + j, source.GetPixelAsInt(iCentreY * oldw + iCentreX)); continue; } if (y < 0) { fPolarAngle = 1.5 * Math.PI; } else { fPolarAngle = 0.5 * Math.PI; } } else { fPolarAngle = Math.Atan2(y, x); } // the crucial rotation part // "reverse" rotate, so minus instead of plus fPolarAngle -= cnAngle; // convert polar to Cartesian fTrueX = fDistance * Math.Cos(fPolarAngle); fTrueY = fDistance * Math.Sin(fPolarAngle); // convert Cartesian to raster fTrueX = fTrueX + iCentreX; fTrueY = iCentreY - fTrueY; iFloorX = (int)(Math.Floor(fTrueX)); iFloorY = (int)(Math.Floor(fTrueY)); iCeilingX = (int)(Math.Ceiling(fTrueX)); iCeilingY = (int)(Math.Ceiling(fTrueY)); // check bounds if (iFloorX < 0 || iCeilingX < 0 || iFloorX >= iWidth || iCeilingX >= iWidth || iFloorY < 0 || iCeilingY < 0 || iFloorY >= iHeight || iCeilingY >= iHeight) continue; fDeltaX = fTrueX - iFloorX; fDeltaY = fTrueY - iFloorY; var clrTopLeft = source.GetPixelAsInt(iFloorY * oldw + iFloorX); var clrTopRight = source.GetPixelAsInt(iFloorY * oldw + iCeilingX); var clrBottomLeft = source.GetPixelAsInt(iCeilingY * oldw + iFloorX); var clrBottomRight = source.GetPixelAsInt(iCeilingY * oldw + iCeilingX); fTopAlpha = (1 - fDeltaX) * ((clrTopLeft >> 24) & 0xFF) + fDeltaX * ((clrTopRight >> 24) & 0xFF); fTopRed = (1 - fDeltaX) * ((clrTopLeft >> 16) & 0xFF) + fDeltaX * ((clrTopRight >> 16) & 0xFF); fTopGreen = (1 - fDeltaX) * ((clrTopLeft >> 8) & 0xFF) + fDeltaX * ((clrTopRight >> 8) & 0xFF); fTopBlue = (1 - fDeltaX) * (clrTopLeft & 0xFF) + fDeltaX * (clrTopRight & 0xFF); // linearly interpolate horizontally between bottom neighbors fBottomAlpha = (1 - fDeltaX) * ((clrBottomLeft >> 24) & 0xFF) + fDeltaX * ((clrBottomRight >> 24) & 0xFF); fBottomRed = (1 - fDeltaX) * ((clrBottomLeft >> 16) & 0xFF) + fDeltaX * ((clrBottomRight >> 16) & 0xFF); fBottomGreen = (1 - fDeltaX) * ((clrBottomLeft >> 8) & 0xFF) + fDeltaX * ((clrBottomRight >> 8) & 0xFF); fBottomBlue = (1 - fDeltaX) * (clrBottomLeft & 0xFF) + fDeltaX * (clrBottomRight & 0xFF); // linearly interpolate vertically between top and bottom interpolated results iRed = (int)(Math.Round((1 - fDeltaY) * fTopRed + fDeltaY * fBottomRed)); iGreen = (int)(Math.Round((1 - fDeltaY) * fTopGreen + fDeltaY * fBottomGreen)); iBlue = (int)(Math.Round((1 - fDeltaY) * fTopBlue + fDeltaY * fBottomBlue)); iAlpha = (int)(Math.Round((1 - fDeltaY) * fTopAlpha + fDeltaY * fBottomAlpha)); // make sure color values are valid if (iRed < 0) iRed = 0; if (iRed > 255) iRed = 255; if (iGreen < 0) iGreen = 0; if (iGreen > 255) iGreen = 255; if (iBlue < 0) iBlue = 0; if (iBlue > 255) iBlue = 255; if (iAlpha < 0) iAlpha = 0; if (iAlpha > 255) iAlpha = 255; var a = iAlpha + 1; var val = (iAlpha << 24) | ((byte)((iRed * a) >> 8) << 16) | ((byte)((iGreen * a) >> 8) << 8) | ((byte)((iBlue * a) >> 8)); newSource.SetPixel(i * newWidth + j, val); } } return newSource; }