React.js is a popular JavaScript library that enables developers to create powerful and dynamic user interfaces. One of the features of React.js is the ability to manipulate images by adding watermarks to them. In this blog post, we will explore how to add a watermark to an image using React.js.
Watermarking an image is a popular way to protect your intellectual property, especially if the image is being shared on social media or other online platforms. A watermark is a semi-transparent image or text that is overlaid on top of another image to indicate ownership or origin. In this blog post, we will be adding a text watermark to an image using React.js.
To add a watermark to an image in React.js, we will use the HTML canvas element. The canvas element is used to draw graphics on a web page using JavaScript. We will create a canvas element and draw the original image and the watermark text on it. We will then convert the canvas to an image and display it to the user.
Prerequisites
Before we get started, ensure that you have the following prerequisites:
Basic knowledge of HTML, CSS, and JavaScript
Node.js and npm installed on your system
A text editor like Visual Studio Code
Getting started
Let's start by creating a new React.js project. Open your terminal and type the following command to create a new React.js project.
npx create-react-app react.js-watermark-added-to-the-image
This command creates a new React.js project with the name react.js-watermark-added-to-the-image
. Navigate to the project directory by running the following command:
cd react.js-watermark-added-to-the-image
Open the project directory in your text editor. Next,
Creating a custom hook
Create a new file named useWatermarkAddedToTheImage.tsx
in the src/hooks
directory of your project. This file will contain the code for the watermark added logic. Here's the code for the custom hook:
import { useState } from 'react';
import { toast } from 'react-toastify';
export interface IFileProcessing {
fileName: string;
imgWatermarkFile: any;
textWatermarkFile: any;
originalFile: any;
}
const useWatermarkAddedToTheImage = () => {
const [processedFile, setProcessedFile] = useState<IFileProcessing | null>();
const [isProcessing, setIsProcessing] = useState<boolean>(false);
const startFileProcessing = async (imgFile: any) => {
try {
if (!imgFile?.name) throw new Error('Please select a valid image file.');
setIsProcessing(true);
let item: IFileProcessing = {
fileName: imgFile?.name,
imgWatermarkFile: null,
textWatermarkFile: null,
originalFile: imgFile,
};
const imgWatermarkFile = await imgWatermark(imgFile, '/logo192.png');
const textWatermarkFile = await textWatermark(imgFile, 'React.js');
setProcessedFile({ ...item, imgWatermarkFile, textWatermarkFile });
} catch (error) {
toast.error(`${error}`);
} finally {
setIsProcessing(false);
}
};
return [(imgFile: any) => startFileProcessing(imgFile), processedFile, isProcessing] as const;
};
const imgWatermark = async (imgOriginal: File, watermarkImagePath: any, quality = 0.75) => {
return new Promise((resolve, reject) => {
let canvas: any = document.createElement('canvas');
canvas.imageSmoothingQuality = 'medium'; // [low, medium, high] Reference:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality
let context: any = canvas.getContext('2d');
let img = document.createElement('img');
img.src = URL.createObjectURL(imgOriginal);
img.onload = async () => {
canvas.width = img.width;
canvas.height = img.height;
// initializing the canvas with the original image
context.drawImage(img, 0, 0, canvas.width, canvas.height);
// loading the watermark image and transforming it into a pattern
const result = await fetch(watermarkImagePath);
const blob = await result.blob();
const image = await createImageBitmap(blob);
const pattern = context.createPattern(image, 'no-repeat');
// translating the watermark text to the top left corner
context.translate(25, 25);
context.rect(0, 0, canvas.width, canvas.height);
context.fillStyle = pattern;
context.fill();
return context.canvas.toBlob((blob: any) => resolve(blob), 'image/jpeg', quality);
};
img.onerror = () => reject(`${imgOriginal.name} is invalid image format.`);
});
};
const textWatermark = async (imgOriginal: File, watermarkText: string, quality = 0.75) => {
return new Promise((resolve, reject) => {
let canvas: any = document.createElement('canvas');
canvas.imageSmoothingQuality = 'medium'; // [low, medium, high] Reference:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality
let context: any = canvas.getContext('2d');
let img = document.createElement('img');
img.src = URL.createObjectURL(imgOriginal);
img.onload = async () => {
canvas.width = img.width;
canvas.height = img.height;
// initializing the canvas with the original image
context.drawImage(img, 0, 0, canvas.width, canvas.height);
// adding a blue watermark text in the top left corner
context.fillStyle = 'white';
context.textBaseline = 'middle';
context.font = 'bold 100px serif';
context.fillText(watermarkText, 100, 100);
return context.canvas.toBlob((blob: any) => resolve(blob), 'image/jpeg', quality);
};
img.onerror = () => reject(`${imgOriginal.name} is invalid image format.`);
});
};
export default useWatermarkAddedToTheImage;
The code defines a custom hook named useWatermarkAddedToTheImage that returns a tuple of three values:
A function named
startFileProcessing
that accepts an image file as an argument and triggers the watermarking process on that file.A state variable named
processedFile
which is initially set to null, but gets updated with the processed image files (with two different types of watermarks).A state variable named
isProcessing
which is initially set tofalse
, but gets updated totrue
during the watermarking process.
The hook internally uses two async functions named imgWatermark
and textWatermark
to add image and text watermarks to the given image file. The hook utilizes the useState
and toast
hooks from react and react-toastify
packages, respectively.
const imgWatermark = async (imgOriginal: File, watermarkImagePath: any, quality = 0.75) => {
return new Promise((resolve, reject) => {
let canvas: any = document.createElement('canvas');
canvas.imageSmoothingQuality = 'medium'; // [low, medium, high] Reference:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality
let context: any = canvas.getContext('2d');
let img = document.createElement('img');
img.src = URL.createObjectURL(imgOriginal);
img.onload = async () => {
canvas.width = img.width;
canvas.height = img.height;
// initializing the canvas with the original image
context.drawImage(img, 0, 0, canvas.width, canvas.height);
// loading the watermark image and transforming it into a pattern
const result = await fetch(watermarkImagePath);
const blob = await result.blob();
const image = await createImageBitmap(blob);
const pattern = context.createPattern(image, 'no-repeat');
// translating the watermark text to the top left corner
context.translate(25, 25);
context.rect(0, 0, canvas.width, canvas.height);
context.fillStyle = pattern;
context.fill();
return context.canvas.toBlob((blob: any) => resolve(blob), 'image/jpeg', quality);
};
img.onerror = () => reject(`${imgOriginal.name} is invalid image format.`);
});
};
The above code defines a function called imgWatermark
that applies a watermark image onto another image. The function takes three parameters: imgOriginal
is the original image that will have the watermark applied, watermarkImagePath
is the path to the watermark image file, and quality
is an optional parameter that determines the quality of the resulting image.
The function creates a new canvas element, loads the original image onto it, and then loads the watermark image, transforms it into a pattern, and applies it to the canvas. Finally, it converts the canvas into a blob and returns it as a Promise.
Note that this function appears to be designed to be run in a browser environment, as it references several browser-specific objects and methods, such as document.createElement
, URL.createObjectURL
, and createImageBitmap
.
const textWatermark = async (imgOriginal: File, watermarkText: string, quality = 0.75) => {
return new Promise((resolve, reject) => {
let canvas: any = document.createElement('canvas');
canvas.imageSmoothingQuality = 'medium'; // [low, medium, high] Reference:https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingQuality
let context: any = canvas.getContext('2d');
let img = document.createElement('img');
img.src = URL.createObjectURL(imgOriginal);
img.onload = async () => {
canvas.width = img.width;
canvas.height = img.height;
// initializing the canvas with the original image
context.drawImage(img, 0, 0, canvas.width, canvas.height);
// adding a blue watermark text in the top left corner
context.fillStyle = 'white';
context.textBaseline = 'middle';
context.font = 'bold 100px serif';
context.fillText(watermarkText, 100, 100);
return context.canvas.toBlob((blob: any) => resolve(blob), 'image/jpeg', quality);
};
img.onerror = () => reject(`${imgOriginal.name} is invalid image format.`);
});
};
The above code defines a function called textWatermark
that applies a text watermark onto an image. The function takes three parameters: imgOriginal
is the original image that will have the watermark applied, watermarkText
is the text to be used as the watermark, and quality
is an optional parameter that determines the quality of the resulting image.
The function creates a new canvas element, loads the original image onto it, and then adds the specified watermark text onto the canvas. The text is positioned at coordinates (100, 100) with a font size of 100 pixels, using a bold serif font with white fill color.
Finally, the function converts the canvas into a blob and returns it as a Promise.
Note that this function appears to be designed to be run in a browser environment, as it references several browser-specific objects and methods, such as document.createElement
, URL.createObjectURL
, and canvas.toBlob
.
Summary
In this blog post, we explore how to add watermarks to images in a React application using the HTML5 Canvas API and the useState
and useEffect
hooks. Specifically, we demonstrate how to add two types of watermarks to an image: an image watermark (e.g., a logo image) and a text watermark (e.g., a copyright notice).
By the end of this blog post, readers should have a good understanding of how to use watermarks to process images in a React application and be able to apply this knowledge to their own projects.
I hope you found this tutorial helpful! If you have any questions or feedback, feel free to let me know.