1+ import fs from 'node:fs/promises' ;
2+ import path from 'node:path' ;
13import sharp from 'sharp' ;
24import type { Blend } from './enumerations' ;
35
6+ const FONT_PATH = path . resolve ( process . cwd ( ) , 'public/fonts/Inter-Bold.woff2' ) ;
7+
8+ /** Module-level singleton so the file is only read once per process. */
9+ let _fontDataUri : Promise < string > | null = null ;
10+
11+ const getFontDataUri = ( ) : Promise < string > => {
12+ if ( ! _fontDataUri ) {
13+ _fontDataUri = fs
14+ . readFile ( FONT_PATH )
15+ . then ( ( buf ) => `data:font/woff2;base64,${ buf . toString ( 'base64' ) } ` )
16+ . catch ( ( ) => {
17+ // Font file missing — fall back to generic family names and hope
18+ // for the best. Log a warning so this is visible in prod logs.
19+ console . warn (
20+ '[watermark] Inter-Bold.woff2 not found at' ,
21+ FONT_PATH ,
22+ '— text may be invisible in environments without system fonts.'
23+ ) ;
24+ return '' ;
25+ } ) ;
26+ }
27+ return _fontDataUri ;
28+ } ;
29+
430export interface WatermarkProps {
531 text ?: string ;
632 fontSize ?: number ;
@@ -68,6 +94,13 @@ export const applyWatermark = async (buffer: Buffer, props: WatermarkProps): Pro
6894 margin = 48
6995 } = props ;
7096
97+ // Resolve the embedded font once (cached after first call).
98+ const fontDataUri = await getFontDataUri ( ) ;
99+ const fontFamilyName = fontDataUri ? 'WatermarkFont' : 'sans-serif' ;
100+ const fontFaceBlock = fontDataUri
101+ ? `<defs><style>@font-face{font-family:'WatermarkFont';src:url('${ fontDataUri } ') format('woff2');font-weight:700;}</style></defs>`
102+ : '' ;
103+
71104 const metadata = await sharp ( buffer ) . metadata ( ) ;
72105
73106 const width = metadata . width ?? 1000 ;
@@ -89,7 +122,7 @@ export const applyWatermark = async (buffer: Buffer, props: WatermarkProps): Pro
89122 fill="${ color } "
90123 fill-opacity="${ opacity } "
91124 font-size="${ fontSize } "
92- font-family="sans-serif "
125+ font-family="${ fontFamilyName } "
93126 font-weight="700"
94127 stroke="#000000"
95128 stroke-opacity="${ opacity * 0.35 } "
@@ -108,6 +141,7 @@ export const applyWatermark = async (buffer: Buffer, props: WatermarkProps): Pro
108141 width="${ width } "
109142 height="${ height } "
110143 >
144+ ${ fontFaceBlock }
111145 ${
112146 tiled
113147 ? repeatedWatermarks
@@ -118,7 +152,7 @@ export const applyWatermark = async (buffer: Buffer, props: WatermarkProps): Pro
118152 fill="${ color } "
119153 fill-opacity="${ opacity } "
120154 font-size="${ fontSize } "
121- font-family="sans-serif "
155+ font-family="${ fontFamilyName } "
122156 font-weight="700"
123157 stroke="#000000"
124158 stroke-opacity="${ opacity * 0.35 } "
0 commit comments