cloudflare / cloudflare/workers-sdk

🐛 BUG: Local Images binding ignores EXIF orientation - photos render sideways in local dev

Open Beginner friendly
#15,029 1 comment 0 reactions 0 assignees View on GitHub
package:miniflare
Dominant language
TypeScript
Stars
4.5k
Forks
1.5k
Avg merge
3d 8h
Merged PRs (30d)
186

Description

### Which Cloudflare product(s) does this pertain to?

Miniflare

### What versions are you using?

miniflare 4.20260730.0 (also present on `main` at time of filing)

### What operating system and version are you using?

Windows 11 (reproduces on all platforms)

### Describe the Bug

**Observed behavior**

The local (low-fidelity) Images binding polyfill does not apply EXIF orientation before transforming. Photos taken on phones (commonly stored as landscape pixels + EXIF `Orientation: 6`) come back sideways from `env.IMAGES.input(...).transform(...)` in local dev.

In production, the Images binding auto-applies EXIF orientation before transforms, so the same code produces upright images when deployed. This is a local/production fidelity gap that makes phone photos appear rotated 90° only in local dev.

Related: #14795 fixed the `fit`/`gravity`/`background` handling in the same code path (thanks!). Before that fix this bug presented as *sideways + black letterbox bars*; after it, images are still sideways.

**Where it happens**

In `packages/miniflare/src/plugins/images/fetcher.ts`, both local fetchers construct sharp without EXIF auto-orientation:

- `imagesLocalFetcher`: `const transformer = sharp(await body.arrayBuffer(), {});`
- `cfImageLocalFetcher`: `const transformer = sharp(source);`

`runTransform` only applies an *explicit* `transform.rotate` value; a parameterless EXIF-based rotation is never applied.

**Expected behavior**

The local binding should match production and orient images per their EXIF flag before applying user transforms. Since miniflare already depends on sharp 0.35.x, this is a one-line-per-fetcher fix:

```ts
sharp(await body.arrayBuffer(), { autoOrient: true })
```

(`autoOrient` bakes the EXIF rotation into pixels at decode and clears the orientation flag; an explicit user `rotate` then composes on top with production-matching semantics.)

**Downstream impact**

Any framework whose dev server routes image optimization through the local binding shows user photos sideways in dev but correct in production. Concretely: Astro's `@astrojs/cloudflare` adapter serves `/_image` through `env.IMAGES` in `astro dev`, so any EXIF-rotated photo renders sideways locally — this is how I found the bug.

### Please provide a link to a minimal reproduction

See steps below — the repro is a few lines in any Worker with an `images` binding.

### Steps to reproduce

1. Create a Worker with an `images` binding and this handler:

```ts
export default {
async fetch(request, env) {
const src = await fetch("https://github.com/recurser/exif-orientation-examples/raw/master/Portrait_6.jpg");
const result = await env.IMAGES.input(src.body)
.transform({ width: 300 })
.output({ format: "image/jpeg" });
return result.response();
},
};
```

2. `wrangler dev` (local): the image is sideways.
3. `wrangler dev --remote` or deploy: the image is upright.

### Please provide any relevant error logs

No errors are logged; the transform succeeds but produces incorrectly oriented output.

Contributor guide

Open the contributing guide

Research direction

Start in packages/miniflare/src/plugins/images/fetcher.ts and inspect imagesLocalFetcher, cfImageLocalFetcher, and runTransform. Reproduce the issue with the provided Portrait_6.jpg Worker example, then verify that local output is upright for EXIF-oriented images and that explicit rotate transforms still compose correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.