Describe the bug
JPEG files exported from darktable show inconsistent color rendering in Apple Photos on iPhone, iPad, and macOS:
- Thumbnail / list-view preview: image appears flat and desaturated (colors roughly 20–30% less saturated than intended)
- Zoomed / full-resolution view: image appears correctly saturated
The same image exported as TIFF renders correctly in both views. The behavior is reproducible across multiple Apple devices (iOS 17 / iPadOS 17 / macOS 14).
Root cause (forensically confirmed)
darktable's JPEG exporter sets in_color_space = JCS_RGB and calls jpeg_set_defaults(), which causes libjpeg to automatically write a JFIF APP0 marker (FF E0) into every exported JPEG.
Apple Photos uses two separate render paths:
- Thumbnail/preview path: sees JFIF → treats YCbCr data as "JFIF-managed" → skips ICC color management → sRGB pixel values are displayed on a Display P3 screen without sRGB→P3 conversion → image appears flat/desaturated
- Full-resolution zoom path: performs a complete decode, reads the ICC APP2 profile, converts sRGB → Display P3 correctly → image appears correctly saturated
Binary analysis of the exported file confirms:
Marker sequence (darktable JPEG):
0x0000 SOI
0x0002 APP0 JFIF v1.01 ← triggers Apple's JFIF path
0x000E APP1 EXIF (22 KB)
0x5968 APP1 XMP (36 KB)
0xEA95 APP2 ICC_PROFILE ← arrives ~60 KB into the file
... DQT, SOF0, DHT, SOS
The ICC APP2 segment ends up unusually late because darktable first writes the JPEG via libjpeg (ICC is written early), then exiv2 rewrites the entire file to inject EXIF/XMP, pushing ICC after the large EXIF block (src/imageio/format/jpeg.c:288).
Key evidence:
- darktable JPEG and a GIMP re-export of the same image both have JFIF → both show identical split behavior
- TIFF export (no JFIF) renders correctly in both Apple Photos views ✅
- Removing only the JFIF marker with ExifTool (
exiftool -JFIF:all= file.jpg) makes both views render correctly
- The ICC profile content is not the cause — the Windows sRGB v2 profile produces the same flat preview
Exif.Photo.ColorSpace = 1 (sRGB) is present and correct but does not affect the behavior
Steps to reproduce
- Open any RAW file in darktable
- Export as JPEG with sRGB output profile (default settings)
- Transfer the JPEG to an iPhone/iPad (iOS 16+) or view in Apple Photos on macOS 13+
- Observe: thumbnail/list view appears flat and desaturated
- Tap/zoom into the image: colors become correctly saturated
Expected behavior
darktable should produce JPEG files that render with consistent color in both thumbnail and full-resolution views in Apple Photos, matching the appearance of TIFF exports.
Proposed fix
In src/imageio/format/jpeg.c, suppress the JFIF header after jpeg_set_defaults():
jpeg_set_defaults(&(jpg->cinfo));
jpg->cinfo.write_JFIF_header = FALSE; // ICC APP2 provides all color information
write_JFIF_header is a public field of jpeg_compress_struct (libjpeg/libjpeg-turbo API). Setting it FALSE after jpeg_set_defaults() and before jpeg_start_compress() suppresses the APP0 marker. All colorimetric information is already in the ICC APP2 segment. Resolution information is already written to Exif.Image.XResolution/YResolution by the exiv2 pass (src/common/exif.cc:3062–3064), so no metadata is lost.
Risk: Minimal. All modern decoders (browsers, Photoshop, Lightroom, Apple, Android) use EXIF for resolution. Only pre-2000 JFIF-only decoders would be affected.
Workaround (until patch is available)
Strip the JFIF marker with ExifTool after export:
exiftool -JFIF:all= -overwrite_original exported.jpg
Evidence files
Three files from the same source RAW, tested on multiple Apple devices:
| File |
Apple Photos preview |
Apple Photos zoom |
| darktable JPEG (sRGB) |
flat / desaturated |
correctly saturated |
| GIMP re-export of same JPEG |
flat / desaturated |
correctly saturated |
| darktable TIFF (sRGB) |
correctly saturated ✅ |
correctly saturated ✅ |
darktable version
5.6.0 (commit cfcb13c)
Source locations
src/imageio/format/jpeg.c:202–203 — in_color_space = JCS_RGB + jpeg_set_defaults() triggers JFIF
src/imageio/format/jpeg.c:255 — jpeg_start_compress(&cinfo, TRUE) — TRUE = write all markers
src/imageio/format/jpeg.c:288 — exiv2 rewrites file after compression (causes late ICC position)
src/common/colorspaces.c:1485 — sRGB v2 output profile registration
Additional context
- Reproducible across multiple iPhones, iPads, and MacBooks
- PNG exports have a related but separate issue: the
cICP chunk written by src/imageio/format/png.c causes Apple Photos to render flat in both preview and zoom (separate issue)
Describe the bug
JPEG files exported from darktable show inconsistent color rendering in Apple Photos on iPhone, iPad, and macOS:
The same image exported as TIFF renders correctly in both views. The behavior is reproducible across multiple Apple devices (iOS 17 / iPadOS 17 / macOS 14).
Root cause (forensically confirmed)
darktable's JPEG exporter sets
in_color_space = JCS_RGBand callsjpeg_set_defaults(), which causes libjpeg to automatically write a JFIF APP0 marker (FF E0) into every exported JPEG.Apple Photos uses two separate render paths:
Binary analysis of the exported file confirms:
The ICC APP2 segment ends up unusually late because darktable first writes the JPEG via libjpeg (ICC is written early), then exiv2 rewrites the entire file to inject EXIF/XMP, pushing ICC after the large EXIF block (
src/imageio/format/jpeg.c:288).Key evidence:
exiftool -JFIF:all= file.jpg) makes both views render correctlyExif.Photo.ColorSpace = 1 (sRGB)is present and correct but does not affect the behaviorSteps to reproduce
Expected behavior
darktable should produce JPEG files that render with consistent color in both thumbnail and full-resolution views in Apple Photos, matching the appearance of TIFF exports.
Proposed fix
In
src/imageio/format/jpeg.c, suppress the JFIF header afterjpeg_set_defaults():write_JFIF_headeris a public field ofjpeg_compress_struct(libjpeg/libjpeg-turbo API). Setting itFALSEafterjpeg_set_defaults()and beforejpeg_start_compress()suppresses the APP0 marker. All colorimetric information is already in the ICC APP2 segment. Resolution information is already written toExif.Image.XResolution/YResolutionby the exiv2 pass (src/common/exif.cc:3062–3064), so no metadata is lost.Risk: Minimal. All modern decoders (browsers, Photoshop, Lightroom, Apple, Android) use EXIF for resolution. Only pre-2000 JFIF-only decoders would be affected.
Workaround (until patch is available)
Strip the JFIF marker with ExifTool after export:
Evidence files
Three files from the same source RAW, tested on multiple Apple devices:
darktable version
5.6.0 (commit cfcb13c)
Source locations
src/imageio/format/jpeg.c:202–203—in_color_space = JCS_RGB+jpeg_set_defaults()triggers JFIFsrc/imageio/format/jpeg.c:255—jpeg_start_compress(&cinfo, TRUE)— TRUE = write all markerssrc/imageio/format/jpeg.c:288— exiv2 rewrites file after compression (causes late ICC position)src/common/colorspaces.c:1485— sRGB v2 output profile registrationAdditional context
cICPchunk written bysrc/imageio/format/png.ccauses Apple Photos to render flat in both preview and zoom (separate issue)