You can edit the below JavaScript code to customize the image tool.
Apply Changes
function processImage(
originalImg, // HTMLImageElement
histWidthParam = 256, // number, width of histogram plot area
histHeightParam = 100, // number, height of histogram plot area
showRedParam = "true", // string "true" or "false"
showGreenParam = "true", // string "true" or "false"
showBlueParam = "true", // string "true" or "false"
showGrayParam = "true", // string "true" or "false"
colorRedParam = "rgba(255,0,0,0.7)", // string, color for red hist
colorGreenParam = "rgba(0,180,0,0.7)", // string, color for green hist
colorBlueParam = "rgba(0,0,255,0.7)", // string, color for blue hist
colorGrayParam = "rgba(100,100,100,0.7)", // string, color for gray hist
backgroundColorParam = "#f0f0f0", // string, canvas background
textColorParam = "#333333", // string, label text color
paddingParam = 10, // number, padding around elements
showLabelsParam = "true", // string "true" or "false"
labelFontSizeParam = 12 // number, font size for labels
) {
// Parse and validate parameters
const histWidth = Math.max(32, Number(histWidthParam) || 256);
const histHeight = Math.max(10, Number(histHeightParam) || 100);
const padding = Math.max(0, Number(paddingParam) || 10);
const labelFontSize = Math.max(6, Number(labelFontSizeParam) || 12);
const _showRed = showRedParam.toLowerCase() === "true";
const _showGreen = showGreenParam.toLowerCase() === "true";
const _showBlue = showBlueParam.toLowerCase() === "true";
const _showGray = showGrayParam.toLowerCase() === "true";
const _showLabels = showLabelsParam.toLowerCase() === "true";
// Helper function to create an error/message canvas
const createMessageCanvas = (message) => {
const canvas = document.createElement('canvas');
const estimatedMessageWidth = message.length * labelFontSize * 0.6 + 2 * padding;
canvas.width = Math.max(200, histWidth + 2 * padding, estimatedMessageWidth);
canvas.height = Math.max(50, labelFontSize + 2 * padding);
const ctx = canvas.getContext('2d');
ctx.fillStyle = backgroundColorParam;
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = textColorParam;
ctx.font = `${labelFontSize}px sans-serif`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(message, canvas.width / 2, canvas.height / 2);
return canvas;
};
// 1. Get image data
const imgWidth = originalImg.naturalWidth;
const imgHeight = originalImg.naturalHeight;
if (!originalImg.complete || imgWidth === 0 || imgHeight === 0) {
return createMessageCanvas("Image not loaded or invalid dimensions");
}
const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = imgWidth;
sourceCanvas.height = imgHeight;
const sourceCtx = sourceCanvas.getContext('2d', { willReadFrequently: true });
try {
sourceCtx.drawImage(originalImg, 0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Error drawing image to source canvas:", e);
return createMessageCanvas("Error drawing original image.");
}
let imageData;
try {
imageData = sourceCtx.getImageData(0, 0, imgWidth, imgHeight);
} catch (e) {
console.error("Error getting image data (getImageData):", e);
return createMessageCanvas("Cannot process image (e.g., cross-origin restrictions)");
}
const data = imageData.data;
// 2. Calculate histograms
const rHist = new Array(256).fill(0);
const gHist = new Array(256).fill(0);
const bHist = new Array(256).fill(0);
const grayHist = new Array(256).fill(0);
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// Alpha data[i+3] is ignored
rHist[r]++;
gHist[g]++;
bHist[b]++;
const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
grayHist[gray]++;
}
// 3. Prepare plot infos
const plotInfos = [];
if (_showRed) plotInfos.push({ data: rHist, color: colorRedParam, name: "Red Channel" });
if (_showGreen) plotInfos.push({ data: gHist, color: colorGreenParam, name: "Green Channel" });
if (_showBlue) plotInfos.push({ data: bHist, color: colorBlueParam, name: "Blue Channel" });
if (_showGray) plotInfos.push({ data: grayHist, color: colorGrayParam, name: "Grayscale" });
// 4. Handle no plots selected
if (plotInfos.length === 0) {
return createMessageCanvas("No channels selected for histogram");
}
// 5. Calculate output canvas dimensions
const outputCanvasWidth = histWidth + 2 * padding;
let outputCanvasHeight = padding; // Initial top padding
for (let i = 0; i < plotInfos.length; i++) {
if (_showLabels) {
outputCanvasHeight += labelFontSize + padding; // Space for label + padding below it
}
outputCanvasHeight += histHeight + padding; // Space for plot + padding below it
}
// 6. Create output canvas and draw
const outputCanvas = document.createElement('canvas');
outputCanvas.width = outputCanvasWidth;
outputCanvas.height = outputCanvasHeight;
const ctx = outputCanvas.getContext('2d');
ctx.fillStyle = backgroundColorParam;
ctx.fillRect(0, 0, outputCanvasWidth, outputCanvasHeight);
let currentY = padding;
for (const plot of plotInfos) {
if (_showLabels) {
ctx.fillStyle = textColorParam;
ctx.font = `${labelFontSize}px sans-serif`;
ctx.textBaseline = 'top';
ctx.fillText(plot.name, padding, currentY);
currentY += labelFontSize + padding;
}
const histData = plot.data;
let maxFreq = 0;
for (let k = 0; k < 256; k++) {
if (histData[k] > maxFreq) {
maxFreq = histData[k];
}
}
const barPlotX = padding;
const barPlotY = currentY;
const barWidthValue = histWidth / 256;
ctx.fillStyle = plot.color;
if (maxFreq > 0) {
for (let k = 0; k < 256; k++) {
const barHeight = (histData[k] / maxFreq) * histHeight;
if (barHeight > 0) {
ctx.fillRect(
barPlotX + k * barWidthValue,
barPlotY + histHeight - barHeight,
barWidthValue,
barHeight
);
}
}
}
currentY += histHeight + padding;
}
return outputCanvas;
}
Apply Changes