Search code examples
adobergbsrgb

Mathematical conversion sRGB and AdobeRGB


It is very clear question, but I've done a lot of research and didn't find answer. StackOverflow question as this or this are about jpeg converting. This is about python build-in library.

So, how to convert sRGB to AdobeRGB and vice versa??? I mean a mathematical function, that convert 3 bytes to 3 bytes. No jpges, and so on. Just mathematical function to convert colors using pen and paper.

Yes, photoshop does it in fact and there are some strange online calculators, that show another result.

Why can't I find a simple formula in google?

I got to thinking, that I don't know something and there is no straight answer to my question.

I will be very grateful if someone can describe, what's going on or give formula.

UPDATE

Large array of results for integer rgbs will be also correct answer.


Solution

  • Here is Python code to implement the formulas. As noted in the comments, you convert from one color space to XYZ (normalized) then from XYZ to the new color space. I'm not 100% happy with the accuracy of these functions, but it should get you in the ballpark. As I come up with refinements I'll edit them into the answer.

    def linear_sRGB(c):
        if c <= 0.04045:
            return c / 12.92
        else:
            return pow((c + 0.055) / 1.055, 2.4)
    
    def sRGB_to_XYZn(r, g, b):
        Rlin = linear_sRGB(r / 255.0)
        Glin = linear_sRGB(g / 255.0)
        Blin = linear_sRGB(b / 255.0)
        Xn = Rlin * 0.4124 + Glin * 0.3576 + Blin * 0.1805
        Yn = Rlin * 0.2126 + Glin * 0.7152 + Blin * 0.0722
        Zn = Rlin * 0.0193 + Glin * 0.1192 + Blin * 0.9505
        return Xn, Yn, Zn
    
    def gamma_sRGB(c):
        if c <= 0.0031308:
            return 12.92 * c
        else:
            return 1.055 * pow(c, 1/2.4) - 0.055
    
    def XYZn_to_sRGB(Xn, Yn, Zn):
        Rlin = Xn * 3.2406255 + Yn *-1.5372080 + Zn *-0.4986286
        Glin = Xn *-0.9689307 + Yn * 1.8757561 + Zn * 0.0415175
        Blin = Xn * 0.0557101 + Yn *-0.2040211 + Zn * 1.0569959
        R = round(255 * gamma_sRGB(Rlin))
        G = round(255 * gamma_sRGB(Glin))
        B = round(255 * gamma_sRGB(Blin))
        return R, G, B
    
    def linear_AdobeRGB(c):
        if c <= 0.0:
            return 0.0
        return pow(c, 2.19921875)
    
    def AdobeRGB_to_XYZn(R, G, B):
        Rlin = linear_AdobeRGB(R / 255.0)
        Glin = linear_AdobeRGB(G / 255.0)
        Blin = linear_AdobeRGB(B / 255.0)
        Xn = Rlin * 0.57667 + Glin * 0.18556 + Blin * 0.18823
        Yn = Rlin * 0.29734 + Glin * 0.62736 + Blin * 0.07529
        Zn = Rlin * 0.02703 + Glin * 0.07069 + Blin * 0.99134
        return Xn, Yn, Zn
    
    def gamma_AdobeRGB(c):
        if c <= 0.0:
            return 0.0
        return pow(c, 1/2.19921875)
    
    def XYZn_to_AdobeRGB(Xn, Yn, Zn):
        Rlin = Xn * 2.04159 + Yn *-0.56501 + Zn *-0.34473
        Glin = Xn *-0.96924 + Yn * 1.87597 + Zn * 0.04156
        Blin = Xn * 0.01344 + Yn *-0.11836 + Zn * 1.01517
        R = round(255 * gamma_AdobeRGB(Rlin))
        G = round(255 * gamma_AdobeRGB(Glin))
        B = round(255 * gamma_AdobeRGB(Blin))
        return R, G, B