jspaint/src/image-manipulation.js

237 lines
5.4 KiB
JavaScript
Raw Normal View History

function draw_ellipse(ctx, x, y, w, h, stroke, fill){
var stroke_color = ctx.strokeStyle;
var fill_color = ctx.fillStyle;
var r1 = Math.round;
var r2 = Math.round;
var cx = x + w/2;
var cy = y + h/2;
if(aliasing){
ctx.fillStyle = stroke_color;
for(var r=0; r<TAU; r+=0.01){
var rx = Math.cos(r) * w/2;
var ry = Math.sin(r) * h/2;
var rect_x = r1(cx+rx);
var rect_y = r1(cy+ry);
var rect_w = r2(-rx*2);
var rect_h = r2(-ry*2);
ctx.fillRect(rect_x+1, rect_y, rect_w, rect_h);
ctx.fillRect(rect_x, rect_y+1, rect_w, rect_h);
ctx.fillRect(rect_x-1, rect_y, rect_w, rect_h);
ctx.fillRect(rect_x, rect_y-1, rect_w, rect_h);
}
ctx.fillStyle = fill_color;
for(var r=0; r<TAU; r+=0.01){
var rx = Math.cos(r) * w/2;
var ry = Math.sin(r) * h/2;
ctx.fillRect(
r1(cx+rx),
r1(cy+ry),
r2(-rx*2),
r2(-ry*2)
);
}
}else{
if(w<0){ x+=w; w=-w; }
if(h<0){ y+=h; h=-h; }
ctx.beginPath();
ctx.ellipse(cx, cy, w/2, h/2, 0, TAU, false);
ctx.stroke();
ctx.fill();
}
}
function draw_rounded_rectangle(ctx, x, y, width, height, radius){
var stroke_color = ctx.strokeStyle;
var fill_color = ctx.fillStyle;
if(aliasing){
var iw = width - radius*2;
var ih = height - radius*2;
var ix = x+radius;
var iy = y+radius;
var r1 = Math.round;
var r2 = Math.round;
ctx.fillStyle = stroke_color;
for(var r=0; r<TAU; r+=0.05){
var rx = Math.cos(r) * radius;
var ry = Math.sin(r) * radius;
var rect_x = r1(ix+rx);
var rect_y = r1(iy+ry);
var rect_w = r2(iw-rx*2);
var rect_h = r2(ih-ry*2);
ctx.fillRect(rect_x+1, rect_y, rect_w, rect_h);
ctx.fillRect(rect_x, rect_y+1, rect_w, rect_h);
ctx.fillRect(rect_x-1, rect_y, rect_w, rect_h);
ctx.fillRect(rect_x, rect_y-1, rect_w, rect_h);
}
ctx.fillStyle = fill_color;
for(var r=0; r<TAU; r+=0.05){
var rx = Math.cos(r) * radius;
var ry = Math.sin(r) * radius;
ctx.fillRect(
r1(ix+rx),
r1(iy+ry),
r2(iw-rx*2),
r2(ih-ry*2)
);
}
}else{
ctx.beginPath();
ctx.moveTo(x + radius, y);
ctx.lineTo(x + width - radius, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
ctx.lineTo(x + width, y + height - radius);
ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
ctx.lineTo(x + radius, y + height);
ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
ctx.lineTo(x, y + radius);
ctx.quadraticCurveTo(x, y, x + radius, y);
ctx.closePath();
ctx.stroke();
ctx.fill();
}
}
function draw_line(ctx, x1, y1, x2, y2){
if(aliasing){
2014-08-11 20:45:55 +00:00
bresenham_line(x1, y1, x2, y2, function(x, y){
ctx.fillRect(x, y, 1, 1);
});
}else{
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
2014-08-10 15:09:56 +00:00
ctx.lineCap = "round";
ctx.stroke();
2014-08-08 21:44:46 +00:00
ctx.lineCap = "butt";
}
}
2014-08-11 20:45:55 +00:00
function bresenham_line(x1, y1, x2, y2, callback){
// Bresenham's line algorithm
x1=~~x1, x2=~~x2, y1=~~y1, y2=~~y2;
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var sx = (x1 < x2) ? 1 : -1;
var sy = (y1 < y2) ? 1 : -1;
var err = dx - dy;
while(1){
callback(x1, y1);
if(x1===x2 && y1===y2) break;
var e2 = err*2;
if(e2 >-dy){ err -= dy; x1 += sx; }
if(e2 < dx){ err += dx; y1 += sy; }
}
}
2014-08-11 20:45:55 +00:00
function brosandham_line(x1, y1, x2, y2, callback){
2014-05-15 17:14:23 +00:00
// Bresenham's line algorithm modified to callback in-between going horizontal and vertical
x1=~~x1, x2=~~x2, y1=~~y1, y2=~~y2;
var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var sx = (x1 < x2) ? 1 : -1;
var sy = (y1 < y2) ? 1 : -1;
var err = dx - dy;
while(1){
callback(x1, y1);
if(x1===x2 && y1===y2) break;
var e2 = err*2;
if(e2 >-dy){ err -= dy; x1 += sx; }
callback(x1, y1);
if(e2 < dx){ err += dx; y1 += sy; }
}
}
2014-10-01 19:46:35 +00:00
function draw_fill(ctx, x, y, fill_r, fill_g, fill_b, fill_a){
var stack = [[x, y]];
var c_width = canvas.width;
var c_height = canvas.height;
var id = ctx.getImageData(0, 0, c_width, c_height);
pixel_pos = (y*c_width + x) * 4;
var start_r = id.data[pixel_pos+0];
var start_g = id.data[pixel_pos+1];
var start_b = id.data[pixel_pos+2];
var start_a = id.data[pixel_pos+3];
if(
fill_r === start_r &&
fill_g === start_g &&
fill_b === start_b &&
fill_a === start_a
){
return;
}
while(stack.length){
var new_pos, x, y, pixel_pos, reach_left, reach_right;
new_pos = stack.pop();
x = new_pos[0];
y = new_pos[1];
pixel_pos = (y*c_width + x) * 4;
while(match_start_color(pixel_pos)){
pixel_pos -= c_width * 4, y--;
}
pixel_pos += c_width * 4, y++;
reach_left = false;
reach_right = false;
while(y++ < c_height && match_start_color(pixel_pos)){
color_pixel(pixel_pos);
if(x > 0){
if(match_start_color(pixel_pos - 4)){
if(!reach_left){
stack.push([x - 1, y]);
reach_left = true;
}
}else if(reach_left){
reach_left = false;
}
}
if(x < c_width-1){
if(match_start_color(pixel_pos + 4)){
if(!reach_right){
stack.push([x + 1, y]);
reach_right = true;
}
}else if(reach_right){
reach_right = false;
}
}
pixel_pos += c_width * 4;
}
}
ctx.putImageData(id, 0, 0);
function match_start_color(pixel_pos){
return (
id.data[pixel_pos+0] === start_r &&
id.data[pixel_pos+1] === start_g &&
id.data[pixel_pos+2] === start_b &&
id.data[pixel_pos+3] === start_a
);
}
function color_pixel(pixel_pos){
id.data[pixel_pos+0] = fill_r;
id.data[pixel_pos+1] = fill_g;
id.data[pixel_pos+2] = fill_b;
id.data[pixel_pos+3] = fill_a;
}
}