I'm drawing an image onto a canvas and trying to apply red dashed outline of approximately 2px but end up with solid red outline. The source image is a .png image with top and bottom texts as part of the image as following example.
A Polar Bear with top and bottom text.
I am using following function to generate red outline:
import { saveAs } from 'file-saver';
export const genOutline = (
imgSrc
) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const refImage = new Image();
refImage.src = imgSrc;
refImage.style.width = "max-content";
refImage.style.height = "max-content";
refImage.onload = () => {
//define hight and width of the canvas
canvas.width = refImage.width + 30;
canvas.height = refImage.height + 30;
var dArr = [-1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, 1, 0, 1, 1, 1], // offset array
s = 2, // thickness scale
i = 0, // iterator
x = 5, // final position
y = 5;
// draw images at offsets from the array scaled by s
for (; i < dArr.length; i += 2) {
ctx.drawImage(refImage, x + dArr[i] * s, y + dArr[i + 1] * s);
}
// fill with color
ctx.globalCompositeOperation = "source-in";
ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.
// draw original image in normal mode
ctx.globalCompositeOperation = "source-over";
ctx.drawImage(refImage, x, y);
canvas.toBlob((blob) => {
console.log("blob", blob);
saveAs(blob, "image_outlined.png");
canvas.remove();
});
}
}
But I want to achieve something similar to what is in the following image:
A Girl portrait with top and bottom text and red dashed outline.
In your code I do not see you tried anything with dashes...
You can do dashes with setLineDash
here are two small examplea
class Shape {
constructor(x, y, width, height, color, dashes) {
this.color = color
this.dashes = dashes
this.path = new Path2D();
this.path.arc(x, y, height / 3, 0, Math.PI, true);
this.path.rect(x + width / 2, y, -width, height);
}
draw(ctx) {
ctx.beginPath();
ctx.setLineDash(this.dashes);
ctx.strokeStyle = this.color;
ctx.stroke(this.path);
}
}
var ctx = canvas.getContext("2d");
var shapes = [];
shapes.push(new Shape(30, 30, 50, 50, "blue", [3, 3]));
shapes.push(new Shape(95, 50, 40, 40, "red", [5, 5]));
shapes.forEach((s) => s.draw(ctx));
<canvas id="canvas" width="160" height="160"></canvas>
const ctx = canvas.getContext("2d");
ctx.setLineDash([10,5])
function drawSpiral(x, y, radiusChange, maxRadius) {
ctx.lineTo(x, y);
var a = 0, r = radiusChange;
while (r < maxRadius) {
a += 1 / r * Math.PI;
r = a * radiusChange;
ctx.lineTo(x + Math.cos(a) * r, y + Math.sin(a) * r);
}
ctx.stroke();
}
drawSpiral(80, 80, 4, 80);
<canvas id="canvas" width="160" height="160"></canvas>
The big problem is doing that around the picture outline.
Your solution for outline was to draw images at offsets, that won't do for dashes you really need to get a true outline then draw it with lines