Watermarks
Draw a watermark from KV on an image from R2
Enable Workers Cache so repeat requests for the same watermarked image are served from cache without re-running the Worker or re-transforming the image:
{ "cache": { "enabled": true, },}[cache]enabled = trueThen set Cache-Control headers on your response to control the cache lifetime:
export default { async fetch(request, env) { const watermarkKey = "my-watermark"; const sourceKey = "my-source-image";
const watermark = await env.NAMESPACE.get(watermarkKey, "stream"); const source = await env.BUCKET.get(sourceKey);
if (!watermark || !source) { return new Response("Not found", { status: 404 }); }
const result = await env.IMAGES.input(source.body) .draw(watermark) .output({ format: "image/jpeg" });
const response = result.response();
return new Response(response.body, { headers: { ...Object.fromEntries(response.headers), "Cache-Control": "public, max-age=3600, stale-while-revalidate=86400", }, }); },};interface Env { BUCKET: R2Bucket; NAMESPACE: KVNamespace; IMAGES: ImagesBinding;}export default { async fetch(request, env): Promise<Response> { const watermarkKey = "my-watermark"; const sourceKey = "my-source-image";
const watermark = await env.NAMESPACE.get(watermarkKey, "stream"); const source = await env.BUCKET.get(sourceKey);
if (!watermark || !source) { return new Response("Not found", { status: 404 }); }
const result = await env.IMAGES.input(source.body) .draw(watermark) .output({ format: "image/jpeg" });
const response = result.response();
return new Response(response.body, { headers: { ...Object.fromEntries(response.headers), "Cache-Control": "public, max-age=3600, stale-while-revalidate=86400", }, }); },} satisfies ExportedHandler<Env>;