Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e3b2efc4 authored by James O'Leary's avatar James O'Leary Committed by Automerger Merge Worker
Browse files

Merge changes from topic "themesMay2322" into tm-dev am: f5fff77b

parents 607b0e6d f5fff77b
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -386,6 +386,13 @@ public class Cam {
        // Yellows are very chromatic at L = 100, and blues are very chromatic at L = 0. All the
        // other hues are white at L = 100, and black at L = 0. To preserve consistency for users of
        // this system, it is better to simply return white at L* > 99, and black and L* < 0.
        if (frame == Frame.DEFAULT) {
            // If the viewing conditions are the same as the default sRGB-like viewing conditions,
            // skip to using HctSolver: it uses geometrical insights to find the closest in-gamut
            // match to hue/chroma/lstar.
            return HctSolver.solveToInt(hue, chroma, lstar);
        }

        if (chroma < 1.0 || Math.round(lstar) <= 0.0 || Math.round(lstar) >= 100.0) {
            return CamUtils.intFromLstar(lstar);
        }
+140 −17
Original line number Diff line number Diff line
@@ -73,12 +73,124 @@ public final class CamUtils {
    // used. It was derived using Schlomer's technique of transforming the xyY
    // primaries to XYZ, then applying a correction to ensure mapping from sRGB
    // 1, 1, 1 to the reference white point, D65.
    static final float[][] SRGB_TO_XYZ = {
            {0.41233895f, 0.35762064f, 0.18051042f},
            {0.2126f, 0.7152f, 0.0722f},
            {0.01932141f, 0.11916382f, 0.95034478f}
    static final double[][] SRGB_TO_XYZ =
            new double[][] {
                    new double[] {0.41233895, 0.35762064, 0.18051042},
                    new double[] {0.2126, 0.7152, 0.0722},
                    new double[] {0.01932141, 0.11916382, 0.95034478},
            };

    static final double[][] XYZ_TO_SRGB =
            new double[][] {
                    new double[] {
                            3.2413774792388685, -1.5376652402851851, -0.49885366846268053,
                    },
                    new double[] {
                            -0.9691452513005321, 1.8758853451067872, 0.04156585616912061,
                    },
                    new double[] {
                            0.05562093689691305, -0.20395524564742123, 1.0571799111220335,
                    },
            };

    /**
     * The signum function.
     *
     * @return 1 if num > 0, -1 if num < 0, and 0 if num = 0
     */
    public static int signum(double num) {
        if (num < 0) {
            return -1;
        } else if (num == 0) {
            return 0;
        } else {
            return 1;
        }
    }

    /**
     * Converts an L* value to an ARGB representation.
     *
     * @param lstar L* in L*a*b*
     * @return ARGB representation of grayscale color with lightness matching L*
     */
    public static int argbFromLstar(double lstar) {
        double fy = (lstar + 16.0) / 116.0;
        double fz = fy;
        double fx = fy;
        double kappa = 24389.0 / 27.0;
        double epsilon = 216.0 / 24389.0;
        boolean lExceedsEpsilonKappa = lstar > 8.0;
        double y = lExceedsEpsilonKappa ? fy * fy * fy : lstar / kappa;
        boolean cubeExceedEpsilon = fy * fy * fy > epsilon;
        double x = cubeExceedEpsilon ? fx * fx * fx : lstar / kappa;
        double z = cubeExceedEpsilon ? fz * fz * fz : lstar / kappa;
        float[] whitePoint = WHITE_POINT_D65;
        return argbFromXyz(x * whitePoint[0], y * whitePoint[1], z * whitePoint[2]);
    }

    /** Converts a color from ARGB to XYZ. */
    public static int argbFromXyz(double x, double y, double z) {
        double[][] matrix = XYZ_TO_SRGB;
        double linearR = matrix[0][0] * x + matrix[0][1] * y + matrix[0][2] * z;
        double linearG = matrix[1][0] * x + matrix[1][1] * y + matrix[1][2] * z;
        double linearB = matrix[2][0] * x + matrix[2][1] * y + matrix[2][2] * z;
        int r = delinearized(linearR);
        int g = delinearized(linearG);
        int b = delinearized(linearB);
        return argbFromRgb(r, g, b);
    }

    /** Converts a color from linear RGB components to ARGB format. */
    public static int argbFromLinrgb(double[] linrgb) {
        int r = delinearized(linrgb[0]);
        int g = delinearized(linrgb[1]);
        int b = delinearized(linrgb[2]);
        return argbFromRgb(r, g, b);
    }

    /** Converts a color from linear RGB components to ARGB format. */
    public static int argbFromLinrgbComponents(double r, double g, double b) {
        return argbFromRgb(delinearized(r), delinearized(g), delinearized(b));
    }

    /**
     * Delinearizes an RGB component.
     *
     * @param rgbComponent 0.0 <= rgb_component <= 100.0, represents linear R/G/B channel
     * @return 0 <= output <= 255, color channel converted to regular RGB space
     */
    public static int delinearized(double rgbComponent) {
        double normalized = rgbComponent / 100.0;
        double delinearized = 0.0;
        if (normalized <= 0.0031308) {
            delinearized = normalized * 12.92;
        } else {
            delinearized = 1.055 * Math.pow(normalized, 1.0 / 2.4) - 0.055;
        }
        return clampInt(0, 255, (int) Math.round(delinearized * 255.0));
    }

    /**
     * Clamps an integer between two integers.
     *
     * @return input when min <= input <= max, and either min or max otherwise.
     */
    public static int clampInt(int min, int max, int input) {
        if (input < min) {
            return min;
        } else if (input > max) {
            return max;
        }

        return input;
    }

    /** Converts a color from RGB components to ARGB format. */
    public static int argbFromRgb(int red, int green, int blue) {
        return (255 << 24) | ((red & 255) << 16) | ((green & 255) << 8) | (blue & 255);
    }

    static int intFromLstar(float lstar) {
        if (lstar < 1) {
            return 0xff000000;
@@ -126,9 +238,9 @@ public final class CamUtils {
        final float r = linearized(Color.red(argb));
        final float g = linearized(Color.green(argb));
        final float b = linearized(Color.blue(argb));
        float[][] matrix = SRGB_TO_XYZ;
        float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
        return y;
        double[][] matrix = SRGB_TO_XYZ;
        double y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
        return (float) y;
    }

    @NonNull
@@ -137,19 +249,30 @@ public final class CamUtils {
        final float g = linearized(Color.green(argb));
        final float b = linearized(Color.blue(argb));

        float[][] matrix = SRGB_TO_XYZ;
        float x = (r * matrix[0][0]) + (g * matrix[0][1]) + (b * matrix[0][2]);
        float y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
        float z = (r * matrix[2][0]) + (g * matrix[2][1]) + (b * matrix[2][2]);
        return new float[]{x, y, z};
        double[][] matrix = SRGB_TO_XYZ;
        double x = (r * matrix[0][0]) + (g * matrix[0][1]) + (b * matrix[0][2]);
        double y = (r * matrix[1][0]) + (g * matrix[1][1]) + (b * matrix[1][2]);
        double z = (r * matrix[2][0]) + (g * matrix[2][1]) + (b * matrix[2][2]);
        return new float[]{(float) x, (float) y, (float) z};
    }

    static float yFromLstar(float lstar) {
        float ke = 8.0f;
    /**
     * Converts an L* value to a Y value.
     *
     * <p>L* in L*a*b* and Y in XYZ measure the same quantity, luminance.
     *
     * <p>L* measures perceptual luminance, a linear scale. Y in XYZ measures relative luminance, a
     * logarithmic scale.
     *
     * @param lstar L* in L*a*b*
     * @return Y in XYZ
     */
    public static double yFromLstar(double lstar) {
        double ke = 8.0;
        if (lstar > ke) {
            return (float) Math.pow(((lstar + 16.0) / 116.0), 3) * 100f;
            return Math.pow((lstar + 16.0) / 116.0, 3.0) * 100.0;
        } else {
            return lstar / (24389f / 27f) * 100f;
            return lstar / (24389.0 / 27.0) * 100.0;
        }
    }

+14 −6
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.internal.graphics.cam;
import android.annotation.NonNull;
import android.util.MathUtils;

import com.android.internal.annotations.VisibleForTesting;

/**
 * The frame, or viewing conditions, where a color was seen. Used, along with a color, to create a
 * color appearance model representing the color.
@@ -68,15 +70,18 @@ public final class Frame {
    private final float mFlRoot;
    private final float mZ;

    float getAw() {
    @VisibleForTesting
    public float getAw() {
        return mAw;
    }

    float getN() {
    @VisibleForTesting
    public float getN() {
        return mN;
    }

    float getNbb() {
    @VisibleForTesting
    public float getNbb() {
        return mNbb;
    }

@@ -92,8 +97,9 @@ public final class Frame {
        return mNc;
    }

    @VisibleForTesting
    @NonNull
    float[] getRgbD() {
    public float[] getRgbD() {
        return mRgbD;
    }

@@ -101,7 +107,9 @@ public final class Frame {
        return mFl;
    }

    float getFlRoot() {
    @VisibleForTesting
    @NonNull
    public float getFlRoot() {
        return mFlRoot;
    }

@@ -167,7 +175,7 @@ public final class Frame {
                5.0 * adaptingLuminance));

        // Intermediate factor, ratio of background relative luminance to white relative luminance
        float n = CamUtils.yFromLstar(backgroundLstar) / whitepoint[1];
        float n = (float) CamUtils.yFromLstar(backgroundLstar) / whitepoint[1];

        // Base exponential nonlinearity
        // note Schlomer 2018 has a typo and uses 1.58, the correct factor is 1.48
+721 −0

File added.

Preview size limit exceeded, changes collapsed.

+32 −1
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.internal.graphics.cam;

import static org.junit.Assert.assertEquals;

import android.platform.test.annotations.LargeTest;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -69,7 +72,7 @@ public final class CamTest {
    public void camFromGreen() {
        Cam cam = Cam.fromInt(GREEN);
        assertEquals(79.331f, cam.getJ(), 0.001f);
        assertEquals(108.409f, cam.getChroma(), 0.001f);
        assertEquals(108.410f, cam.getChroma(), 0.001f);
        assertEquals(142.139f, cam.getHue(), 0.001f);
        assertEquals(85.587f, cam.getM(), 0.001f);
        assertEquals(78.604f, cam.getS(), 0.001f);
@@ -193,4 +196,32 @@ public final class CamTest {
    public void deltaERedToBlue() {
        assertEquals(21.415f, Cam.fromInt(RED).distance(Cam.fromInt(BLUE)), 0.001f);
    }

    @Test
    public void viewingConditions_default() {
        Frame vc = Frame.DEFAULT;

        Assert.assertEquals(0.184, vc.getN(), 0.001);
        Assert.assertEquals(29.981, vc.getAw(), 0.001);
        Assert.assertEquals(1.016, vc.getNbb(), 0.001);
        Assert.assertEquals(1.021, vc.getRgbD()[0], 0.001);
        Assert.assertEquals(0.986, vc.getRgbD()[1], 0.001);
        Assert.assertEquals(0.933, vc.getRgbD()[2], 0.001);
        Assert.assertEquals(0.789, vc.getFlRoot(), 0.001);
    }

    @LargeTest
    @Test
    public void testHctReflexivity() {
        for (int i = 0; i <= 0x00ffffff; i++) {
            int color = 0xFF000000 | i;
            Cam hct = Cam.fromInt(color);
            int reconstructedFromHct = Cam.getInt(hct.getHue(), hct.getChroma(),
                    CamUtils.lstarFromInt(color));

            Assert.assertEquals("input was " + Integer.toHexString(color)
                            + "; output was " + Integer.toHexString(reconstructedFromHct),
                    reconstructedFromHct, reconstructedFromHct);
        }
    }
}
Loading