Skip to content

fix: normalize color space for consistent pixel values in nativeImage - #48178

Merged
jkleinsc merged 12 commits into
electron:mainfrom
felixrieseberg:felixr/native-image-color-normalization
May 8, 2026
Merged

jkleinsc merged 12 commits into
electron:mainfrom
felixrieseberg:felixr/native-image-color-normalization

Conversation

@felixrieseberg

@felixrieseberg felixrieseberg commented Aug 27, 2025 •

Copy link
Copy Markdown
Member

Description of Change

This PR normalizes color space so that pixel values in nativeImage match if they do match visually to the user. I am not entirely sure whether we actually want this - a priori, I think this feels correct but I'm happy to be corrected.

Closes #46949

Checklist

Release Notes

Notes: fix: If a nativeImage was passed an image with a color profile, its pixel values will now be normalized to SRGB. This ensures that two visually identical images after color space application will receive similar pixel values when converted to a nativeImage.

@electron-cation electron-cation Bot added the new-pr 🌱 PR opened recently label Aug 27, 2025
@nikwen

nikwen commented Aug 27, 2025

Copy link
Copy Markdown
Member

We might want to consider this a breaking change, just to make sure we don't break any apps relying on the old behavior.

@felixrieseberg
felixrieseberg force-pushed the felixr/native-image-color-normalization branch from 1445729 to 75f0685 Compare August 28, 2025 19:30
@felixrieseberg

Copy link
Copy Markdown
Member Author

I'll let @reitowo decide! I think breaking change seems reasonable

@codebytere codebytere left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conceptually LGTM - i'm leaving semver-major for this as well.

Comment thread spec/api-native-image-spec.ts Resolved
Comment thread spec/api-native-image-spec.ts Resolved
@electron-cation electron-cation Bot removed the new-pr 🌱 PR opened recently label Sep 3, 2025
@felixrieseberg
felixrieseberg force-pushed the felixr/native-image-color-normalization branch from 75f0685 to cb2e462 Compare January 24, 2026 19:02
@felixrieseberg

Copy link
Copy Markdown
Member Author

It only took me forever but I have integrated all feedback and rebased!

@reitowo reitowo left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API LGTM with a minor nit suggestion

Comment thread spec/api-native-image-spec.ts Resolved
Comment thread docs/api/native-image.md Resolved
Comment thread docs/api/native-image.md Resolved
Comment thread docs/api/native-image.md Resolved

@samuelmaddock samuelmaddock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API LGTM

Open to include nativeImage.getColorSpace in this PR or separate as per @reitowo's feedback.

Will approve once tests are passing.

Comment thread docs/api/native-image.md Resolved
Comment thread docs/api/native-image.md Resolved
@felixrieseberg
felixrieseberg requested a review from a team as a code owner February 9, 2026 03:29
@reitowo

reitowo commented Feb 25, 2026

Copy link
Copy Markdown
Member

I think this is ready for merge?

@ckerr
ckerr force-pushed the felixr/native-image-color-normalization branch 3 times, most recently from 983322a to 69a031e Compare March 23, 2026 17:31

@jkleinsc jkleinsc left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should update the breaking changes to either 42 or 43 depending upon whether or not we want this to land in 42 or 43. I'm fine with it going into 42.

felixrieseberg and others added 9 commits April 28, 2026 11:33
toBitmap() now normalizes the color space to sRGB by default, ensuring
that visually identical images produce consistent pixel values regardless
of their original color profile (e.g., Display P3 on macOS).

An optional colorSpace parameter is added to toBitmap() to control the
target color space: 'srgb' (default), 'display-p3', or 'source' (no
conversion).

Closes electron#46949
Sort ui/gfx/ includes alphabetically: codec/jpeg_codec.h,
codec/png_codec.h, then color_space.h.
- Add breaking-changes.md entry for toBitmap() color space
  normalization under Planned Breaking API Changes (41.0)
- Update getBitmap() docs to include colorSpace option and
  breaking-changes-header since it delegates to toBitmap()
