You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, numLevels = 5, colorsStr = "") {
// Helper function to convert HEX color to RGB object
// It's defined inside processImage to keep it self-contained.
const _hexToRgb = (hexColor) => {
// Trim and remove '#'
const hex = String(hexColor).trim().replace(/^#/, '');
// Validate hex format (3 or 6 hex characters)
if (!/^(?:[0-9a-fA-F]{3}){1,2}$/.test(hex)) {
return null;
}
let fullHex = hex;
if (hex.length === 3) {
fullHex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
}
const bigint = parseInt(fullHex, 16);
// Check if parsing was successful (it should be if regex passed)
if (isNaN(bigint)) {
return null;
}
const r = (bigint >> 16) & 255;
const g = (bigint >> 8) & 255;
const b = bigint & 255;
return { r, g, b };
};
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Use naturalWidth/Height for <img> elements, or width/height for Image objects
const width = originalImg.naturalWidth || originalImg.width;
const height = originalImg.naturalHeight || originalImg.height;
// Handle cases where image dimensions are invalid
if (width === 0 || height === 0) {
canvas.width = 1; // Return a 1x1 canvas
canvas.height = 1;
return canvas;
}
canvas.width = width;
canvas.height = height;
try {
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, width, height);
} catch (e) {
console.error("Error drawing original image: ", e);
// Return the blank canvas (correctly sized) if drawing fails
return canvas;
}
let imageData;
try {
// Get pixel data from the canvas
imageData = ctx.getImageData(0, 0, width, height);
} catch (e) {
console.error("Error getting ImageData (possibly due to CORS or tainted canvas): ", e);
// If pixel data cannot be accessed, return the canvas with the original image drawn
// (as drawing was successful above)
return canvas;
}
const data = imageData.data; // Pixel data array (R,G,B,A, R,G,B,A, ...)
// Validate and prepare the number of levels for quantization
// Ensure numLevels is an integer and at least 1
numLevels = Math.max(1, Math.floor(Number(numLevels)));
// Prepare the color palette
let parsedColors = [];
if (typeof colorsStr === 'string' && colorsStr.trim() !== "") {
parsedColors = colorsStr.split(',')
.map(c => _hexToRgb(c)) // _hexToRgb handles trimming and '#'
.filter(c => c !== null); // Filter out any invalid colors
}
// Default color palette for a topographic map effect
const defaultColorPalette = [
{ r: 68, g: 114, b: 196 }, // ~Blue (representing water/low elevation)
{ r: 112, g: 173, b: 71 }, // ~Green (representing lowlands/vegetation)
{ r: 255, g: 217, b: 102 }, // ~Yellow (representing mid-altitude/sandy areas)
{ r: 198, g: 89, b: 17 }, // ~Brown (representing higher altitude/rocky areas)
{ r: 220, g: 220, b: 220 } // ~Light Gray/White (representing peaks/snow)
];
const colorPalette = parsedColors.length > 0 ? parsedColors : defaultColorPalette;
// Safeguard: if the effective colorPalette is empty for any reason, add a fallback color
if (colorPalette.length === 0) {
colorPalette.push({r: 0, g: 0, b: 0}); // Fallback to black
}
// Iterate over each pixel in the image data
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 preserved
// Convert the pixel to grayscale using the luminosity method
const gray = 0.299 * r + 0.587 * g + 0.114 * b; // Value from 0 (black) to 255 (white)
// Quantize the grayscale value to determine its level index
const grayNormalized = gray / 255; // Normalize to 0-1 range
// Calculate the level index. For numLevels, indices are 0 to numLevels-1.
// E.g., if numLevels = 5:
// grayNormalized = 0 -> levelIndex = floor(0*5) = 0
// grayNormalized = 0.19 -> levelIndex = floor(0.19*5) = floor(0.95) = 0
// grayNormalized = 0.2 -> levelIndex = floor(0.2*5) = floor(1.0) = 1
// ...
// grayNormalized = 1 -> levelIndex = floor(1*5) = 5. This needs clamping.
let levelIndex = Math.floor(grayNormalized * numLevels);
// Clamp the index to the valid range [0, numLevels-1]
levelIndex = Math.min(levelIndex, numLevels - 1);
// Select the color for this level from the_REPLACE palette
// Cycle through palette colors if numLevels is greater than palette size
const selectedColor = colorPalette[levelIndex % colorPalette.length];
// Update the pixel data with the new color
data[i] = selectedColor.r;
data[i + 1] = selectedColor.g;
data[i + 2] = selectedColor.b;
}
// Put the modified pixel data back onto the canvas
ctx.putImageData(imageData, 0, 0);
// Return the processed canvas
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 Topographic Map Filter Effect tool allows users to transform images into stylized topographic representations. By processing the input image, it reduces the color levels and applies a customizable color palette to create distinct layers typical of topographic maps, using predefined colors that signify different elevations. This tool is useful for graphic designers, educators, and outdoor enthusiasts who wish to visualize landscapes, create maps for presentations, or enhance images for creative projects.