Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

[Bug]: Image editor silently writes PNG data into .JPG files (uppercase extension breaks canvas.toBlob MIME)

Open Beginner friendly
#3,424 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

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

Research direction

Start in src/components/ImageEditor.vue, especially defaultSavedImageType() and onSave(), then trace how the Save image as dialog handles the format field. Reproduce with an uppercase .JPG image and inspect the encoded blob type before upload. Done when saving preserves JPEG bytes for uppercase extensions and mismatched encoded data is not silently uploaded.

Written by the indexing model from the issue text.

Description

Bug description

Editing a photo whose extension is uppercase .JPG in the built-in viewer image
editor corrupts the file: the stored bytes become PNG while the filename keeps its
.JPG extension.

Observed on Nextcloud 32.0.14.1, viewer 5.0.0, Chrome 155:

before after "Speichern" (save)
content type image/jpeg image/png
size 2 865 024 B 504 955 B
magic bytes FF D8 FF 89 50 4E 47

file on the server: PNG image data, 4320 x 3240, 8-bit/color RGBA.

The upload itself succeeds (PUT /remote.php/dav/files/<user>/<path>.JPG → 204),
so there is no indication anything went wrong.

Steps to reproduce
  1. Upload a JPEG with an uppercase extension (e.g. ABC1234.JPG — the default
    export of many cameras).
  2. Open it in the viewer (/apps/files/... → click the file), press Ctrl+E
    (or open with ?editing=true) so the image editor opens.
  3. Apply any change (e.g. Filters → Black & White).
  4. Click Save → Save image as dialog appears → Save → confirm overwrite.
  5. Inspect the file server-side:
file data/<user>/files/ABC1234.JPG
# PNG image data, 4320 x 3240, 8-bit/color RGBA, non-interlaced
Expected behaviour

The file must still be a JPEG (or the user must be told the format changed).

Root cause

In src/components/ImageEditor.vue (viewer 5.0.0):

defaultSavedImageType() {
    return extname(this.decodedSourceName).slice(1) || 'jpeg'   // -> "JPG"
}

The extension is not lower-cased. The Filerobot editor then builds the MIME
type from it ('image/' + (ext === 'jpg' ? 'jpeg' : ext)) → image/JPG.

onSave() only normalises case-sensitively:

mimeType = mimeType.replace('jpg', 'jpeg')      // no-op for "image/JPG"
...
const blob = await new Promise(resolve => imageCanvas.toBlob(resolve, mimeType, quality))
const response = await axios.put(putUrl, new File([blob], fullName))

HTMLCanvasElement.toBlob() falls back to image/png for an unknown MIME type
(per spec: "if type is not a supported image format, use image/png"), so PNG
bytes are uploaded under the original .JPG name. The File's name is also not
checked against blob.type.

Consequences seen in the wild:

  • PNG files that are 5–15× larger than the JPEG they replace (a 15 MB PNG was
    written over a 1.4 MB JPEG in a user report).
  • Metadata/EXIF is lost, so Memories date/time editing then fails with
    Could not set exif data: Error: Not a valid JPG (looks more like a PNG) (HTTP 500).
  • Previews, sync clients and third-party apps see a file whose extension lies
    about its content.
Suggested fix
defaultSavedImageType() {
    return (extname(this.decodedSourceName).slice(1) || 'jpeg').toLowerCase()
}

plus a defensive normalisation in onSave() (case-insensitive jpg → jpeg)
and, most importantly, a check after encoding:

if (blob.type !== mimeType) { showError(...); return }   // never upload mismatched bytes

Also worth lower-casing/validating the extension in the "Save image as" dialog
(format field), which currently keeps JPG as well.

Environment
  • Nextcloud 32.0.14.1, PHP 8.3.33, viewer 5.0.0 (default install)
  • Chrome 155, Linux
  • Affected files: any image with an uppercase .JPG/.JPEG/.PNG-style extension;
    lowercase .jpg is unaffected (image/jpeg works).
Dominant language
JavaScript
Stars
121
Forks
70
Avg merge
1d 3h
Merged PRs (30d)
18

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from nextcloud/viewer

All issues in nextcloud/viewer

Similar issues

More JavaScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.