bennycondon
bennycondon
CDCloudflare Developers
Created by bennycondon on 3/22/2023 in #workers-help
Generating images in Workers
I'm trying to generate an image in a Worker, and then store the image in an R2 bucket. My current approach (example code included below) was to: 1. Use the Canvas API to generate the image, 2. Use HTMLCanvasElement.toDataURL() and dataURItoBlob() to convert the image to a Blob, and then 3. Put the Blob in an R2 bucket. However, as document is not defined and the Canvas API is not supported (https://github.com/cloudflare/workerd/discussions/212), this approach does not work in Workers. Are there any other approaches I could try to achieve this in Workers?
interface Env {
BUCKET: R2Bucket;
}

export const onRequest: PagesFunction<Env> = async (context) => {
const canvas = document.createElement("canvas");

canvas.width = 200;
canvas.height = 200;

const ctx = canvas.getContext("2d");

if (ctx === null) {
return new Response(null, { status: 500 });
}

ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("text", canvas.width / 2, canvas.width / 2);

const dataUrl = canvas.toDataURL("image/jpeg");
const blobData = dataURItoBlob(dataUrl);

await context.env.BUCKET.put("my-image.jpeg", blobData);

return new Response(null, { status: 200 });
};

function dataURItoBlob(dataURI: string) {
const binary = Buffer.from(dataURI.split(",")[1], "base64").toString();
const array = [];

for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}

return new Blob([new Uint8Array(array)], { type: "image/jpeg" });
}
interface Env {
BUCKET: R2Bucket;
}

export const onRequest: PagesFunction<Env> = async (context) => {
const canvas = document.createElement("canvas");

canvas.width = 200;
canvas.height = 200;

const ctx = canvas.getContext("2d");

if (ctx === null) {
return new Response(null, { status: 500 });
}

ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("text", canvas.width / 2, canvas.width / 2);

const dataUrl = canvas.toDataURL("image/jpeg");
const blobData = dataURItoBlob(dataUrl);

await context.env.BUCKET.put("my-image.jpeg", blobData);

return new Response(null, { status: 200 });
};

function dataURItoBlob(dataURI: string) {
const binary = Buffer.from(dataURI.split(",")[1], "base64").toString();
const array = [];

for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}

return new Blob([new Uint8Array(array)], { type: "image/jpeg" });
}
8 replies