You can edit the below JavaScript code to customize the image tool.
async function processImage(
originalImg,
textColor = "white",
fontSize = 20,
fontFamily = "Arial",
backgroundColor = "rgba(0, 0, 0, 0.5)",
textBgPadding = 8, // Padding for text within its background
stampMargin = 10, // Margin of the whole stamp from image border
stampPosition = "bottom-left" // "top-left", "top-right", "bottom-left", "bottom-right", "center"
) {
// Helper function to get geolocation string
async function getGeoLocationString() {
return new Promise((resolve) => {
if (!navigator.geolocation) {
resolve("Geolocation not supported");
return;
}
navigator.geolocation.getCurrentPosition(
async (position) => {
const lat = position.coords.latitude;
const lon = position.coords.longitude;
try {
// Using Nominatim (OpenStreetMap) for reverse geocoding
const apiUrl = `https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=${lat}&lon=${lon}&accept-language=en`;
const response = await fetch(apiUrl);
if (!response.ok) {
resolve(`Lat: ${lat.toFixed(3)}, Lon: ${lon.toFixed(3)} (API Error ${response.status})`);
return;
}
const data = await response.json();
if (data.error) {
resolve(`Lat: ${lat.toFixed(3)}, Lon: ${lon.toFixed(3)} (${data.error})`);
return;
}
let locationString = "";
if (data.address) {
const city = data.address.city || data.address.town || data.address.village;
const state = data.address.state || data.address.county;
const country = data.address.country;
let parts = [];
if (city) parts.push(city);
// Add state only if it's different from city (e.g. for US cities) and not too long
if (state && state !== city && state.length < 25) parts.push(state);
if (country) parts.push(country);
locationString = parts.join(", ");
// Fallback to display_name if specific parts are not found or string is too short
if ((!locationString || locationString.length < 5) && data.display_name) {
locationString = data.display_name.length > 60 ? data.display_name.substring(0, 57) + "..." : data.display_name;
}
}
if (!locationString) { // If still no location string (e.g. middle of the ocean)
locationString = `Lat: ${lat.toFixed(4)}, Lon: ${lon.toFixed(4)}`;
}
resolve(locationString);
} catch (error) {
console.error("Reverse geocoding or processing error:", error);
resolve(`Lat: ${lat.toFixed(3)}, Lon: ${lon.toFixed(3)} (Request Error)`);
}
},
(error) => {
let errorMessage = "Location: ";
switch (error.code) {
case error.PERMISSION_DENIED:
errorMessage += "Permission Denied";
break;
case error.POSITION_UNAVAILABLE:
errorMessage += "Unavailable";
break;
case error.TIMEOUT:
errorMessage += "Timeout";
break;
default:
errorMessage += `Error ${error.code}`;
break;
}
resolve(errorMessage);
},
{ // Geolocation options
enableHighAccuracy: false, // Balances accuracy and power consumption
timeout: 10000, // 10 seconds to get a fix
maximumAge: 300000 // Use a cached position up to 5 minutes old
}
);
});
}
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Check if the image is valid and loaded
if (!originalImg || typeof originalImg.naturalWidth === 'undefined' || originalImg.naturalWidth === 0 || originalImg.naturalHeight === 0) {
console.error("Image Location Stamp Adder: Invalid image provided or image not loaded.");
// Create a small canvas with an error message
canvas.width = 300;
canvas.height = 100;
ctx.fillStyle = "# сожалениюFFDDDD"; // Light red background
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = "red";
ctx.strokeStyle = "darkred";
ctx.lineWidth = 2;
ctx.strokeRect(0, 0, canvas.width, canvas.height);
ctx.font = "bold 16px Arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("Error: Invalid or Broken Image", canvas.width / 2, canvas.height / 2);
return canvas;
}
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
// Draw the original image onto the canvas
ctx.drawImage(originalImg, 0, 0, canvas.width, canvas.height);
// Get the location string (this is an async operation)
const locationText = await getGeoLocationString();
// Setup text properties for measurement and drawing
ctx.font = `${fontSize}px ${fontFamily}`;
ctx.textAlign = "left";
ctx.textBaseline = "top"; // Y-coordinate refers to the top of the text's bounding box
const textMetrics = ctx.measureText(locationText);
const textWidth = textMetrics.width;
// fontSize is a good approximation for the visual height of the text.
// More precise metrics (like actualBoundingBoxAscent/Descent) could be used if needed.
const textVisualHeight = fontSize;
// Calculate dimensions of the background box for the text
const boxWidth = textWidth + 2 * textBgPadding;
const boxHeight = textVisualHeight + 2 * textBgPadding;
// Calculate initial X, Y coordinates for the top-left corner of the background box
let boxX, boxY;
switch (stampPosition) {
case "top-left":
boxX = stampMargin;
boxY = stampMargin;
break;
case "top-right":
boxX = canvas.width - boxWidth - stampMargin;
boxY = stampMargin;
break;
case "bottom-right":
boxX = canvas.width - boxWidth - stampMargin;
boxY = canvas.height - boxHeight - stampMargin;
break;
case "center":
boxX = (canvas.width - boxWidth) / 2;
boxY = (canvas.height - boxHeight) / 2;
break;
case "bottom-left": // Default
default:
boxX = stampMargin;
boxY = canvas.height - boxHeight - stampMargin;
break;
}
// Adjust boxX, boxY to ensure the stamp (at least part of it) is visible on canvas
// Clamp the starting point of the box to be within canvas bounds.
// If box is wider/taller than canvas, it will start at 0,0.
boxX = Math.max(0, Math.min(boxX, canvas.width - boxWidth));
boxY = Math.max(0, Math.min(boxY, canvas.height - boxHeight));
// Text drawing coordinates (absolute on canvas)
const textDrawX = boxX + textBgPadding;
const textDrawY = boxY + textBgPadding;
// Draw background for the text stamp (if a color is specified)
if (backgroundColor && backgroundColor !== "transparent" && backgroundColor !== "") {
ctx.fillStyle = backgroundColor;
// Draw the rectangle, ensuring it doesn't exceed canvas boundaries if stamp is larger.
// The actual drawn width/height of the box is clipped by canvas dimensions.
ctx.fillRect(boxX, boxY, boxWidth, boxHeight);
}
// Draw the location text
ctx.fillStyle = textColor;
// Font is already set (used for measureText).
ctx.fillText(locationText, textDrawX, textDrawY);
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 Location Stamp Adder is a tool that allows users to add a geolocation stamp to their images. This tool retrieves the user’s current geographical location and overlays it onto the image as text. Users can customize various aspects of the stamp, including text color, font size, font family, and background color. Additionally, they can choose the position of the stamp on the image, such as top-left, top-right, bottom-left, bottom-right, or center. This tool is ideal for photographers, travelers, and social media users who want to document and share their locations with their images.