A Capacitor plugin for adding text and image watermarks to images on iOS, Android, and Web.
This is a from-scratch Capacitor port of the API surface of
react-native-image-marker
(MIT licensed, by @JimmyDaddy). No source code
from the original project is included — see NOTICE for attribution.
npm install @daboss2003/capacitor-image-marker
npx cap sync| Platform | Minimum |
|---|---|
| iOS | 13.0 |
| Android | SDK 22 |
| Web | Any modern browser with Canvas 2D |
A working Capacitor app that exercises every feature (text watermarks, image
watermarks, position presets, font size, scale, max-size, save format, etc.)
lives in example/. Quick start:
cd example
npm install
npm run dev # opens http://localhost:5173
# Native:
npx cap add ios && npm run ios
npx cap add android && npm run androidSee example/README.md for details.
Wherever an ImageOptions.src is accepted, you may pass:
- An absolute
file://path (e.g. from@capacitor/filesystem) - An
http:///https://URL - A
data:image/...;base64,...data URI - A bare base64 string (will be treated as PNG/JPEG payload)
No require('./image.png') style asset references — pass real URIs.
import {
ImageMarker,
Position,
TextBackgroundType,
ImageFormat,
} from '@daboss2003/capacitor-image-marker';
const result = await ImageMarker.markText({
backgroundImage: {
src: 'file:///path/to/photo.jpg',
scale: 1,
rotate: 0,
alpha: 1,
},
watermarkTexts: [
{
text: 'Hello, World',
position: { position: Position.bottomRight },
style: {
color: '#ffffff',
fontSize: 36,
fontName: 'Helvetica',
bold: true,
shadowStyle: {
dx: 2,
dy: 2,
radius: 4,
color: '#000000aa',
},
textBackgroundStyle: {
type: TextBackgroundType.none,
color: '#00000088',
padding: '8 12',
cornerRadius: {
all: { x: 6, y: 6 },
},
},
},
},
],
quality: 90,
saveFormat: ImageFormat.jpg,
});
console.log(result.uri); // file:// path (or data: URI when saveFormat is base64)const result = await ImageMarker.markImage({
backgroundImage: { src: 'file:///path/to/photo.jpg' },
watermarkImages: [
{
src: 'file:///path/to/logo.png',
scale: 0.5,
alpha: 0.8,
rotate: 0,
position: { position: Position.bottomLeft },
},
],
saveFormat: ImageFormat.png,
});ImageMarker.markText(options: TextMarkOptions): Promise<MarkResult>
ImageMarker.markImage(options: ImageMarkOptions): Promise<MarkResult>Both methods resolve with { uri: string }:
- For
saveFormat: 'png' | 'jpg'(defaultjpg),uriis afile://path to the rendered image in the app's cache directory. - For
saveFormat: 'base64',uriis adata:image/png;base64,...data URI.
| Field | Type | Default | Description |
|---|---|---|---|
backgroundImage |
ImageOptions |
— | Image to draw text on. |
watermarkTexts |
TextOptions[] |
[] |
Text watermarks to render. |
quality |
number (0–100) |
100 |
JPEG quality. |
filename |
string |
random | Output filename in cache dir. |
saveFormat |
'png' | 'jpg' | 'base64' |
'jpg' |
Output format. |
maxSize |
number |
2048 |
Downscale source so neither side exceeds this. |
| Field | Type | Default | Description |
|---|---|---|---|
backgroundImage |
ImageOptions |
— | Image to draw watermarks on. |
watermarkImages |
WatermarkImageOptions[] |
— | One or more image watermarks. |
quality |
number |
100 |
JPEG quality. |
filename |
string |
random | Output filename in cache dir. |
saveFormat |
'png' | 'jpg' | 'base64' |
'jpg' |
Output format. |
maxSize |
number |
2048 |
Downscale source so neither side exceeds this. |
interface ImageOptions {
src: string; // file:// | http(s):// | data: | bare base64
scale?: number; // default 1
rotate?: number; // degrees, default 0
alpha?: number; // 0..1, default 1
}Same as ImageOptions plus:
interface WatermarkImageOptions extends ImageOptions {
position?: PositionOptions;
}Anchor a watermark either with an enum or with explicit coordinates.
interface PositionOptions {
X?: number | string; // px, or "10%" of background width
Y?: number | string; // px, or "10%" of background height
position?: Position; // takes precedence if set
}
enum Position {
topLeft, topCenter, topRight,
bottomLeft, bottomCenter, bottomRight,
center,
}interface TextOptions {
text: string;
position?: PositionOptions;
style?: TextStyle;
}interface TextStyle {
color?: string; // CSS hex (#RGB, #RGBA, #RRGGBB, #RRGGBBAA)
fontName?: string;
fontSize?: number; // px / pt / sp
shadowStyle?: ShadowLayerStyle | null;
textBackgroundStyle?: TextBackgroundStyle | null;
underline?: boolean;
strikeThrough?: boolean;
textAlign?: 'left' | 'center' | 'right';
italic?: boolean;
bold?: boolean;
skewX?: number; // degrees, alternative to italic
rotate?: number; // degrees around anchor
}A filled (optionally rounded) rectangle drawn behind the text.
interface TextBackgroundStyle extends Padding {
type?: 'stretchX' | 'stretchY' | 'fit'; // default 'fit'
color: string;
cornerRadius?: CornerRadius;
}Padding is CSS-like — any of these forms work:
{ padding: 10 }
{ padding: '10%' }
{ padding: '10 20' }
{ padding: '10% 20 30 40' }
{ paddingHorizontal: 12, paddingVertical: 8 }
{ paddingX: 12, paddingY: 8 }
{ paddingLeft: 8, paddingRight: 4, paddingTop: 2, paddingBottom: 2 }CornerRadius accepts per-corner or an all shorthand:
{
cornerRadius: {
topLeft: { x: 8, y: 8 },
topRight: { x: 8, y: 8 },
all: { x: 4, y: 4 }, // applies to corners not set above
}
}interface ShadowLayerStyle {
dx: number;
dy: number;
radius: number;
color: string;
}- Coordinates are expressed in pixels of the background image (after any
maxSizedownscaling).'10%'values are resolved relative to the parent dimension (width forX/horizontal padding, height forY/vertical padding). - The default outer margin used by the enum
Positionvalues is20px. - On Web the output is always a
data:URI (the browser has no file system to write to). ThesaveFormatstill controls MIME type (PNG vs JPEG). - iOS uses
UIGraphicsImageRenderer; Android usesBitmap+Canvas; Web uses<canvas>2D.