Describe the Bug
A collection has upload: { focalPoint: true } and no imageSizes. The focal point is then only a pair of numbers on the document, which the front end uses to place the image. No stored file depends on it.
A save from the admin's "Edit Image" tool still reads the stored file and writes it back, with the same bytes, under the same name. This happens when the focal point moved, and also when nothing moved. With a storage adapter, each such save is a download and an upload, and the stored object gets a new upload time.
Two things cause it, both in packages/payload/src/uploads/generateFileData.ts:
shouldReupload answers yes for any crop and for any focal point that differs from the stored one. It does not look at what the collection does with them.
- The admin always sends a crop with the focal point, a crop of the whole picture:
uploadEdits[crop][width]=100, [height]=100, [x]=0, [y]=0. So shouldReupload answers yes on every save from "Edit Image".
The rewrite is not needed. The same focal point change, sent as focalX and focalY in the body with no uploadEdits, is stored and leaves the file untouched.
Expected: with no image sizes and a crop of the whole picture, a focal point change updates focalX and focalY and leaves the stored file alone.
Related:
Link to the code that reproduces this issue
https://github.com/franknoel/payload-focal-point-rewrite
Reproduction Steps
- Clone the repository.
cp .env.example .env, then fill in DATABASE_URL and PAYLOAD_SECRET.
pnpm install
pnpm check
The script empties the Media collection, uploads a JPEG with the local API, saves four updates, and shows which of them write the stored file again. The second and third updates send the query that the admin sends:
untouched same bytes focal point 50,50 alt text only
REWRITTEN same bytes focal point 50,50 Edit Image, nothing moved
REWRITTEN same bytes focal point 20,30 Edit Image, focal point moved
untouched same bytes focal point 70,80 focal point in the body, no Edit Image
In the admin:
pnpm dev, create the first user, upload fixtures/photo.jpg in Media.
- Note the modification time of
media/photo.jpg.
- Open the document, "Edit Image", change "X %" and "Y %", "Apply Changes", "Save".
- The modification time of
media/photo.jpg has changed. The file has the same bytes.
The request of step 3:
PATCH /api/media/<id>?depth=0&fallback-locale=null&uploadEdits[crop][height]=100&uploadEdits[crop][unit]=%&uploadEdits[crop][width]=100&uploadEdits[crop][x]=0&uploadEdits[crop][y]=0&uploadEdits[focalPoint][x]=25&uploadEdits[focalPoint][y]=35&uploadEdits[heightInPixels]=800&uploadEdits[widthInPixels]=1200
Which area(s) are affected?
area: core, area: ui
Environment Info
Binaries:
Node: 24.21.0
npm: 11.19.0
Yarn: 1.22.22
pnpm: 9.15.9
Relevant Packages:
payload: 3.90.2
next: 16.3.3
@payloadcms/db-mongodb: 3.90.2
@payloadcms/graphql: 3.90.2
@payloadcms/next/utilities: 3.90.2
@payloadcms/richtext-lexical: 3.90.2
@payloadcms/translations: 3.90.2
@payloadcms/ui/shared: 3.90.2
react: 19.2.6
react-dom: 19.2.6
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 25.6.0
Available memory (MB): 32768
Available CPU cores: 10
Describe the Bug
A collection has
upload: { focalPoint: true }and noimageSizes. The focal point is then only a pair of numbers on the document, which the front end uses to place the image. No stored file depends on it.A save from the admin's "Edit Image" tool still reads the stored file and writes it back, with the same bytes, under the same name. This happens when the focal point moved, and also when nothing moved. With a storage adapter, each such save is a download and an upload, and the stored object gets a new upload time.
Two things cause it, both in
packages/payload/src/uploads/generateFileData.ts:shouldReuploadanswers yes for any crop and for any focal point that differs from the stored one. It does not look at what the collection does with them.uploadEdits[crop][width]=100,[height]=100,[x]=0,[y]=0. SoshouldReuploadanswers yes on every save from "Edit Image".The rewrite is not needed. The same focal point change, sent as
focalXandfocalYin the body with nouploadEdits, is stored and leaves the file untouched.Expected: with no image sizes and a crop of the whole picture, a focal point change updates
focalXandfocalYand leaves the stored file alone.Related:
shouldReupload, so that a change of another field no longer fetches the file.Link to the code that reproduces this issue
https://github.com/franknoel/payload-focal-point-rewrite
Reproduction Steps
cp .env.example .env, then fill inDATABASE_URLandPAYLOAD_SECRET.pnpm installpnpm checkThe script empties the Media collection, uploads a JPEG with the local API, saves four updates, and shows which of them write the stored file again. The second and third updates send the query that the admin sends:
In the admin:
pnpm dev, create the first user, uploadfixtures/photo.jpgin Media.media/photo.jpg.media/photo.jpghas changed. The file has the same bytes.The request of step 3:
Which area(s) are affected?
area: core, area: ui
Environment Info