You can edit the below JavaScript code to customize the image tool.
async function processImage(
originalImg,
dotSize = 8, // Defines the grid cell size for dot placement. Integer.
dotSizeMultiplier = 1.0, // Scales the calculated dot radius. 1.0 means max radius is dotSize/2.
// Values > 1 can make dots overlap cells.
dotColorMode = 'average', // 'average' (use cell's average color), 'black', or a specific CSS color string (e.g., 'red', '#00FF00').
backgroundColor = 'white',// CSS color string for the canvas background.
desaturation = 0.0 // Desaturation level for the source image before processing. 0.0 (no change) to 1.0 (full grayscale).
) {
// Ensure originalImg is a loaded image with dimensions
const imgWidth = originalImg.naturalWidth || originalImg.width;
const imgHeight = originalImg.naturalHeight || originalImg.height;
if (imgWidth === 0 || imgHeight === 0) {
console.warn("Image Magazine Print Filter: Original image has zero width or height. Returning a 1x1 canvas.");
const emptyCanvas = document.createElement('canvas');
emptyCanvas.width = 1;
emptyCanvas.height = 1;
const emptyCtx = emptyCanvas.getContext('2d');
if (emptyCtx) {
emptyCtx.fillStyle = 'gray'; // Indicate issue
emptyCtx.fillRect(0, 0, 1, 1);
}
return emptyCanvas;
}
const outputCanvas = document.createElement('canvas');
// Use alpha: true for flexibility, e.g., if backgroundColor is 'transparent'
const ctx = outputCanvas.getContext('2d', { alpha: true });
outputCanvas.width = imgWidth;
outputCanvas.height = imgHeight;
// Validate and clamp parameters
dotSize = Math.max(1, Math.floor(dotSize));
dotSizeMultiplier = Math.max(0, dotSizeMultiplier); // Allow 0 to effectively remove dots
desaturation = Math.max(0.0, Math.min(1.0, desaturation)); // Clamp between 0 and 1
// Create a temporary canvas to hold the source image, possibly desaturated
const tempCanvas = document.createElement('canvas');
tempCanvas.width = imgWidth;
tempCanvas.height = imgHeight;
const tempCtx = tempCanvas.getContext('2d');
// Draw the original image onto the temporary canvas
tempCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
let sourcePixelData; // This will hold the Uint8ClampedArray of the source pixels
// Apply desaturation if specified
if (desaturation > 0) {
const imageDataObj = tempCtx.getImageData(0, 0, imgWidth, imgHeight);
const data = imageDataObj.data;
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Standard luminance calculation
const gray = 0.299 * r + 0.587 * g + 0.114 * b;
// Interpolate between original color and gray
data[i] = Math.round(r * (1 - desaturation) + gray * desaturation);
data[i + 1] = Math.round(g * (1 - desaturation) + gray * desaturation);
data[i + 2] = Math.round(b * (1 - desaturation) + gray * desaturation);
// Alpha channel (data[i + 3]) remains unchanged
}
// Put the modified (desaturated) image data back onto the temporary canvas
tempCtx.putImageData(imageDataObj, 0, 0);
}
// Get the pixel data from the temporary canvas (will be original or desaturated)
sourcePixelData = tempCtx.getImageData(0, 0, imgWidth, imgHeight).data;
// Fill the output canvas with the specified background color
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, imgWidth, imgHeight);
// Calculate the base radius for dots within a cell (if multiplier is 1.0)
const baseCellRadius = (dotSize / 2.0);
// Iterate over the image in blocks of dotSize x dotSize
for (let y = 0; y < imgHeight; y += dotSize) {
for (let x = 0; x < imgWidth; x += dotSize) {
let sumR = 0, sumG = 0, sumB = 0;
let pixelCountInBlock = 0;
// Calculate the average color of the pixels in the current block
for (let blockPixelY = 0; blockPixelY < dotSize; blockPixelY++) {
const currentPixelY = y + blockPixelY;
if (currentPixelY >= imgHeight) break; // Stop if row is outside image bounds
for (let blockPixelX = 0; blockPixelX < dotSize; blockPixelX++) {
const currentPixelX = x + blockPixelX;
if (currentPixelX >= imgWidth) break; // Stop if column is outside image bounds
const R_idx = (currentPixelY * imgWidth + currentPixelX) * 4;
sumR += sourcePixelData[R_idx];
sumG += sourcePixelData[R_idx + 1];
sumB += sourcePixelData[R_idx + 2];
pixelCountInBlock++;
}
}
if (pixelCountInBlock === 0) continue; // Should not happen for valid image blocks
const avgR = sumR / pixelCountInBlock;
const avgG = sumG / pixelCountInBlock;
const avgB = sumB / pixelCountInBlock;
// Calculate luminance of the average block color (0-255)
const luminance = 0.299 * avgR + 0.587 * avgG + 0.114 * avgB;
// Determine dot size based on luminance: darker block = larger dot
// intensityFactor is 1 for black (luminance=0), 0 for white (luminance=255)
const intensityFactor = (255.0 - luminance) / 255.0;
let currentDotRadius = intensityFactor * baseCellRadius * dotSizeMultiplier;
currentDotRadius = Math.max(0, currentDotRadius); // Ensure radius is not negative
// Draw the dot if it's large enough to be visible (e.g., diameter >= 0.5px)
if (currentDotRadius >= 0.25) {
ctx.beginPath();
// Center of the dot is the center of the current block
ctx.arc(
x + dotSize / 2.0,
y + dotSize / 2.0,
currentDotRadius,
0, // Start angle
2 * Math.PI, // End angle
false // Counterclockwise
);
let finalDotFillStyle;
if (dotColorMode === 'average') {
finalDotFillStyle = `rgb(${Math.round(avgR)}, ${Math.round(avgG)}, ${Math.round(avgB)})`;
} else if (dotColorMode === 'black') {
finalDotFillStyle = 'black';
} else {
// Assume dotColorMode is a user-provided CSS color string (e.g., 'red', '#FF0000')
finalDotFillStyle = dotColorMode;
}
ctx.fillStyle = finalDotFillStyle;
ctx.fill();
}
}
}
return outputCanvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Magazine Print Filter is an online tool designed to transform images into a dot-based, magazine-style print effect. Users can customize various parameters such as dot size, color mode, and desaturation levels to achieve a unique visual style. This tool is useful for graphic designers, digital artists, and hobbyists looking to create artistic renditions of photographs suitable for print media, posters, or digital art projects. It allows for flexibility in color representation and background settings, making it an excellent choice for creative visual experimentation.