python-mss icon indicating copy to clipboard operation
python-mss copied to clipboard

Display Profile Color Correction

Open Snipeye opened this issue 4 years ago • 1 comments

General information:

  • OS name: _MacOS _
  • OS version: 10.14.6, but I anticipate it applies to newer versions
  • OS architecture: 64 bits
  • Resolutions:
    • Monitor 1: 1920x1200 screen resolution, screen is retina and sampled at 2x
  • Python version: 3.8.8
  • MSS version: 6.1.0

Description of the warning/error

When a capture (using .grab) in macOS, the resultant screenshot is modified according to the selected color profile. A picture of a pure #FF00FF color resulted in RGB values of [252 40 252] - this agrees with the system color profile tool:

image

A workaround is to set my profile to sRGB IEC61966-2.1, but even that results in some "corruption" ([251 0 255]). Is there a way we can reverse the color-correction? I think that CGImage has a link to the decode transform used to change color spaces? (https://developer.apple.com/documentation/coregraphics/cgimage/1454575-decode) but I'm not sure if that's what's being used under the hood for mss, I only stumbled on this today when looking for some fast image capture.

Full message

None

Other details

None

Snipeye avatar Oct 14 '21 04:10 Snipeye

You're correct that what you're seeing is due to macOS applying the display’s color profile — usually Display P3 on modern Macs. MSS just returns raw, untagged RGB values from the compositor, so without an ICC profile attached, those numbers have no defined color meaning.

That’s not technically “corruption,” just the expected result of capturing pixels that have already been color-managed for your display.

That said, I'm not really sure that reversing the conversion is always the best idea.

The values that MSS returns are just raw, untagged RGB values. Without a colorspace attached (like "Color LCD", which is more technically known as Display P3), you don't actually have information about what colors these represent. As you've observed, this can be a problem.

However, converting to an arbitrary colorspace, like sRGB, for MSS's output has its downsides too. For instance, suppose that you have a program that renders in a wide gamut: you might be using Photoshop, or viewing photos from the iPhone camera, for instance. Converting this to sRGB would mean that all the out-of-gamut colors that look so vivid on your monitor would be crushed.

There's also a question of how to do the adaptation. For instance, if the illuminants are different (like for DCI-P3), then you might want to choose between Bradford, von Kries, CAT02, etc. chromatic adaptations. Just doing that conversion on a system - like a Mac - that supports device contexts with a wide range of colorspaces, this can become very complex: take a look at the docs for the Colour library, or the information you can get back to describe a CGColorSpace, and it suddenly becomes a big deal. Mapping out-of-gamut colors also is a choice, the "rendering intent": you might want to do what the ICC calls absolute or relative colormetric (get the closest color you can), perceptual (preserve gradiations), saturation (for charts), etc. This depends a lot on the desired application, and is not something that the source acquisition library (MSS) can choose.

Some applications might not even care, or even prefer that you don't do the conversion. Colorspace conversion, at the very least, involves linearizing (removing gamma), performing a 4x4 (for RGBA) matrix multiplication, and then re-encode (re-apply gamma), for each pixel. Some applications might not like to do this: if you're training an AI, you don't want to take that performance hit: you don't care about the colorspace, as long as it's the same between training and inference. If you're saving to H.264/H.265/AV1/VP9 video, TIFF, JPEG, etc., you don't want both the performance hit and quantization loss, and instead tag your saved file with the correct colorspace.

Personally, I would feel that it would make more sense to tag the ScreenShot object with the colorspace being used, insofar as that can be determined: this might be, for instance, the ICC Profile (in ICC Profile Binary Format from ICC.1:2022, that is to say, the contents of an .icc file, or what you get from CGColorSpaceCopyICCData, or via the _ICC_PROFILE root property on X11, or reading the file referenced by GetICMProfileW on Windows). That can be read directly by PIL.ImageCms.ImageCmsProfile and many other subsystems. The precise details of that API are worth considering, but it's something that I think makes much more sense than always converting to sRGB for output.

A later improvement might be to allow the caller to request that MSS convert the returned data to a given colorspace. This would be a lot of work to put into MSS, but may be good for some use cases. At the point where that is possible, then I could see an argument for the default to be to always return data in sRGB. Until then, though, I think that no conversion is probably the best path.

jholveck avatar Nov 01 '25 08:11 jholveck