Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add NSCalibratedRGBColorSpace support. #4202

Closed
wants to merge 2 commits into from

Conversation

niw
Copy link

@niw niw commented Dec 31, 2024

Problem

Ghostty is using sRGB by default, optionally Display P3 color space. However neither color space matches to the color space that the regular macOS apps are using.
That is NSCalibratedRGBColorSpace, seems called "Generic RGB" from initializer API name.

Because of this, colors has same hex value are slightly stronger on Ghostty compare to Terminal.app, for example.

Example: A window in front is Ghostty without this patch, a window behind is Terminal.app
Screen capture

Solution

Add generic-rgb to WindowColorspace, therefore users can set window-colorspace to generic-rgb in config to have similar colors with the other macOS apps.

niw added 2 commits January 1, 2025 09:03
**Problems**

Ghostty is using sRGB by default, optionally Display P3 color space.
However neither color space matches to the color space that the regular
macOS apps are using.
That is `NSCalibratedRGBColorSpace`, seems called "Generic RGB" from
initializer API name.

Because of this, colors has same hex value are slightly darker on
Ghostty compare to Terminal.app, for example.

**Solution**

Add `generic-rgb` to `WindowColorspace`, therefore users can set
`window-colorspace` to `generic-rgb` in config to have similar colors
with the other macOS apps.
@niw niw force-pushed the add_generic_rgb_color_space branch from e1ef552 to ed5b692 Compare January 1, 2025 00:03
@naruaway
Copy link

naruaway commented Jan 1, 2025

