Watermark

Add personalized watermarks to images using a simple React.

Original

Image Without Watermark

Image after adding watermark

Compressed

Image with Watermark

Installation

Install dependencies

1npm install pixel-craft --save

Copy the source code

components/ImageCompressor.tsx

1import React, { useEffect, useRef } from 'react';
2
3type Position = 
4  | 'top-left'
5  | 'top-right'
6  | 'bottom-left'
7  | 'bottom-right'
8  | 'center'
9  | 'custom';
10
11interface WatermarkedImageProps {
12  baseImageUrl: string;
13  watermarkText?: string;
14  watermarkImageUrl?: string;
15  position?: Position;
16  top?: number;
17  left?: number;
18  bottom?: number;
19  right?: number;
20  opacity?: number;
21  font?: string;
22  textColor?: string;
23  watermarkWidth?: number;
24  watermarkHeight?: number;
25}
26
27const WatermarkedImage: React.FC<WatermarkedImageProps> = ({
28  baseImageUrl,
29  watermarkText,
30  watermarkImageUrl,
31  position = 'bottom-right',
32  top,
33  left,
34  bottom,
35  right,
36  opacity = 0.5,
37  font = '24px Arial',
38  textColor = 'rgba(255, 255, 255, 0.7)',
39  watermarkWidth = 100,
40  watermarkHeight = 50,
41}) => {
42  const canvasRef = useRef<HTMLCanvasElement>(null);
43
44  useEffect(() => {
45    const baseImage = new Image();
46    baseImage.crossOrigin = 'anonymous';
47    baseImage.src = baseImageUrl;
48
49    baseImage.onload = () => {
50      const canvas = canvasRef.current;
51      if (!canvas) return;
52      const ctx = canvas.getContext('2d');
53      if (!ctx) return;
54
55      canvas.width = baseImage.width;
56      canvas.height = baseImage.height;
57
58      ctx.drawImage(baseImage, 0, 0);
59
60      const applyWatermark = () => {
61        ctx.globalAlpha = opacity;
62
63        let x = 0, y = 0;
64
65        const calculatePosition = () => {
66          switch (position) {
67            case 'top-left':
68              x = 10;
69              y = 10;
70              break;
71            case 'top-right':
72              x = baseImage.width - (watermarkWidth + 10);
73              y = 10;
74              break;
75            case 'bottom-left':
76              x = 10;
77              y = baseImage.height - (watermarkHeight + 10);
78              break;
79            case 'bottom-right':
80              x = baseImage.width - (watermarkWidth + 10);
81              y = baseImage.height - (watermarkHeight + 10);
82              break;
83            case 'center':
84              x = (baseImage.width - watermarkWidth) / 2;
85              y = (baseImage.height - watermarkHeight) / 2;
86              break;
87            case 'custom':
88              x = left ?? baseImage.width - (right ?? watermarkWidth + 10) - watermarkWidth;
89              y = top ?? baseImage.height - (bottom ?? watermarkHeight + 10) - watermarkHeight;
90              break;
91            default:
92              x = 10;
93              y = 10;
94          }
95        };
96
97        calculatePosition();
98
99        if (watermarkText) {
100          ctx.font = font;
101          ctx.fillStyle = textColor;
102          ctx.fillText(watermarkText, x, y + watermarkHeight);
103        } else if (watermarkImageUrl) {
104          const watermarkImage = new Image();
105          watermarkImage.crossOrigin = 'anonymous';
106          watermarkImage.src = watermarkImageUrl;
107          watermarkImage.onload = () => {
108            ctx.drawImage(watermarkImage, x, y, watermarkWidth, watermarkHeight);
109          };
110        }
111
112        ctx.globalAlpha = 1.0;
113      };
114
115      applyWatermark();
116    };
117  }, [
118    baseImageUrl,
119    watermarkText,
120    watermarkImageUrl,
121    position,
122    top,
123    left,
124    bottom,
125    right,
126    opacity,
127    font,
128    textColor,
129    watermarkWidth,
130    watermarkHeight,
131  ]);
132
133  return <canvas ref={canvasRef} />;
134};
135
136export default WatermarkedImage;

Props

Prop nameTypeRequiredDescription
baseImageURLString(required)URL of the base image to apply watermark on.
watermarkTextStringundefinedText content of the watermark (either this orwatermarkImageUrlis used).
watermarkImageUrlstringundefinedURL of an image to be used as the watermark.
position'top-left'
'top-right'
'bottom-left'
'bottom-right'
'center' 'custom'
'bottom-right'Predefined or custom positioning of the watermark.
topnumberundefinedTop offset for custom positioning.
leftnumberundefinedLeft offset for custom positioning.
bottomnumberundefinedBottom offset for custom positioning.
rightnumberundefinedRight offset for custom positioning.
opacitynumber0.5Opacity of the watermark (0 to 1).
fontstring'24px Arial'Font style used when applying text watermark.
textColorstring'rgba(255,255,255,0.7)'Color of the watermark text.
watermarkWidthnumber100Width of watermark image (if using watermarkImageUrl ).
watermarkHeightnumber50Height of watermark image.

Possible Errors and User Measures

Error/ IssueCauseUser's Measures/ Fixes
Base image fails to loadIncorrect or no CORS headersbaseImageUrlEnsure the URL is correct and the server supports CORS(Access-Control-Allow-Origin).
Watermark image not shownWrongwatermarkImageUrlor CORS restrictionSame as above: use accessible images and check CORS headers.
Watermark text is not visiblePoor textColor contrast with base imageUse high-contrast colors or semi-transparent backgrounds for text.
Canvas size is 0Image fails to load before drawingAdd error handling (onError) and conditionally render fallback UI.
Watermark image not positioned properlynvalid custom position values (top, left, right, bottom)Validate and clamp position values before use.
Image not updated when props changeRenders once and doesn’t reflect updated props Ensure useeffect dependency list includes all props affecting rendering (which you've already done well).

Real World Uses

Branding product images

Automatically add company logo to product or catalog images before display/upload.

Watermarking user-uploaded content

Add a copyright notice or username to user-uploaded photos in CMS, marketplaces, or design tools.

Protecting images in gallery/portfolio

Prevent misuse by watermarking preview images with your brand or signature.

Batch watermarking

Use in a loop to process multiple images and save/download them.

Optimization Techniques

TechniquesBenefits
Use requestAnimationFrame or async chunking for canvas workPrevents UI freezing on large image loads or batch processing.
Convert canvas to Blob instead of DataURL for large outputsMore memory-efficient and suitable for upload.
Preload watermark imageAvoid delayed drawing on first render; useImage with before canvas use. or onload to prevent UI freezing.
Allow setting watermark scaling relative to base image size   Makes watermark responsive to different image resolutions.
Debounce rerenders if props update rapidly   Useful if image URL or options are updated frequently (e.g., sliders/UI    tools).