Regenerate the colorspace-srgb.png and colorspace-p3.png test fixtures
so they represent the same visual color encoded in two different source
color spaces. The updated sRGB fixture stores the color as sRGB pixel
values, while the Display P3 fixture stores the corresponding Display P3
pixel values and retains its embedded P3 ICC profile.

Even though the source bitmaps can contain different bytes, their outputs
should be byte-identical after normalization to the sRGB color space.
@ckerr
ckerr force-pushed the felixr/native-image-color-normalization branch from da8835a to a4bb37c Compare April 28, 2026 16:41
@ckerr

ckerr commented Apr 28, 2026

Copy link
Copy Markdown
Member

We should update the breaking changes to either 42 or 43 depending upon whether or not we want this to land in 42 or 43. I'm fine with it going into 42.

I think I'd be OK with 42 if anyone feels strongly about it, but -- since it's a month later now -- it feels a little late in the cycle?

I've pushed two changes up to unblock this PR:

  • updated breaking-changes.md to put this change in 43.0 to address @jkleinsc's change request
  • rebased to main

@ckerr
ckerr requested a review from jkleinsc April 28, 2026 16:43
@jkleinsc jkleinsc added target/43-x-y PR should also be added to the "43-x-y" branch. and removed no-backport labels May 7, 2026
@jkleinsc
jkleinsc merged commit 0e354e8 into electron:main May 8, 2026
69 checks passed
@release-clerk

release-clerk Bot commented May 8, 2026

Copy link
Copy Markdown

Release Notes Persisted

fix: If a nativeImage was passed an image with a color profile, its pixel values will now be normalized to SRGB. This ensures that two visually identical images after color space application will receive similar pixel values when converted to a nativeImage.

@trop

trop Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

I have automatically backported this PR to "43-x-y", please check out #51565

@trop trop Bot added in-flight/43-x-y and removed target/43-x-y PR should also be added to the "43-x-y" branch. labels May 8, 2026
ckerr pushed a commit that referenced this pull request May 8, 2026
…#51565)

fix: normalize color space for consistent pixel values in nativeImage (#48178)

* fix: normalize color space for consistent pixel values in nativeImage

toBitmap() now normalizes the color space to sRGB by default, ensuring
that visually identical images produce consistent pixel values regardless
of their original color profile (e.g., Display P3 on macOS).

An optional colorSpace parameter is added to toBitmap() to control the
target color space: 'srgb' (default), 'display-p3', or 'source' (no
conversion).

Closes #46949

* fix: implement feedback

* fix: correct include ordering in electron_api_native_image.cc

Sort ui/gfx/ includes alphabetically: codec/jpeg_codec.h,
codec/png_codec.h, then color_space.h.

* docs: add breaking-changes entry and update getBitmap docs

- Add breaking-changes.md entry for toBitmap() color space
  normalization under Planned Breaking API Changes (41.0)
- Update getBitmap() docs to include colorSpace option and
  breaking-changes-header since it delegates to toBitmap()

* docs: linter: remove semicolons from js code samples

* docs: linter: make change description <= 120 chars

* test: fix new colorSpace spec

* test: regenerate nativeImage color-space PNG fixtures

Regenerate the colorspace-srgb.png and colorspace-p3.png test fixtures
so they represent the same visual color encoded in two different source
color spaces. The updated sRGB fixture stores the color as sRGB pixel
values, while the Display P3 fixture stores the corresponding Display P3
pixel values and retains its embedded P3 ICC profile.

Even though the source bitmaps can contain different bytes, their outputs
should be byte-identical after normalization to the sRGB color space.

* docs: marked breaking change for 43.0

* chore: fix up for lint

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Felix Rieseberg <f@anthropic.com>
@trop trop Bot added merged/43-x-y PR was merged to the "43-x-y" branch. and removed in-flight/43-x-y labels May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

44-x-y api-review/approved ✅ merged/43-x-y PR was merged to the "43-x-y" branch. semver/major incompatible API changes

Projects

No open projects
Status: No status

Development

Successfully merging this pull request may close these issues.

nativeImage.toBitmap() doesn't preserve color matrix / color space information.

9 participants