You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, sortMode = 'rows', sortKey = 'brightness', sortDirection = 'ascending', thresholdMinStr = '0', thresholdMaxStr = '255') {
// This function interprets "Image Alphabetical Translator" as a "pixel sorting" utility.
// "Alphabetical" is interpreted as sorting pixels based on a certain value.
// This implementation provides various sorting keys, including a 'hex' mode for true
// alphabetical (lexicographical) sorting of color values.
const canvas = document.createElement('canvas');
// Using { willReadFrequently: true } is a performance hint for browsers.
const ctx = canvas.getContext('2d', { willReadFrequently: true });
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
ctx.drawImage(originalImg, 0, 0);
const thresholdMin = Number(thresholdMinStr);
let thresholdMax = Number(thresholdMaxStr);
/**
* Converts an RGB color value to HSL.
* @param {number} r The red color value (0-255)
* @param {number} g The green color value (0-255)
* @param {number} b The blue color value (0-255)
* @returns {Array<number>} An array containing the HSL values [h, s, l].
*/
function rgbToHsl(r, g, b) {
r /= 255;
g /= 255;
b /= 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h = 0, s = 0, l = (max + min) / 2;
if (max !== min) {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return [h * 360, s * 100, l * 100];
}
/**
* Calculates a sortable value from RGB components based on the specified sortKey.
* @param {number} r The red color value (0-255)
* @param {number} g The green color value (0-255)
* @param {number} b The blue color value (0-255)
* @param {string} key The sorting key ('hex', 'red', 'green', 'blue', 'hue', etc.)
* @returns {number|string} The value to be used for sorting.
*/
function getSortValue(r, g, b, key) {
switch (key) {
case 'hex':
const toHex = c => c.toString(16).padStart(2, '0');
return `${toHex(r)}${toHex(g)}${toHex(b)}`;
case 'red': return r;
case 'green': return g;
case 'blue': return b;
case 'hue':
case 'saturation':
case 'lightness': {
const [h, s, l] = rgbToHsl(r, g, b);
if (key === 'hue') return h;
if (key === 'saturation') return s;
return l;
}
case 'brightness':
default:
// Luma formula (BT.601 standard)
return (0.299 * r + 0.587 * g + 0.114 * b);
}
}
// Adjust the maximum possible threshold value based on the sort key.
// Thresholds do not apply to 'hex' mode.
if (sortKey !== 'hex') {
let maxVal = 255;
if (sortKey === 'hue') maxVal = 360;
if (sortKey === 'saturation' || sortKey === 'lightness') maxVal = 100;
if (thresholdMax > maxVal) {
thresholdMax = maxVal;
}
}
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
const { width, height } = canvas;
const getPixel = (x, y) => {
const i = (y * width + x) * 4;
return [data[i], data[i + 1], data[i + 2], data[i + 3]];
};
const setPixel = (x, y, rgba) => {
const i = (y * width + x) * 4;
data[i] = rgba[0];
data[i + 1] = rgba[1];
data[i + 2] = rgba[2];
data[i + 3] = rgba[3];
};
const sortSegment = (start, end, fixedCoord, isRow) => {
if (start >= end) return; // Nothing to sort for a single pixel or less
const segmentPixels = [];
// Extract pixels from the segment
for (let i = start; i <= end; i++) {
const [x, y] = isRow ? [i, fixedCoord] : [fixedCoord, i];
const rgba = getPixel(x, y);
segmentPixels.push({ rgba, sortValue: getSortValue(rgba[0], rgba[1], rgba[2], sortKey) });
}
// Sort the segment
segmentPixels.sort((a, b) => {
if (sortKey === 'hex') {
return sortDirection === 'ascending'
? a.sortValue.localeCompare(b.sortValue)
: b.sortValue.localeCompare(a.sortValue);
} else {
return sortDirection === 'ascending'
? a.sortValue - b.sortValue
: b.sortValue - a.sortValue;
}
});
// Write the sorted pixels back to the main image data
for (let i = start; i <= end; i++) {
const [x, y] = isRow ? [i, fixedCoord] : [fixedCoord, i];
setPixel(x, y, segmentPixels[i - start].rgba);
}
};
const processLines = (lineLength, fixedLength, isRow) => {
for (let i = 0; i < fixedLength; i++) {
let segmentStart = -1;
for (let j = 0; j < lineLength; j++) {
const [x, y] = isRow ? [j, i] : [i, j];
const rgba = getPixel(x, y);
// For 'hex' mode, ignore thresholds and sort the entire line.
const value = sortKey === 'hex' ? 0 : getSortValue(rgba[0], rgba[1], rgba[2], sortKey);
const inThreshold = sortKey === 'hex' || (value >= thresholdMin && value <= thresholdMax);
if (inThreshold && segmentStart < 0) {
segmentStart = j; // Start of a new sortable segment
} else if (!inThreshold && segmentStart >= 0) {
sortSegment(segmentStart, j - 1, i, isRow); // End of a segment
segmentStart = -1;
}
}
// If a segment extends to the end of the line, sort it.
if (segmentStart >= 0) {
sortSegment(segmentStart, lineLength - 1, i, isRow);
}
}
};
if (sortMode === 'rows') {
processLines(width, height, true);
} else if (sortMode === 'columns') {
processLines(height, width, false);
}
ctx.putImageData(imageData, 0, 0);
return canvas;
}
Free Image Tool Creator
Can't find the image tool you're looking for? Create one based on your own needs now!
The Image Alphabetical Translator Tool is a pixel sorting utility that allows users to manipulate images by sorting their pixels based on various criteria such as brightness, color channels (red, green, blue), and even hexadecimal values. Users can choose to sort pixels in either rows or columns, and can set thresholds for sorting. This tool can be useful for artists and designers looking to create unique visual effects, for data visualization purposes, or for generating abstract representations of images based on different sorting criteria.