(I am not part of Ghostty development but let me leave a comment since I worked on alacritty/alacritty#6602 before, which is cited in the corresponding Ghostty PR #376)

However neither color space matches to the color space that the regular macOS apps are using.

Are we sure about this? Assuming we are talking about "how apps should render specified RGB tuple such as #50C878 physically in the display by default", all the web browsers use sRGB (cf. alacritty/alacritty#6602 (comment)) and I think colorschemes are designed in sRGB in general (#376 (comment)). Terminal.app might not be a good example here since it does not even support truecolor escape sequence so I would say in general their support for colors are not well considered.

Choosing anything other than sRGB makes colorschemes look different from other places, notably on web browsers and I guess for generic-rgb, it can even render differently per display as well if I am understanding correctly. I think it's fine to add this as an option with these caveats though.

I would consider this option as a "temporary hack" to make it look the same as other apps in specific situations without modifying colorscheme / color code. If anyone just wants to use "more vivid colors than sRGB can express", they should use P3 color space, which should look the same across displays. In an ideal world we should not neither use P3 as global config as well though. Each color should optionally specify color space such as P3 like we can do for the web (cf. https://webkit.org/blog/10042/wide-gamut-color-in-css-with-display-p3/)

@naruaway
Copy link

naruaway commented Jan 1, 2025

I found more relevant discussions so linking here for a reference:

  • Gamma Correction #2125
  • True Color and Display P3 colorspace #2665
    • By @lilyball:

      The point of truecolor is that by specifying RGB values, the colors look the same everywhere. But when you set window-colorspace = display-p3, truecolor colors are now interpreted as Display P3 colors instead. The simple answer is to always interpret truecolor colors in sRGB even when the window colorspace is Display P3

@niw
Copy link
Author

niw commented Jan 1, 2025

I think the root problem is RGB color space is device dependent and each RGB values may have different result on each system depends on how the values are interrpted by the application and the system, unlike, for example, the image file that contains a profile describes how to interrupt their RGB values to reproduce colors or other device independnt color values such as CIE L*a*b.

I certianly agree that, in general, color schema and many RGB values avilable on the internet are created and assumed to be used in sRGB color space and implicity asked applications to interrupt these RGB values in sRGB, and current Ghostty implementation is reasonable to do so by default, and also allow uses to use Display P3, if users knows their RGB values are in Display P3 optionally, which is good.

My point is, however, many other native macOS applications made with AppKit using RGB values, for example some text editor app that let users to pick colors for the syntax highlighting using system color picker and display the RGB values in their user interface, in the implementation, uses NSColor with Generic RGB color space in general and renders colors in Generic RGB not sRGB in their application windows.
Therefore, if users copied and pasted such RGB values into the config file for Ghostty, because these values are not in sRGB but in Generic RGB, the result would be vivid or stronger on Ghostty, which is unexpected for those who’re using such values.
Therefore, I don’t think it’s a ”temporary hack,” but just for additional feature to let Ghostty has a similar behaviors with the other native macOS applications, if users want.

Ideally, I think, all RGB color values in the wild are associated with a color space information, but that wound unlikly be happening...

@niw
Copy link
Author

niw commented Jan 1, 2025

@naruaway oops, I sent my last comment before reading your last comment, please forgive me if I said something that is coflicting with it.

@naruaway
Copy link

naruaway commented Jan 1, 2025

No conflict! Thanks for the additional comment 🙏

let Ghostty has a similar behaviors with the other native macOS applications, if users want.

I am little bit skeptical about the need for this ("similar behavior") though. For "user picks up colors using system color picker to choose colors to be shown" case, there is no GUI colorpicker so this is not applicable. The only way to specify colors in Ghostty right now is via text config file or via 3rd party web based tools such as https://ghostty.zerebos.com/settings/colors. For the former, I think people will assume sRGB and for the latter, the color in the web UI is shown in sRGB.

For "Therefore, if users copied and pasted such RGB values into the config file for Ghostty", I think we can convert them into sRGB before copy-pasting them. This is actually good thing by itself since now the colorscheme will be display-independent. Changing Ghostty global config just to allow direct copy-pasting does not sound a good trade-off since this config will affect colors from escape sequences as well.

In any way, I think we should clarify (in Ghostty documentation?) that specifying display-p3 or generic-rgb has a huge drawback of having "wrong" colors for color escape sequence for many users. For example, if a web developer is using https://github.com/catgoose/nvim-colorizer.lua to preview CSS colors, the color will look wrong. So I would say display-p3 and generic-rgb are "advanced option for people who understands what they are doing" even if it might not be "temporary solution"

@niw
Copy link
Author

niw commented Jan 1, 2025

I am little bit skeptical about the need for this ("similar behavior") though. For "user picks up colors using system color picker to choose colors to be shown" case

I don’t disagree with this, probably rare case for sure... but I did, then found this.

For "Therefore, if users copied and pasted such RGB values into the config file for Ghostty", I think we can convert them into sRGB before copy-pasting them.

Certainly, when Ghostty has for example an GUI to let users to pick colors visually then sure the RGB value will be stored in sRGB color space. And in that mean, actually, this can be “temporary hack.” I agree with having a doumentation (and with a brief color space expranation) would help a lot for users to do what thay want to do.

@naruaway
Copy link

naruaway commented Jan 1, 2025

I would like to reproduce the problem so I tried but I somehow could not... @niw Do you have reproduction steps?
The following is what I did:

I am using MacBook Air (M2, 2022) and macOS version is 15.2 (24C101).

First, I opened Terminal.app and created a new profile, changed regular green color via color picker with "RGB Sliders" by specifying RGB hex (#45A161). And I ran printf "\033[42m \033[0m\n" to print this color in Terminal.app:

macos-terminal-app

Interestingly, using Digital Color Meter, this green is actually #45A161 in sRGB, not in Generic RGB:

color-meter

So somehow in my environment, everything here is in sRGB...

@niw
Copy link
Author

niw commented Jan 1, 2025

@naruaway Ooh, I found this Color Space option in color palette! Now I am feeling this patch is really not right thing to do, instead as you mentioned, use this to convert color to sRGB and use it in Ghostty instead of adding ability to Ghostty to use Generic RGB instead. I think on your color palette, sRGB is selected instead.

Color Palette Option

@naruaway
Copy link

naruaway commented Jan 1, 2025

Very interesting.. I missed that config in the color palette and now I confirmed that it was "Device RGB":

devicergb

I recently did a fresh-install of macOS so I guess this is the default config (but not 100% sure). And for my MacBook Air, "Device RGB" and "sRGB" show the exact same color code hex. When I switch to "Display P3" or even "Generic RGB", the color code will be different.

And yes, for this use case (port Terminal.app color scheme to Ghostty), probably saying "please copy-paste sRGB color hex" is the best way for majority of people to avoid further confusion. And ideally we should even discourage the usage of display-p3 in Ghostty config as well if the motivation is "just to get more vivid colors for the same colorscheme".

(IMHO the only valid situation to use display-p3 in Ghostty should be when we really want to show some colors which is not representable in sRGB space 👍 )

@naruaway
Copy link

naruaway commented Jan 1, 2025

Note that for people who wants to convert hex values in "Generic RGB" already stored in some place, you can use the following Swift code:

// Save this as "generic-rgb-to-srgb.swift" and run it with "swift generic-rgb-to-srgb.swift" on macOS

import Cocoa

func genericRgbToSrgb(hex: Int) -> String {
  let red = CGFloat((hex >> 16) & 0xFF) / 255.0
  let green = CGFloat((hex >> 8) & 0xFF) / 255.0
  let blue = CGFloat(hex & 0xFF) / 255.0

  let genericRGBColor = NSColor(calibratedRed: red, green: green, blue: blue, alpha: 1.0)

  guard let sRGBColor = genericRGBColor.usingColorSpace(.sRGB) else {
    fatalError("Failed to convert color to sRGB")
  }

  let sRGBRed = Int(round(sRGBColor.redComponent * 255.0))
  let sRGBGreen = Int(round(sRGBColor.greenComponent * 255.0))
  let sRGBBlue = Int(round(sRGBColor.blueComponent * 255.0))

  return String(format: "#%02X%02X%02X", sRGBRed, sRGBGreen, sRGBBlue)
}

print(genericRgbToSrgb(hex: 0x39934E))

I verified that this prints #45A161 as expected. 0x39934E is from the color palette with "Generic RGB" setting for the same color. We can easily write color scheme converter for macOS in this way. Note that this does not handle underflow/overflow, which implies the target colorspace is not wide enough to represent the original color

@niw
Copy link
Author

niw commented Jan 1, 2025

Okay since there is enough info and findings about color and color space for using it on Ghostty config on this thread, and I am now feeling this patch is not necessary, also and the successor would be implementing GUI config interface that can accept colors with atribtrary color space e.g. General RGB and can convert it to application color space, likely sRGB (or if not, then use Display P3, for example.)

I am going to close this pull request.

@niw niw closed this Jan 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants