/// <summary> /// Flips (reflects the image) either vertical or horizontal. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="flipMode">The flip mode.</param> /// <returns>A new WriteableBitmap that is a flipped version of the input.</returns> public static BitmapBuffer Flip(this BitmapBuffer bmp, FlipMode flipMode) { using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { // Use refs for faster access (really important!) speeds up a lot! int w = context.Width; int h = context.Height; int[] p = context.Pixels; int i = 0; BitmapBuffer result = BitmapBufferFactory.New(w, h); switch (flipMode) { default: throw new NotSupportedException(); case FlipMode.Vertical: using (BitmapContext destContext = result.GetBitmapContext()) { int[] rp = destContext.Pixels; for (int y = h - 1; y >= 0; y--) { for (int x = 0; x < w; x++) { int srcInd = y * w + x; rp[i] = p[srcInd]; i++; } } } break; case FlipMode.Horizontal: using (BitmapContext destContext = result.GetBitmapContext()) { int[] rp = destContext.Pixels; for (int y = 0; y < h; y++) { for (int x = w - 1; x >= 0; x--) { int srcInd = y * w + x; rp[i] = p[srcInd]; i++; } } } break; } return(result); } }
/// <summary> /// Fills the whole WriteableBitmap with a color. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="color">The color used for filling.</param> public static void Clear(this BitmapBuffer bmp, ColorInt color) { using (BitmapContext context = bmp.GetBitmapContext()) { Clear(context, color); } }
/// <summary> /// Draws an anti-aliased, alpha blended, colored line by connecting two points using Wu's antialiasing algorithm /// Uses the pixels array and the width directly for best performance. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x1">The x0.</param> /// <param name="y1">The y0.</param> /// <param name="x2">The x1.</param> /// <param name="y2">The y1.</param> /// <param name="sa">Alpha color component</param> /// <param name="sr">Premultiplied red color component</param> /// <param name="sg">Premultiplied green color component</param> /// <param name="sb">Premultiplied blue color component</param> /// <param name="clipRect">The region in the image to restrict drawing to.</param> public static void DrawLineWu(this BitmapBuffer bmp, int x1, int y1, int x2, int y2, int sa, int sr, int sg, int sb, RectD?clipRect = null) { using (BitmapContext context = bmp.GetBitmapContext()) { DrawLineWu(context, bmp.PixelWidth, bmp.PixelHeight, x1, y1, x2, y2, sa, sr, sg, sb, clipRect); } }
///// <summary> ///// Applies the given function to all the pixels of the bitmap in ///// order to set their color. ///// </summary> ///// <param name="bmp">The WriteableBitmap.</param> ///// <param name="func">The function to apply. With parameters x, y and a color as a result</param> //public static void dbugForEach(this BitmapBuffer bmp, Func<int, int, ColorInt> func) //{ // using (var context = bmp.GetBitmapContext()) // { // int[] pixels = context.Pixels; // int w = context.Width; // int h = context.Height; // int index = 0; // for (int y = 0; y < h; y++) // { // for (int x = 0; x < w; x++) // { // pixels[index++] = func(x, y).ToPreMultAlphaColor(); // } // } // } //} ///// <summary> ///// Applies the given function to all the pixels of the bitmap in ///// order to set their color. ///// </summary> ///// <param name="bmp">The WriteableBitmap.</param> ///// <param name="func">The function to apply. With parameters x, y, source color and a color as a result</param> //public static void dbugForEach(this BitmapBuffer bmp, Func<int, int, ColorInt, ColorInt> func) //{ // using (var context = bmp.GetBitmapContext()) // { // int[] pixels = context.Pixels; // int w = context.Width; // int h = context.Height; // int index = 0; // for (int y = 0; y < h; y++) // { // for (int x = 0; x < w; x++) // { // int c = pixels[index]; // // Premultiplied Alpha! // byte a = (byte)(c >> 24); // // Prevent division by zero // int ai = a; // if (ai == 0) // { // ai = 1; // } // // Scale inverse alpha to use cheap integer mul bit shift // ai = ((255 << 8) / ai); // ColorInt srcColor = ColorInt.FromArgb(a, // (byte)((((c >> 16) & 0xFF) * ai) >> 8), // (byte)((((c >> 8) & 0xFF) * ai) >> 8), // (byte)((((c & 0xFF) * ai) >> 8))); // pixels[index++] = func(x, y, srcColor).ToPreMultAlphaColor(); // } // } // } //} /// <summary> /// Gets the color of the pixel at the x, y coordinate as integer. /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x">The x coordinate of the pixel.</param> /// <param name="y">The y coordinate of the pixel.</param> /// <returns>The color of the pixel at x, y.</returns> public static int dbugGetPixeli(this BitmapBuffer bmp, int x, int y) { using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { return(context.Pixels[y * context.Width + x]); } }
/// <summary> /// Creates a new WriteableBitmap which is the grayscaled version of this one and returns it. The gray values are equal to the brightness values. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <returns>The new gray WriteableBitmap.</returns> public static BitmapBuffer Gray(this BitmapBuffer bmp) { using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { int nWidth = context.Width; int nHeight = context.Height; int[] px = context.Pixels; BitmapBuffer result = BitmapBufferFactory.New(nWidth, nHeight); using (BitmapContext dest = result.GetBitmapContext()) { int[] rp = dest.Pixels; int len = context.Length; for (int i = 0; i < len; i++) { // Extract int c = px[i]; int a = (c >> 24) & 0xff; int r = (c >> 16) & 0xff; int g = (c >> 8) & 0xff; int b = (c) & 0xff; // Convert to gray with constant factors 0.2126, 0.7152, 0.0722 r = g = b = ((r * 6966 + g * 23436 + b * 2366) >> 15); // Set rp[i] = (a << 24) | (r << 16) | (g << 8) | b; } } return(result); } }
/// <summary> /// Sets the color of the pixel using an extra alpha value and a precalculated index (faster). /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="index">The coordinate index.</param> /// <param name="a">The alpha value of the color.</param> /// <param name="color">The color.</param> public static void SetPixeli(this BitmapBuffer bmp, int index, byte a, ColorInt color) { using (BitmapContext context = bmp.GetBitmapContext()) { context.Pixels[index] = color.ToPreMultAlphaColor(); } }
/// <summary> /// Draws a closed Cardinal spline (cubic) defined by a point collection. /// The cardinal spline passes through each point in the collection. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="points">The points for the curve in x and y pairs, therefore the array is interpreted as (x1, y1, x2, y2, x3, y3, x4, y4, x1, x2 ..., xn, yn).</param> /// <param name="tension">The tension of the curve defines the shape. Usually between 0 and 1. 0 would be a straight line.</param> /// <param name="color">The color for the spline.</param> public static void DrawCurveClosed(this BitmapBuffer bmp, int[] points, float tension, int color) { using (BitmapContext context = bmp.GetBitmapContext()) { // Use refs for faster access (really important!) speeds up a lot! int w = context.Width; int h = context.Height; int pn = points.Length; // First segment DrawCurveSegment(points[pn - 2], points[pn - 1], points[0], points[1], points[2], points[3], points[4], points[5], tension, color, context, w, h); // Middle segments int i; for (i = 2; i < pn - 4; i += 2) { DrawCurveSegment(points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[i + 4], points[i + 5], tension, color, context, w, h); } // Last segment DrawCurveSegment(points[i - 2], points[i - 1], points[i], points[i + 1], points[i + 2], points[i + 3], points[0], points[1], tension, color, context, w, h); // Last-to-First segment DrawCurveSegment(points[i], points[i + 1], points[i + 2], points[i + 3], points[0], points[1], points[2], points[3], tension, color, context, w, h); } }
/// <summary> /// Draws an anti-aliased line with a desired stroke thickness /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color for the line.</param> /// <param name="strokeThickness">The stroke thickness of the line.</param> /// </summary> public static void DrawLineAa(this BitmapBuffer bmp, int x1, int y1, int x2, int y2, ColorInt color, int strokeThickness, RectD?clipRect = null) { using (BitmapContext context = bmp.GetBitmapContext()) { AAWidthLine(bmp.PixelWidth, bmp.PixelHeight, context, x1, y1, x2, y2, strokeThickness, color.ToPreMultAlphaColor(), clipRect); } }
/// <summary> /// Fills the whole WriteableBitmap with an empty color (0). /// </summary> /// <param name="bmp">The WriteableBitmap.</param> public static void Clear(this BitmapBuffer bmp) { using (BitmapContext context = bmp.GetBitmapContext()) { context.Clear(); } }
/// <summary> /// Creates a new inverted WriteableBitmap and returns it. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <returns>The new inverted WriteableBitmap.</returns> public static BitmapBuffer Invert(this BitmapBuffer bmp) { using (BitmapContext srcContext = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { var result = BitmapBufferFactory.New(srcContext.Width, srcContext.Height); using (BitmapContext resultContext = result.GetBitmapContext()) { int[] rp = resultContext.Pixels; int[] p = srcContext.Pixels; int length = srcContext.Length; for (int i = 0; i < length; i++) { // Extract int c = p[i]; int a = (c >> 24) & 0xff; int r = (c >> 16) & 0xff; int g = (c >> 8) & 0xff; int b = (c) & 0xff; // Invert r = 255 - r; g = 255 - g; b = 255 - b; // Set rp[i] = (a << 24) | (r << 16) | (g << 8) | b; } return(result); } } }
/// <summary> /// Sets the color of the pixel. /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x">The x coordinate (row).</param> /// <param name="y">The y coordinate (column).</param> /// <param name="color">The color.</param> public static void SetPixel(this BitmapBuffer bmp, int x, int y, int color) { using (BitmapContext context = bmp.GetBitmapContext()) { context.Pixels[y * context.Width + x] = color; } }
/// <summary> /// Draws a colored line by connecting two points using an optimized DDA. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color for the line.</param> /// <param name="clipRect">The region in the image to restrict drawing to.</param> public static void DrawLine(this BitmapBuffer bmp, int x1, int y1, int x2, int y2, int color, RectD?clipRect = null) { using (BitmapContext context = bmp.GetBitmapContext()) { DrawLine(context, context.Width, context.Height, x1, y1, x2, y2, color, clipRect); } }
/// <summary> /// Sets the color of the pixel. /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x">The x coordinate (row).</param> /// <param name="y">The y coordinate (column).</param> /// <param name="color">The color.</param> public static void SetPixel(this BitmapBuffer bmp, int x, int y, ColorInt color) { using (BitmapContext context = bmp.GetBitmapContext()) { context.Pixels[y * context.Width + x] = color.ToPreMultAlphaColor(); } }
/// <summary> /// Sets the color of the pixel using a precalculated index (faster). /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="index">The coordinate index.</param> /// <param name="color">The color.</param> public static void SetPixeli(this BitmapBuffer bmp, int index, int color) { using (BitmapContext context = bmp.GetBitmapContext()) { context.Pixels[index] = color; } }
/// <summary> /// Sets the color of the pixel including the alpha value. /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x">The x coordinate (row).</param> /// <param name="y">The y coordinate (column).</param> /// <param name="a">The alpha value of the color.</param> /// <param name="r">The red value of the color.</param> /// <param name="g">The green value of the color.</param> /// <param name="b">The blue value of the color.</param> public static void SetPixel(this BitmapBuffer bmp, int x, int y, byte a, byte r, byte g, byte b) { using (BitmapContext context = bmp.GetBitmapContext()) { context.Pixels[y * context.Width + x] = (a << 24) | (r << 16) | (g << 8) | b; } }
/// <summary> /// Sets the color of the pixel including the alpha value and using a precalculated index (faster). /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="index">The coordinate index.</param> /// <param name="a">The alpha value of the color.</param> /// <param name="r">The red value of the color.</param> /// <param name="g">The green value of the color.</param> /// <param name="b">The blue value of the color.</param> public static void SetPixeli(this BitmapBuffer bmp, int index, byte a, byte r, byte g, byte b) { using (BitmapContext context = bmp.GetBitmapContext()) { context.Pixels[index] = (a << 24) | (r << 16) | (g << 8) | b; } }
/// <summary> /// Sets the color of the pixel using an extra alpha value. /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x">The x coordinate (row).</param> /// <param name="y">The y coordinate (column).</param> /// <param name="a">The alpha value of the color.</param> /// <param name="color">The color.</param> public static void SetPixel(this BitmapBuffer bmp, int x, int y, byte a, ColorInt color) { using (BitmapContext context = bmp.GetBitmapContext()) { // Add one to use mul and cheap bit shift for multiplicaltion context.Pixels[y * context.Width + x] = color.ToPreMultAlphaColor(); } }
/// <summary> /// Copies color information from an ARGB byte array into this WriteableBitmap starting at a specific buffer index. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="offset">The starting index in the buffer.</param> /// <param name="count">The number of bytes to copy from the buffer.</param> /// <param name="buffer">The color buffer as byte ARGB values.</param> /// <returns>The WriteableBitmap that was passed as parameter.</returns> public static BitmapBuffer FromByteArray(this BitmapBuffer bmp, byte[] buffer, int offset, int count) { using (BitmapContext context = bmp.GetBitmapContext()) { BitmapContext.BlockCopy(buffer, offset, context, 0, count); return(bmp); } }
private const byte TOP = 8; // 1000 /// <summary> /// Draws a line using a pen / stamp for the line /// </summary> /// <param name="bmp">The WriteableBitmap containing the pixels as int RGBA value.</param> /// <param name="w">The width of one scanline in the pixels array.</param> /// <param name="h">The height of the bitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="penBmp">The pen bitmap.</param> public static void DrawLinePenned(this BitmapBuffer bmp, int x1, int y1, int x2, int y2, BitmapBuffer penBmp, RectD?clipRect = null) { using (BitmapContext context = bmp.GetBitmapContext()) using (BitmapContext penContext = penBmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { DrawLinePenned(context, bmp.PixelWidth, bmp.PixelHeight, x1, y1, x2, y2, penContext, clipRect); } }
/// <summary> /// Draws a colored line by connecting two points using a DDA algorithm (Digital Differential Analyzer). /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color for the line.</param> /// <param name="clipRect">The region in the image to restrict drawing to.</param> public static unsafe void DrawLineDDA(this BitmapBuffer bmp, int x1, int y1, int x2, int y2, int color, RectD?clipRect = null) { using (BitmapContext context = bmp.GetBitmapContext()) { // Use refs for faster access (really important!) speeds up a lot! int w = context.Width; int h = context.Height; int *pixels = context.Pixels._inf32Buffer; // Get clip coordinates int clipX1 = 0; int clipX2 = w; int clipY1 = 0; int clipY2 = h; if (clipRect.HasValue) { RectD c = clipRect.Value; clipX1 = (int)c.X; clipX2 = (int)(c.X + c.Width); clipY1 = (int)c.Y; clipY2 = (int)(c.Y + c.Height); } // Distance start and end point int dx = x2 - x1; int dy = y2 - y1; // Determine slope (absolute value) int len = dy >= 0 ? dy : -dy; int lenx = dx >= 0 ? dx : -dx; if (lenx > len) { len = lenx; } // Prevent division by zero if (len != 0) { // Init steps and start float incx = dx / (float)len; float incy = dy / (float)len; float x = x1; float y = y1; // Walk the line! for (int i = 0; i < len; i++) { if (y < clipY2 && y >= clipY1 && x < clipX2 && x >= clipX1) { pixels[(int)y * w + (int)x] = color; } x += incx; y += incy; } } } }
/// <summary> /// Sets the color of the pixel using a precalculated index (faster). /// For best performance this method should not be used in iterative real-time scenarios. Implement the code directly inside a loop. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="index">The coordinate index.</param> /// <param name="r">The red value of the color.</param> /// <param name="g">The green value of the color.</param> /// <param name="b">The blue value of the color.</param> public static void SetPixeli(this BitmapBuffer bmp, int index, byte r, byte g, byte b) { using (BitmapContext context = bmp.GetBitmapContext()) { unsafe { context.Pixels._inf32Buffer[index] = (255 << 24) | (r << 16) | (g << 8) | b; } } }
/// <summary> /// Clones the specified WriteableBitmap. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <returns>A copy of the WriteableBitmap.</returns> public static BitmapBuffer Clone(this BitmapBuffer bmp) { using (BitmapContext srcContext = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { BitmapBuffer result = BitmapBufferFactory.New(srcContext.Width, srcContext.Height); using (var destContext = result.GetBitmapContext()) { BitmapContext.BlockCopy(srcContext, 0, destContext, 0, srcContext.Length * ARGB_SIZE); } return(result); } }
/// <summary> /// Draws a cubic Beziér spline defined by start, end and two control points. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x1">The x-coordinate of the start point.</param> /// <param name="y1">The y-coordinate of the start point.</param> /// <param name="cx1">The x-coordinate of the 1st control point.</param> /// <param name="cy1">The y-coordinate of the 1st control point.</param> /// <param name="cx2">The x-coordinate of the 2nd control point.</param> /// <param name="cy2">The y-coordinate of the 2nd control point.</param> /// <param name="x2">The x-coordinate of the end point.</param> /// <param name="y2">The y-coordinate of the end point.</param> /// <param name="color">The color.</param> public static void DrawBezier(this BitmapBuffer bmp, int x1, int y1, int cx1, int cy1, int cx2, int cy2, int x2, int y2, int color) { // Determine distances between controls points (bounding rect) to find the optimal stepsize int minX = Math.Min(x1, Math.Min(cx1, Math.Min(cx2, x2))); int minY = Math.Min(y1, Math.Min(cy1, Math.Min(cy2, y2))); int maxX = Math.Max(x1, Math.Max(cx1, Math.Max(cx2, x2))); int maxY = Math.Max(y1, Math.Max(cy1, Math.Max(cy2, y2))); // Get slope int lenx = maxX - minX; int len = maxY - minY; if (lenx > len) { len = lenx; } // Prevent division by zero if (len != 0) { using (BitmapContext context = bmp.GetBitmapContext()) { // Use refs for faster access (really important!) speeds up a lot! int w = context.Width; int h = context.Height; // Init vars float step = STEP_FACTOR / len; int tx1 = x1; int ty1 = y1; int tx2, ty2; // Interpolate for (float t = step; t <= 1; t += step) { float tSq = t * t; float t1 = 1 - t; float t1Sq = t1 * t1; tx2 = (int)(t1 * t1Sq * x1 + 3 * t * t1Sq * cx1 + 3 * t1 * tSq * cx2 + t * tSq * x2); ty2 = (int)(t1 * t1Sq * y1 + 3 * t * t1Sq * cy1 + 3 * t1 * tSq * cy2 + t * tSq * y2); // Draw line DrawLine(context, w, h, tx1, ty1, tx2, ty2, color); tx1 = tx2; ty1 = ty2; } // Prevent rounding gap DrawLine(context, w, h, tx1, ty1, x2, y2, color); } } }
/// <summary> /// Creates a new resized WriteableBitmap. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="width">The new desired width.</param> /// <param name="height">The new desired height.</param> /// <param name="interpolation">The interpolation method that should be used.</param> /// <returns>A new WriteableBitmap that is a resized version of the input.</returns> public static BitmapBuffer Resize(this BitmapBuffer bmp, int width, int height, Interpolation interpolation) { using (BitmapContext srcContext = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { int[] pd = Resize(srcContext, srcContext.Width, srcContext.Height, width, height, interpolation); BitmapBuffer result = BitmapBufferFactory.New(width, height); using (BitmapContext dstContext = result.GetBitmapContext()) { BitmapContext.BlockCopy(pd, 0, dstContext, 0, ARGB_SIZE * pd.Length); } return(result); } }
/// <summary> /// Gets the brightness / luminance of the pixel at the x, y coordinate as byte. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x">The x coordinate of the pixel.</param> /// <param name="y">The y coordinate of the pixel.</param> /// <returns>The brightness of the pixel at x, y.</returns> public static byte GetBrightness(this BitmapBuffer bmp, int x, int y) { using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { // Extract color components int c = context.Pixels[y * context.Width + x]; byte r = (byte)(c >> 16); byte g = (byte)(c >> 8); byte b = (byte)(c); // Convert to gray with constant factors 0.2126, 0.7152, 0.0722 return((byte)((r * 6966 + g * 23436 + b * 2366) >> 15)); } }
/// <summary> /// Creates a new WriteableBitmap which is contrast adjusted version of this one and returns it. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="level">Level of contrast as double. [-255.0, 255.0] </param> /// <returns>The new WriteableBitmap.</returns> public static BitmapBuffer AdjustContrast(this BitmapBuffer bmp, double level) { int factor = (int)((259.0 * (level + 255.0)) / (255.0 * (259.0 - level)) * 255.0); using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { int nWidth = context.Width; int nHeight = context.Height; unsafe { NativeInt32Arr px1 = context.Pixels; int * px = px1._inf32Buffer; BitmapBuffer result = BitmapBufferFactory.New(nWidth, nHeight); using (BitmapContext dest = result.GetBitmapContext()) { NativeInt32Arr rp1 = dest.Pixels; int * rp = rp1._inf32Buffer; int len = context.Length; for (int i = 0; i < len; i++) { // Extract int c = px[i]; int a = (c >> 24) & 0xff; int r = (c >> 16) & 0xff; int g = (c >> 8) & 0xff; int b = (c) & 0xff; // Adjust contrast based on computed factor //TODO: create lookup table for this r = ((factor * (r - 128)) >> 8) + 128; g = ((factor * (g - 128)) >> 8) + 128; b = ((factor * (b - 128)) >> 8) + 128; // Clamp r = r < 0 ? 0 : r > 255 ? 255 : r; g = g < 0 ? 0 : g > 255 ? 255 : g; b = b < 0 ? 0 : b > 255 ? 255 : b; // Set rp[i] = (a << 24) | (r << 16) | (g << 8) | b; } } return(result); } } }
/// <summary> /// Copies the Pixels from the WriteableBitmap into a ARGB byte array starting at a specific Pixels index. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="offset">The starting Pixels index.</param> /// <param name="count">The number of Pixels to copy, -1 for all</param> /// <returns>The color buffer as byte ARGB values.</returns> public static byte[] ToByteArray(this BitmapBuffer bmp, int offset, int count) { using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { if (count == -1) { // Copy all to byte array count = context.Length; } int len = count * ARGB_SIZE; byte[] result = new byte[len]; // ARGB BitmapContext.BlockCopy(context, offset, result, 0, len); return(result); } }
/// <summary> /// Creates a new cropped WriteableBitmap. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="x">The x coordinate of the rectangle that defines the crop region.</param> /// <param name="y">The y coordinate of the rectangle that defines the crop region.</param> /// <param name="width">The width of the rectangle that defines the crop region.</param> /// <param name="height">The height of the rectangle that defines the crop region.</param> /// <returns>A new WriteableBitmap that is a cropped version of the input.</returns> public static BitmapBuffer Crop(this BitmapBuffer bmp, int x, int y, int width, int height) { using (BitmapContext srcContext = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { int srcWidth = srcContext.Width; int srcHeight = srcContext.Height; // If the rectangle is completely out of the bitmap if (x > srcWidth || y > srcHeight) { return(BitmapBufferFactory.New(0, 0)); } // Clamp to boundaries if (x < 0) { x = 0; } if (x + width > srcWidth) { width = srcWidth - x; } if (y < 0) { y = 0; } if (y + height > srcHeight) { height = srcHeight - y; } // Copy the pixels line by line using fast BlockCopy BitmapBuffer result = BitmapBufferFactory.New(width, height); using (BitmapContext destContext = result.GetBitmapContext()) { for (int line = 0; line < height; line++) { int srcOff = ((y + line) * srcWidth + x) * ARGB_SIZE; int dstOff = line * width * ARGB_SIZE; BitmapContext.BlockCopy(srcContext, srcOff, destContext, dstOff, width * ARGB_SIZE); } return(result); } } }
/// <summary> /// Creates a new WriteableBitmap which is gamma adjusted version of this one and returns it. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="value">Value of gamma for adjustment. Original is 1.0.</param> /// <returns>The new WriteableBitmap.</returns> public static unsafe BitmapBuffer AdjustGamma(this BitmapBuffer bmp, double value) { using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { int nWidth = context.Width; int nHeight = context.Height; int * srcPixels = context.Pixels._inf32Buffer; BitmapBuffer result = BitmapBufferFactory.New(nWidth, nHeight); using (BitmapContext dest = result.GetBitmapContext()) { int *rp = dest.Pixels._inf32Buffer; var gammaCorrection = 1.0 / value; int len = context.Length; for (int i = 0; i < len; i++) { // Extract int c = srcPixels[i]; int a = (c >> 24) & 0xff; int r = (c >> 16) & 0xff; int g = (c >> 8) & 0xff; int b = (c) & 0xff; //Gamma adjustment //TODO: create gamma-lookup table for this *** r = (int)(255.0 * Math.Pow((r / 255.0), gammaCorrection)); g = (int)(255.0 * Math.Pow((g / 255.0), gammaCorrection)); b = (int)(255.0 * Math.Pow((b / 255.0), gammaCorrection)); // Clamps r = r < 0 ? 0 : r > 255 ? 255 : r; g = g < 0 ? 0 : g > 255 ? 255 : g; b = b < 0 ? 0 : b > 255 ? 255 : b; // Set rp[i] = (a << 24) | (r << 16) | (g << 8) | b; } } return(result); } }
/// <summary> /// Creates a new WriteableBitmap which is brightness adjusted version of this one and returns it. /// </summary> /// <param name="bmp">The WriteableBitmap.</param> /// <param name="nLevel">Level of contrast as double. [-255.0, 255.0] </param> /// <returns>The new WriteableBitmap.</returns> public static unsafe BitmapBuffer AdjustBrightness(this BitmapBuffer bmp, int nLevel) { using (BitmapContext context = bmp.GetBitmapContext(ReadWriteMode.ReadOnly)) { int nWidth = context.Width; int nHeight = context.Height; int * px = context.Pixels._inf32Buffer; BitmapBuffer result = BitmapBufferFactory.New(nWidth, nHeight); using (BitmapContext dest = result.GetBitmapContext()) { int *rp = dest.Pixels._inf32Buffer; int len = context.Length; for (int i = 0; i < len; i++) { // Extract int c = px[i]; int a = (c >> 24) & 0xff; int r = (c >> 16) & 0xff; int g = (c >> 8) & 0xff; int b = (c) & 0xff; // Brightness adjustment //TODO: create lookup table for this r += nLevel; g += nLevel; b += nLevel; // Clamp r = r < 0 ? 0 : r > 255 ? 255 : r; g = g < 0 ? 0 : g > 255 ? 255 : g; b = b < 0 ? 0 : b > 255 ? 255 : b; // Set rp[i] = (a << 24) | (r << 16) | (g << 8) | b; } } return(result); } }