You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(originalImg, styleIntensity = 1.8, colorBands = 5, actionLines = 180) {
// Parse arguments in case they are passed as strings
const intensity = parseFloat(styleIntensity) || 1.8;
const bands = parseInt(colorBands) || 5;
const linesCount = parseInt(actionLines) || 180;
// Create main canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = originalImg.width;
const height = canvas.height = originalImg.height;
// Draw the original image
ctx.drawImage(originalImg, 0, 0);
const imgData = ctx.getImageData(0, 0, width, height);
const data = imgData.data;
// Phase 1: Apply "Hiroki Major" Comic/Cel-Shaded Filter
// This boosts saturation/contrast heavily and posterizes the image for an anime style
for (let i = 0; i < data.length; i += 4) {
let r = data[i] / 255;
let g = data[i + 1] / 255;
let b = data[i + 2] / 255;
// Calculate relative luminance
let luma = 0.299 * r + 0.587 * g + 0.114 * b;
// Contrast boost
luma = ((luma - 0.5) * intensity) + 0.5;
// Saturation boost
r = luma + (r - luma) * intensity;
g = luma + (g - luma) * intensity;
b = luma + (b - luma) * intensity;
// Clamp values between 0 and 1
r = Math.max(0, Math.min(1, r));
g = Math.max(0, Math.min(1, g));
b = Math.max(0, Math.min(1, b));
// Posterize to reduce colors to discrete bands (cel-shading effect)
r = Math.round(r * bands) / bands;
g = Math.round(g * bands) / bands;
b = Math.round(b * bands) / bands;
data[i] = r * 255;
data[i + 1] = g * 255;
data[i + 2] = b * 255;
}
ctx.putImageData(imgData, 0, 0);
// Phase 2: Create a classic Manga Halftone (Screentone) overlay
const patternCanvas = document.createElement('canvas');
patternCanvas.width = 6;
patternCanvas.height = 6;
const pCtx = patternCanvas.getContext('2d');
pCtx.fillStyle = 'rgba(0, 0, 0, 0.25)';
pCtx.beginPath();
pCtx.arc(3, 3, 1.5, 0, Math.PI * 2);
pCtx.fill();
ctx.globalCompositeOperation = 'multiply';
const pattern = ctx.createPattern(patternCanvas, 'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, width, height);
ctx.globalCompositeOperation = 'source-over'; // Reset
// Phase 3: Draw Shounen "Action/Speed Lines" focusing on the center
// This gives the striking energetic pop-art feel typical of the genre
const centerX = width / 2;
const centerY = height / 2;
const maxRadius = Math.sqrt(centerX * centerX + centerY * centerY);
const clearRadius = Math.min(width, height) * 0.20; // Clear zone in the center
ctx.translate(centerX, centerY);
for (let i = 0; i < linesCount; i++) {
// Spread lines evenly, but add a slight jitter for organic feel
const angle = (i / linesCount) * Math.PI * 2 + (Math.random() * 0.04 - 0.02);
// Randomize inner starting radius for jagged edges
const rStart = clearRadius + (Math.random() * clearRadius);
const thickness = Math.random() * 3 + 1; // Random wedge thickness
ctx.save();
ctx.rotate(angle);
ctx.beginPath();
ctx.moveTo(rStart, 0);
// Create an elongated triangle shooting out from the center
ctx.lineTo(maxRadius, -thickness);
ctx.lineTo(maxRadius, thickness);
ctx.closePath();
// 80% black lines, 20% white lines to simulate high-contrast ink
ctx.fillStyle = Math.random() > 0.2 ? 'rgba(0, 0, 0, 0.9)' : 'rgba(255, 255, 255, 0.8)';
ctx.fill();
ctx.restore();
}
// Reset transform to return a clean canvas object
ctx.resetTransform();
return canvas;
}
Apply Changes