You can edit the below JavaScript code to customize the image tool.
/**
* Applies a displacement map effect to an image.
* This function takes a source image and a map image, and for each pixel, it uses the color
* values from the map image to offset (displace) the corresponding pixel from the source image.
*
* @param {HTMLImageElement} originalImg The source image object to be distorted.
* @param {string} [mapImgDataURL='...'] A data URL string for the displacement map image. Defaults to a horizontal black-to-white gradient.
* @param {number} [horizontalDisplacementScale=25] The maximum number of pixels to displace horizontally.
* @param {number} [verticalDisplacementScale=25] The maximum number of pixels to displace vertically.
* @param {string} [displacementChannelX='luminance'] The color channel from the map to use for horizontal displacement. Can be 'red', 'green', 'blue', 'alpha', or 'luminance'.
* @param {string} [displacementChannelY='luminance'] The color channel from the map to use for vertical displacement. Can be 'red', 'green', 'blue', 'alpha', or 'luminance'.
* @returns {Promise<HTMLCanvasElement>} A promise that resolves with a new canvas element containing the displaced image.
*/
async function processImage(originalImg, mapImgDataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAAAXNSR0IArs4c6QAAAPZJREFUeF7t1AEJADAMA8Gb3H8xJ1g7kS5IEmzbtrW2tbe3N7W2tTe1N7W39X/vBYmQECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFChAgRIkSIECFDg9QcDBbX7cQAAAABJRU5ErkJggg==', horizontalDisplacementScale = 25, verticalDisplacementScale = 25, displacementChannelX = 'luminance', displacementChannelY = 'luminance') {
// Asynchronously load the displacement map image from the provided data URL.
const mapImg = await new Promise((resolve, reject) => {
const img = new Image();
img.crossOrigin = "Anonymous";
img.onload = () => resolve(img);
img.onerror = () => reject(new Error('Failed to load the map image from the data URL.'));
img.src = mapImgDataURL;
});
const {
width,
height
} = originalImg;
// Create a canvas for the final output
const outputCanvas = document.createElement('canvas');
outputCanvas.width = width;
outputCanvas.height = height;
const outputCtx = outputCanvas.getContext('2d');
// Create a temporary canvas to draw the source image and get its pixel data
const sourceCanvas = document.createElement('canvas');
sourceCanvas.width = width;
sourceCanvas.height = height;
const sourceCtx = sourceCanvas.getContext('2d', {
willReadFrequently: true
});
sourceCtx.drawImage(originalImg, 0, 0);
// Create a temporary canvas to draw the map image (stretched to fit) and get its pixel data
const mapCanvas = document.createElement('canvas');
mapCanvas.width = width;
mapCanvas.height = height;
const mapCtx = mapCanvas.getContext('2d', {
willReadFrequently: true
});
mapCtx.drawImage(mapImg, 0, 0, width, height);
// Get the raw pixel data arrays from the canvases
const sourceImageData = sourceCtx.getImageData(0, 0, width, height);
const mapImageData = mapCtx.getImageData(0, 0, width, height);
const outputImageData = outputCtx.createImageData(width, height);
const sourceData = sourceImageData.data;
const mapData = mapImageData.data;
const outputData = outputImageData.data;
/**
* Helper to get a specific channel value from the map data for a given pixel.
*/
const getChannelValue = (pixelIndex, channel) => {
const r = mapData[pixelIndex];
const g = mapData[pixelIndex + 1];
const b = mapData[pixelIndex + 2];
const a = mapData[pixelIndex + 3];
switch (channel.toLowerCase()) {
case 'red':
return r;
case 'green':
return g;
case 'blue':
return b;
case 'alpha':
return a;
case 'luminance':
default:
// Standard luminance calculation (Rec. 601)
return 0.299 * r + 0.587 * g + 0.114 * b;
}
};
// Iterate over each pixel of the output image to calculate its new color
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
const currentPixelIndex = (y * width + x) * 4;
// Get displacement values from the map image's specified channels
const valX = getChannelValue(currentPixelIndex, displacementChannelX);
const valY = getChannelValue(currentPixelIndex, displacementChannelY);
// Normalize the 0-255 channel value to a -0.5 to 0.5 range and apply the scale.
// A 50% gray (127.5) results in zero displacement.
const offsetX = (valX / 255 - 0.5) * horizontalDisplacementScale;
const offsetY = (valY / 255 - 0.5) * verticalDisplacementScale;
// Calculate the source pixel coordinates to sample color from
const sourceX = x + offsetX;
const sourceY = y + offsetY;
// Round to the nearest integer and clamp coordinates to stay within image bounds
const clampedX = Math.max(0, Math.min(width - 1, Math.round(sourceX)));
const clampedY = Math.max(0, Math.min(height - 1, Math.round(sourceY)));
const sourcePixelIndex = (clampedY * width + clampedX) * 4;
// Copy the color from the displaced source pixel to the current output pixel
outputData[currentPixelIndex] = sourceData[sourcePixelIndex];
outputData[currentPixelIndex + 1] = sourceData[sourcePixelIndex + 1];
outputData[currentPixelIndex + 2] = sourceData[sourcePixelIndex + 2];
outputData[currentPixelIndex + 3] = sourceData[sourcePixelIndex + 3];
}
}
// Draw the final manipulated pixel data onto the output canvas
outputCtx.putImageData(outputImageData, 0, 0);
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 Displacement Mapping Tool allows users to apply a displacement map effect to an image. By utilizing a source image along with a map image, the tool displaces each pixel of the source image based on the color values from the map image. This effect can create various visual transformations, adding depth and texture to images. Use cases include enhancing graphics for digital artwork, creating unique visual effects for presentations, and generating interesting textures for web design or digital media projects.