/// <summary> /// http://en.wikipedia.org/wiki/Alpha_compositing /// </summary> /// <param name="destination_rect"></param> /// <param name="source"></param> /// <param name="source_rect"></param> /// <param name="blendMode"></param> public void Blit( Rectangle destination_rect, IPixelCanvas source, Rectangle source_rect, BlendMode blendMode) { Blit(destination_rect, source, source_rect, 255, 255, 255, 255, blendMode); }
/// <summary> /// http://en.wikipedia.org/wiki/Alpha_compositing /// </summary> /// <param name="destination_rect"></param> /// <param name="source"></param> /// <param name="source_rect"></param> /// <param name="blendMode"></param> public void Blit( System.Drawing.Rectangle destination_rect, IPixelCanvas source, System.Drawing.Rectangle source_rect, BlendMode blendMode ) { Blit(destination_rect, source, source_rect, 255, 255, 255, 255, blendMode); }
public void DrawLineDDA(Rectangle bounds, int x1, int y1, int x2, int y2, IPixelCanvas pen, BlendMode blendMode = BlendMode.Copy) { var x1_d = (double)x1; var y1_d = (double)y1; var x2_d = (double)x2; var y2_d = (double)y2; if (!TryCohenSutherlandClip(bounds, ref x1_d, ref y1_d, ref x2_d, ref y2_d)) return; DrawLineDDA((int)x1_d, (int)y1_d, (int)x2_d, (int)y2_d, pen, blendMode); }
/// <summary> /// http://en.wikipedia.org/wiki/Alpha_compositing /// </summary> /// <param name="destination_rect"></param> /// <param name="source"></param> /// <param name="source_rect"></param> /// <param name="alpha"></param> /// <param name="red"></param> /// <param name="green"></param> /// <param name="blue"></param> /// <param name="blendMode"></param> public void Blit( System.Drawing.Rectangle destination_rect, IPixelCanvas source, System.Drawing.Rectangle source_rect, byte alpha, byte red, byte green, byte blue, BlendMode blendMode) { // http://keithp.com/~keithp/porterduff/p253-porter.pdf // http://en.wikipedia.org/wiki/Alpha_compositing // tint with transparent color, nothing to do here, since this would make every source pixel transparent if (alpha == 0) return; if (!IntersectsWith(destination_rect)) return; // tinted if color is not opaque white var is_tinted = alpha != 255 || red != 255 || green != 255 || blue != 255; var source_width = source.Width; var source_pixels = source; var source_length = source.Length; int source_rectangle_x = source_rect.X; int source_rectangle_y = source_rect.Y; var destination_width = Width; var destination_height = Height; var destination_pixels = this; var destination_length = Length; int destination_rectangle_x = destination_rect.X; int destination_rectangle_y = destination_rect.Y; int destination_rect_width = destination_rect.Width; int destination_rect_height = destination_rect.Height; int sourceIdx = -1; int idx; double ii; double jj; int source_pixel = 0; int source_alpha = 0; int source_red = 0; int source_green = 0; int source_blue = 0; int destination_alpha; int destination_red; int destination_green; int destination_blue; var source_rectangle_width = source_rect.Width; var sdx = source_rect.Width / destination_rect.Width; var sdy = source_rect.Height / destination_rect.Height; int lastii = -1; int lastjj = -1; jj = source_rectangle_y; int current_x; int current_y = destination_rectangle_y; // each row in destination rectangle for (int destination_rect_row = 0; destination_rect_row < destination_rect_height; destination_rect_row++) { // check if current y is within destination rectangle bounds (todo: >= 0? should it be destination_rect_y ?) if (current_y >= 0 && current_y < destination_height) { ii = source_rectangle_x; idx = destination_rectangle_x + current_y * destination_width; // start from left most column in destination rectangle current_x = destination_rectangle_x; // each column in destination rectangle for (int destination_rect_col = 0; destination_rect_col < destination_rect_width; destination_rect_col++) { // todo: >= 0? if (current_x >= 0 && current_x < destination_width) { if ((int)ii != lastii || (int)jj != lastjj) { sourceIdx = (int)ii + (int)jj * source_width; if (sourceIdx >= 0 && sourceIdx < source_length) { // retrieve current source pixel and it's channels values source_pixel = source_pixels[sourceIdx]; if (blendMode == BlendMode.Copy) { destination_pixels[idx] = source_pixel; current_x++; idx++; ii += sdx; continue; } if (source_pixel != 0) { source_alpha = ((source_pixel >> 24) & 0xff); source_red = ((source_pixel >> 16) & 0xff); source_green = ((source_pixel >> 8) & 0xff); source_blue = ((source_pixel) & 0xff); // tint the pixel if needed if (is_tinted && source_alpha != 0) { source_alpha = (((source_alpha * alpha) * 0x8081) >> 23); source_red = ((((((source_red * red) * 0x8081) >> 23) * alpha) * 0x8081) >> 23); source_green = ((((((source_green * green) * 0x8081) >> 23) * alpha) * 0x8081) >> 23); source_blue = ((((((source_blue * blue) * 0x8081) >> 23) * alpha) * 0x8081) >> 23); source_pixel = (source_alpha << 24) | (source_red << 16) | (source_green << 8) | source_blue; } } else { source_alpha = 0; } } else { source_alpha = 0; } } if (source_alpha == 0) { current_x++; idx++; ii += sdx; continue; } else { // get destination pixel int destPixel = destination_pixels[idx]; destination_alpha = ((destPixel >> 24) & 0xff); // destination is transparent or source is opaque, // just replace destination pixel with source pixel if (blendMode == BlendMode.Alpha && (source_alpha == 255 || destination_alpha == 0)) { destination_pixels[idx] = source_pixel; current_x++; idx++; ii += sdx; continue; } // get destination pixel rgb values destination_red = ((destPixel >> 16) & 0xff); destination_green = ((destPixel >> 8) & 0xff); destination_blue = ((destPixel) & 0xff); if (blendMode == BlendMode.Alpha) { var isa = 255 - source_alpha; destPixel = ((destination_alpha & 0xff) << 24) | (((((source_red << 8) + isa * destination_red) >> 8) & 0xff) << 16) | (((((source_green << 8) + isa * destination_green) >> 8) & 0xff) << 8) | ((((source_blue << 8) + isa * destination_blue) >> 8) & 0xff); } else throw new NotSupportedException(); destination_pixels[idx] = destPixel; } } current_x++; idx++; ii += sdx; } } jj += sdy; current_y++; } }
public void Blit(IPixelCanvas source, BlendMode blendMode) { Blit(this.Bounds, source, source.Bounds, blendMode); }
public void DrawLine(int x1, int y1, int x2, int y2, IPixelCanvas pen, BlendMode blendMode = BlendMode.Copy) { DrawLineDDA(x1, y1, x2, y2, pen); }
public void DrawLineDDA(int x1, int y1, int x2, int y2, IPixelCanvas pen, BlendMode blendMode = BlendMode.Copy) { if (pen.Bounds.IsEmpty) return; var pen_centre_x = pen.Width / 2; var pen_centre_y = pen.Height / 2; // http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm // cartesian slope-intercept http://en.wikipedia.org/wiki/Linear_equation#Slope.E2.80.93intercept_form // y = mx + b // m - slope of the line // b - y intercept (y coordinate of location where the line crosses the y axis) // write above equation as function of both x and y // slope is the "rise over run" or dx / dy // // y = mx + b // y = dy/dx * x + b // dx * y = dy * x + dx * b // 0 = dy*x - dx*y + dx*b // f(x,y) = 0 = Ax + By + C // where // A = dy // B = -dx // C = dx*b var dx = x2 - x1; var dy = y2 - y1; //# calculate number of steps as greather of max(abs(dx), abs(dy)) // use maximum possible number of steps for better accuracy // do not user Math class here for quicker execution var dx_abs = dx; if (dx_abs < 0) dx_abs = -dx; var dy_abs = dy; if (dy_abs < 0) dy_abs = -dy; // calculate x and y steps var x_step = 0.0f; var y_step = 0.0f; var steps = dx_abs; if (dx_abs < dy_abs) steps = dy_abs; x_step = dx / (float)steps; y_step = dy / (float)steps; if (steps == 0) return; // line start point var x = (float)x1; var y = (float)y1; //var dash_style = new bool[] { true, false, false }; //var dash_i = 0; for (int i = 0; i <= steps; i++) { if (y < _height && y >= 0 && x < _width && x >= 0) { //if (dash_style[dash_i]) { // blit pen at the centre var dest_rect = new Rectangle(x - pen_centre_x, y - pen_centre_y, pen.Width, pen.Height); Blit(dest_rect, pen, pen.Bounds, blendMode); } //dash_i = (dash_i + 1) % dash_style.Length; } x += x_step; y += y_step; } }
public static IPixelCanvas Blit(IPixelCanvas first, IPixelCanvas second, BlendMode blendMode) { var pc = new PixelArrayCanvas(first.Width, first.Height); pc.Blit(second, blendMode); return pc; }
public void Draw(IPixelCanvas pc, DrawingContext cx, CancellationToken ct) { DrawAction(pc, cx, ct); }
public void Draw(IPixelCanvas pc, CancellationToken ct) { DrawAction(pc, ct); }