Image Transformations via Pages Function doesn't seem to work

I'm trying to implement CF Image Transformations through workers (in my case, a Pages Function), but the image does not seem to get transformed. According to the troubleshooting page, the response should contain the Cf-Resized header, but it does not. - The feature is enabled in my cloudflare account - There shouldn't be any other workers running on the same request - The feature is enabled in the correct zone (dashboard > Images > Transformations > <my-domain.com> is enabled, and even "Resize from any origin" is checked even though that shouldn't be needed for workers. - Source image is publicly reachable (it's in my R2 bucket) - Worker is compiling correctly and being hit on the correct route and returning the right image, just not transformed - The pages project is running on v2.my-domain.com which is a custom domain for the production builds of the pages project My worker code is quite simple, a slightly modified version of the docs' example, some checks trimmed away to fit this ticket:
export async function onRequestGet({ request, env }) {

let options = { cf: { image: {} } };

const imageURL = `${env.S3_PUBLIC_HOST}${url.searchParams.get("image")}`;
const size = url.searchParams.get("size");

switch (size) {
case "small": options.cf.image.width = 400; break;
case "medium": options.cf.image.width = 600; break;
default:
return new Response('Disallowed size', { status: 400 });
}

options.cf.image.quality = 80;
options.cf.image.fit = 'scale-down';
options.cf.image.metadata = 'copyright';

const accept = request.headers.get("Accept");
if (/image\/webp/.test(accept)) {
options.cf.image.format = 'webp';
} else {
options.cf.image.format = 'jpg';
}

const imageRequest = new Request(imageURL, {
headers: request.headers,
});

return fetch(imageRequest, options);
}
export async function onRequestGet({ request, env }) {

let options = { cf: { image: {} } };

const imageURL = `${env.S3_PUBLIC_HOST}${url.searchParams.get("image")}`;
const size = url.searchParams.get("size");

switch (size) {
case "small": options.cf.image.width = 400; break;
case "medium": options.cf.image.width = 600; break;
default:
return new Response('Disallowed size', { status: 400 });
}

options.cf.image.quality = 80;
options.cf.image.fit = 'scale-down';
options.cf.image.metadata = 'copyright';

const accept = request.headers.get("Accept");
if (/image\/webp/.test(accept)) {
options.cf.image.format = 'webp';
} else {
options.cf.image.format = 'jpg';
}

const imageRequest = new Request(imageURL, {
headers: request.headers,
});

return fetch(imageRequest, options);
}
12 Replies
Martijn
Martijn•6mo ago
So to clarify, requests to this worker "work" as in it successfully responds with the original image, but it's just not transformed at all (no matter the size I pass), and it does not have the Cf-Resized response header. Here's an example path I use: my-domain.com/api/gallery/?image=gallery%2Fmy-dir%2FIMG_0655.jpg&size=large
Chaika
Chaika•6mo ago
The fetch options are never going to work with functions due to the fact even on Custom Domains the function still "runs" on your pages.dev, which Image Resizing isn't enabled on You have to use either the URL Format or an actual worker proxying the requests
Martijn
Martijn•6mo ago
Alright, that makes sense. Thanks for clarifying. With the URL, there's no way for me to limit which format, and even because they are hosted on "remote" R2 bucket (as opposed to inside CF Images Storage), I'm not able to limit which external images can be transformed, right?
Chaika
Chaika•6mo ago
What do you mean "limit formats"? There's a format (webp, jpg, etc) option in the url format.
because they are hosted on "remote" R2 bucket (as opposed to inside CF Images Storage), I'm not able to limit which external images can be transformed, right?
Use an R2 Custom Domain on the same zone/domain as you are transforming from, and you can disable Resize from any Origin. You wouldn't use Image Resizing with CF Image storage anyway, the "resize from any origin" is just for subdomains/hostnames out of that domain
Martijn
Martijn•6mo ago
My R2 is indeed on custom domain assets.my-domain.com. Is that considered inside the zone? Can I uncheck the "resize from any origin"? And with limit formats I meant widths etc. A malicious actor could theoretically request many different widths and image formats to rack up my bill with the URL Format method?
Chaika
Chaika•6mo ago
My R2 is indeed on custom domain assets.my-domain.com. Is that considered inside the zone?
a "zone" in cloudflare is anything under the websites tab. If you use https://assets.my-domain.com/cdn-cgi/image/options the yea you could resize assets.my-domain without resize from any origin. Workers are also entirely immune from that setting
Chaika
Chaika•6mo ago
And with limit formats I meant widths etc. A malicious actor could theoretically request many different widths and image formats to rack up my bill with the URL Format method?
Either a Worker, or you could maybe hack something together using transform rules: https://developers.cloudflare.com/images/transform-images/serve-images-custom-paths/#serve-images-from-custom-paths, which modify the path server-side. Could maybe do something like https://assets.my-domain/special-pathlarge/images/<image-url> and substring out the source path and force specific settings
Cloudflare Docs
Serve images from custom paths · Cloudflare Image Optimization docs
You can use Transform Rules to rewrite URLs for every image that you transform through Images.
Martijn
Martijn•6mo ago
Alright, much appreciate the help Chaika!
Chaika
Chaika•6mo ago
Sure, hopefully one day you'll be able to just use image resizing with your functions the api might actually accept your pages.dev as a zone to enable resizing on even if the ui doesn't show it, not sure, but wouldn't be a supported action I imagine lol
Martijn
Martijn•6mo ago
Yeah, since the differences in what you can do with them are subtle but significant, I often struggle.
Chaika
Chaika•6mo ago
yeaaaa they're still working on convergence and hopefully one day cutting down on those differences and just having one product
Martijn
Martijn•6mo ago
I won't be the one to try this 😅
Want results from more Discord servers?
Add your server