Explore the world of free coloring images and discover their therapeutic benefits for all ages. From intricate mandalas and floral designs to whimsical illustrations, coloring provides a unique outlet for creative expression and relaxation. Engage in this enjoyable activity, known to promote mindfulness, reduce stress, and enhance focus. With a variety of designs available for both beginners and advanced colorists, there’s something to suit everyone’s preferences. Learn about the different types of coloring images, tips for selecting the right line thickness, and how to optimize your printing settings for the best results. Embrace the art of coloring and enrich your life with creativity and joy.
Free Coloring Images
Pattern Type Mandala
Flower
Butterfly
Geometric
Zentangle
Cute Objects
Generate New Image
📥 Download Image Your coloring image is ready. Tap the button below to save it to your device.
Save Image
Cancel
`);
doc.close();
this.showToast('Opening PDF print dialog...');
}// ... (all drawing methods remain the same)
drawMandala(cx, cy, r, lw) {
const ctx = this.ctx;
const c = this.settings.complexity;
const petals = 6 + Math.floor(c * 1.5);
const layers = 2 + Math.floor(c / 2);ctx.lineWidth = lw * 1.5;
ctx.beginPath();
ctx.arc(cx, cy, r + lw*2, 0, Math.PI * 2);
ctx.stroke();
ctx.lineWidth = lw;for (let l = 0; l < layers; l++) {
const layerR = r - (l * (r / layers));
const innerR = layerR * 0.4;
for (let i = 0; i < petals; i++) {
const angle = (i / petals) * Math.PI * 2 - Math.PI / 2;
const nextAngle = ((i + 1) / petals) * Math.PI * 2 - Math.PI / 2;
const midAngle = angle + (nextAngle - angle) / 2;ctx.beginPath();
ctx.moveTo(cx + Math.cos(angle) * innerR, cy + Math.sin(angle) * innerR);
ctx.quadraticCurveTo(
cx + Math.cos(midAngle) * (layerR * 1.1),
cy + Math.sin(midAngle) * (layerR * 1.1),
cx + Math.cos(nextAngle) * innerR,
cy + Math.sin(nextAngle) * innerR
);
ctx.stroke();if (c > 4 && l % 2 === 0) {
ctx.beginPath();
ctx.arc(
cx + Math.cos(midAngle) * (layerR * 0.7),
cy + Math.sin(midAngle) * (layerR * 0.7),
layerR * 0.1, 0, Math.PI * 2
);
ctx.stroke();
}
}ctx.beginPath();
ctx.arc(cx, cy, layerR, 0, Math.PI * 2);
ctx.stroke();
if(c > 2) {
for(let i=0; i
6);
}
}ctx.beginPath();
ctx.arc(cx, cy, r*0.12, 0, Math.PI*2);
ctx.stroke();
if(c > 3) {
for(let i=0; i<5; i++) {
const angle = (i/5)*Math.PI*2;
ctx.beginPath();
ctx.arc(cx+Math.cos(angle)*r*0.06, cy+Math.sin(angle)*r*0.06, lw, 0, Math.PI*2);
ctx.fill();
}
}
}drawPetal(cx, cy, angle, length, width, lw, addVein) {
const ctx = this.ctx;
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(angle);ctx.beginPath();
ctx.moveTo(0, 0);
ctx.bezierCurveTo(width, -length*0.3, width, -length*0.7, 0, -length);
ctx.bezierCurveTo(-width, -length*0.7, -width, -length*0.3, 0, 0);
ctx.stroke();if(addVein) {
ctx.beginPath();
ctx.moveTo(0, -length*0.1);
ctx.lineTo(0, -length*0.9);
ctx.stroke();
}ctx.restore();
}drawLeaf(cx, cy, angle, size, lw) {
const ctx = this.ctx;
ctx.save();
ctx.translate(cx, cy);
ctx.rotate(angle);ctx.beginPath();
ctx.moveTo(0, 0);
ctx.bezierCurveTo(size*0.5, -size*0.2, size*0.8, -size*0.1, size, 0);
ctx.bezierCurveTo(size*0.8, size*0.1, size*0.5, size*0.2, 0, 0);
ctx.stroke();ctx.beginPath();
ctx.moveTo(size*0.1, 0);
ctx.lineTo(size*0.8, 0);
ctx.stroke();ctx.restore();
}drawButterfly(cx, cy, r, lw) {
const ctx = this.ctx;
const c = this.settings.complexity;
const wingSpan = r * 1.2;
const wingH = r * 0.9;const wings = [
{ xOff: -wingSpan*0.4, yOff: -wingH*0.3, w: wingSpan*0.6, h: wingH*0.8 },
{ xOff: wingSpan*0.4, yOff: -wingH*0.3, w: wingSpan*0.6, h: wingH*0.8 },
{ xOff: -wingSpan*0.25, yOff: wingH*0.2, w: wingSpan*0.4, h: wingH*0.5 },
{ xOff: wingSpan*0.25, yOff: wingH*0.2, w: wingSpan*0.4, h: wingH*0.5 }
];wings.forEach(wing => {
const isRight = wing.xOff > 0;
const dir = isRight ? 1 : -1;
const sx = cx + wing.xOff;
const sy = cy + wing.yOff;ctx.beginPath();
ctx.moveTo(sx, sy);
ctx.bezierCurveTo(
sx + wing.w * 0.5 * dir, sy - wing.h * 0.8,
sx + wing.w * 1.2 * dir, sy - wing.h * 0.5,
sx + wing.w * dir, sy + wing.h * 0.2
);
ctx.bezierCurveTo(
sx + wing.w * 0.8 * dir, sy + wing.h * 0.8,
sx + wing.w * 0.2 * dir, sy + wing.h * 0.6,
sx, sy
);
ctx.stroke();if(c > 2) {
ctx.beginPath();
ctx.moveTo(sx, sy);
ctx.bezierCurveTo(
sx + wing.w*0.3*dir, sy - wing.h*0.5,
sx + wing.w*0.7*dir, sy - wing.h*0.3,
sx + wing.w*0.6*dir, sy + wing.h*0.1
);
ctx.bezierCurveTo(
sx + wing.w*0.4*dir, sy + wing.h*0.4,
sx + wing.w*0.1*dir, sy + wing.h*0.3,
sx, sy
);
ctx.stroke();
}
if(c > 6) {
for(let i=0; i<3; i++) {
const spotX = sx + wing.w*(0.3 + i*0.2)*dir;
const spotY = sy - wingH*0.1 + (i*wingH*0.15);
ctx.beginPath();
ctx.arc(spotX, spotY, wing.w*0.08, 0, Math.PI*2);
ctx.stroke();
}
}
});ctx.beginPath();
ctx.ellipse(cx, cy, r*0.04, r*0.4, 0, 0, Math.PI*2);
ctx.fill();ctx.beginPath();
ctx.moveTo(cx - r*0.02, cy - r*0.35);
ctx.bezierCurveTo(cx - r*0.2, cy - r*0.8, cx - r*0.4, cy - r*0.9, cx - r*0.35, cy - r*0.95);
ctx.stroke();
ctx.beginPath();
ctx.arc(cx - r*0.35, cy - r*0.95, r*0.03, 0, Math.PI*2);
ctx.fill();ctx.beginPath();
ctx.moveTo(cx + r*0.02, cy - r*0.35);
ctx.bezierCurveTo(cx + r*0.2, cy - r*0.8, cx + r*0.4, cy - r*0.9, cx + r*0.35, cy - r*0.95);
ctx.stroke();
ctx.beginPath();
ctx.arc(cx + r*0.35, cy - r*0.95, r*0.03, 0, Math.PI*2);
ctx.fill();
}drawGeometric(cx, cy, r, lw) {
const ctx = this.ctx;
const c = this.settings.complexity;
const shapes = 3 + Math.floor(c / 2);for(let s=0; s 3) {
const nextR = currentR * 0.6;
for(let i=0; i 6) {
this.drawPolygon(cx, cy, currentR*0.3, sides, -rotation, lw*0.8);
}
}this.drawPolygon(cx, cy, r + lw*2, shapes, 0, lw*1.5);
}drawPolygon(cx, cy, r, sides, rotation, lw) {
const ctx = this.ctx;
ctx.lineWidth = lw;
ctx.beginPath();
for(let i=0; i<=sides; i++) {
const angle = rotation + (i / sides) * Math.PI * 2;
const x = cx + Math.cos(angle) * r;
const y = cy + Math.sin(angle) * r;
if(i===0) ctx.moveTo(x, y);
else ctx.lineTo(x, y);
}
ctx.stroke();
}drawZentangle(cx, cy, r, lw) {
const ctx = this.ctx;
const c = this.settings.complexity;
const strings = 2 + Math.floor(c/3);
const paths = [];
for(let s=0; s {
ctx.beginPath();
ctx.moveTo(path[0].x, path[0].y);
for(let i=1; i r * 0.95) continue;const tangle = tangleTypes[Math.floor(Math.random()*tangleTypes.length)];
ctx.save();
ctx.translate(gx, gy);
ctx.rotate(Math.random() * Math.PI * 2);
this.drawTangle(tangle, gridSize * 0.4, lw * 0.8, c);
ctx.restore();
}
}ctx.lineWidth = lw * 2;
ctx.beginPath();
ctx.arc(cx, cy, r, 0, Math.PI * 2);
ctx.stroke();
}drawTangle(type, size, lw, complexity) {
const ctx = this.ctx;
ctx.lineWidth = lw;
const s = Math.max(10, size);switch(type) {
case 'dots':
for(let i=0; i<4; i++) {
ctx.beginPath();
ctx.arc((Math.random()-0.5)*s, (Math.random()-0.5)*s, lw*1.5, 0, Math.PI*2);
ctx.fill();
}
break;
case 'hatching':
for(let i=-2; i<=2; i++) {
ctx.beginPath();
ctx.moveTo(i*s*0.3, -s*0.5);
ctx.lineTo(i*s*0.3, s*0.5);
ctx.stroke();
}
break;
case 'circles':
ctx.beginPath();
ctx.arc(0, 0, s*0.4, 0, Math.PI*2);
ctx.stroke();
if(complexity > 5) {
ctx.beginPath();
ctx.arc(0, 0, s*0.2, 0, Math.PI*2);
ctx.stroke();
}
break;
case 'waves':
ctx.beginPath();
for(let x=-s*0.5; x<=s*0.5; x+=2) {
ctx.lineTo(x, Math.sin(x*0.2)*s*0.2);
}
ctx.stroke();
if(complexity > 4) {
ctx.beginPath();
for(let x=-s*0.5; x<=s*0.5; x+=2) {
ctx.lineTo(x, Math.sin(x*0.2)*s*0.2 + s*0.3);
}
ctx.stroke();
}
break;
}
}drawCuteObjects(cx, cy, r, lw) {
const ctx = this.ctx;
const c = this.settings.complexity;
const s = r * 0.8;ctx.beginPath();
ctx.arc(cx, cy - s*0.2, s*0.5, 0, Math.PI*2);
ctx.stroke();ctx.beginPath();
ctx.moveTo(cx - s*0.35, cy - s*0.55);
ctx.lineTo(cx - s*0.5, cy - s*0.9);
ctx.lineTo(cx - s*0.1, cy - s*0.65);
ctx.stroke();ctx.beginPath();
ctx.moveTo(cx + s*0.35, cy - s*0.55);
ctx.lineTo(cx + s*0.5, cy - s*0.9);
ctx.lineTo(cx + s*0.1, cy - s*0.65);
ctx.stroke();if(c > 3) {
ctx.beginPath();
ctx.moveTo(cx - s*0.3, cy - s*0.58);
ctx.lineTo(cx - s*0.42, cy - s*0.82);
ctx.lineTo(cx - s*0.15, cy - s*0.65);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cx + s*0.3, cy - s*0.58);
ctx.lineTo(cx + s*0.42, cy - s*0.82);
ctx.lineTo(cx + s*0.15, cy - s*0.65);
ctx.stroke();
}ctx.beginPath();
ctx.arc(cx - s*0.18, cy - s*0.25, s*0.08, 0, Math.PI*2);
ctx.fill();
ctx.beginPath();
ctx.arc(cx + s*0.18, cy - s*0.25, s*0.08, 0, Math.PI*2);
ctx.fill();ctx.fillStyle = '#FFFFFF';
ctx.beginPath();
ctx.arc(cx - s*0.15, cy - s*0.28, s*0.025, 0, Math.PI*2);
ctx.fill();
ctx.beginPath();
ctx.arc(cx + s*0.21, cy - s*0.28, s*0.025, 0, Math.PI*2);
ctx.fill();
ctx.fillStyle = '#000000';ctx.beginPath();
ctx.moveTo(cx, cy - s*0.1);
ctx.lineTo(cx - s*0.04, cy - s*0.06);
ctx.lineTo(cx + s*0.04, cy - s*0.06);
ctx.closePath();
ctx.fill();ctx.beginPath();
ctx.moveTo(cx, cy - s*0.06);
ctx.quadraticCurveTo(cx - s*0.1, cy + s*0.05, cx - s*0.15, cy - s*0.02);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cx, cy - s*0.06);
ctx.quadraticCurveTo(cx + s*0.1, cy + s*0.05, cx + s*0.15, cy - s*0.02);
ctx.stroke();const whiskerY = cy - s*0.05;
for(let i=0; i<3; i++) {
const angle = (i - 1) * 0.2;
ctx.beginPath();
ctx.moveTo(cx - s*0.15, whiskerY);
ctx.lineTo(cx - s*0.6, whiskerY + Math.sin(angle)*s*0.3);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(cx + s*0.15, whiskerY);
ctx.lineTo(cx + s*0.6, whiskerY + Math.sin(angle)*s*0.3);
ctx.stroke();
}ctx.beginPath();
ctx.ellipse(cx, cy + s*0.5, s*0.35, s*0.4, 0, 0, Math.PI*2);
ctx.stroke();ctx.beginPath();
ctx.moveTo(cx + s*0.3, cy + s*0.7);
ctx.bezierCurveTo(cx + s*0.8, cy + s*0.5, cx + s*0.9, cy, cx + s*0.7, cy - s*0.2);
ctx.stroke();if(c > 5) {
for(let i=0; i<3; i++) {
ctx.beginPath();
ctx.moveTo(cx - s*0.15 + i*s*0.15, cy + s*0.2);
ctx.lineTo(cx - s*0.1 + i*s*0.15, cy + s*0.5);
ctx.stroke();
}
}ctx.beginPath();
ctx.ellipse(cx - s*0.2, cy + s*0.85, s*0.1, s*0.06, 0, 0, Math.PI*2);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(cx + s*0.2, cy + s*0.85, s*0.1, s*0.06, 0, 0, Math.PI*2);
ctx.stroke();ctx.beginPath();
ctx.moveTo(cx - s*0.6, cy + s*0.92);
ctx.quadraticCurveTo(cx, cy + s*0.98, cx + s*0.6, cy + s*0.92);
ctx.stroke();
}
}// Initialize app
document.addEventListener('DOMContentLoaded', () => {
new ColoringGenerator();
});