【问题标题】:How to mix two int colors correctly如何正确混合两种 int 颜色
【发布时间】:2019-02-28 03:40:45
【问题描述】:

我正在尝试混合两种编码为整数的颜色。这是我的小功能:

int blend (int a, int b, float ratio) {
    if (ratio > 1f) {
        ratio = 1f;
    } else if (ratio < 0f) {
        ratio = 0f;
    }
    float iRatio = 1.0f - ratio;

    int aA = (a >> 24 & 0xff);
    int aR = ((a & 0xff0000) >> 16);
    int aG = ((a & 0xff00) >> 8);
    int aB = (a & 0xff);

    int bA = (b >> 24 & 0xff);
    int bR = ((b & 0xff0000) >> 16);
    int bG = ((b & 0xff00) >> 8);
    int bB = (b & 0xff);

    int A = ((int)(aA * iRatio) + (int)(bA * ratio));
    int R = ((int)(aR * iRatio) + (int)(bR * ratio));
    int G = ((int)(aG * iRatio) + (int)(bG * ratio));
    int B = ((int)(aB * iRatio) + (int)(bB * ratio));

    return A << 24 | R << 16 | G << 8 | B;
}

似乎一切正常,但某些参数会产生错误的颜色。 例如:

    int a = 0xbbccdd;
    int b = 0xbbccdd;
    int c = blend(a, b, 0.5f); // gives 0xbaccdc, although it should be 0xbbccdd

我的猜测是,无论是乘以浮动比率还是强制转换都应该归咎于此,但我无法弄清楚它们有什么问题......

那么在java中混合两种颜色的正确方法是什么?

【问题讨论】:

  • 那么为什么不使用ByteBuffer 来获取byte[] 数组,并从byte[] 数组生成int 值?
  • 为了性能。如果我错了,请纠正我,但创建原语比实例化对象快得多。此代码必须每秒运行数百次。
  • 我使用按位运算找到的最佳答案在这里:stackoverflow.com/a/4787257/303612

标签: java colors int bit-manipulation color-blending


【解决方案1】:

我的猜测是转换为 int 应该在添加之后完成。像这样

int a = (int)((aA * iRatio) + (bA * ratio));

我还建议在使用变量时使用 Java 命名约定。只有常量应该是大写字母。

【讨论】:

  • 它有帮助。愚蠢的我,我为什么不那样投:/
  • 顺便说一句。你会如何命名变量?我知道大写只用于最终的静态变量,这只是 SOOOO 可读和本地化的......
  • 可能类似于“redHex”、“greenHex”和“blueHex”,因为它们代表各自颜色的十六进制值。 :)
【解决方案2】:

感谢 JuliusB 和 dARKpRINCE。我已经对其进行了调整以接受 java.awt.Color,修复了演员表并将变量重命名为更像 Java 标准。它运作良好。再次感谢!

Color blend( Color c1, Color c2, float ratio ) {
    if ( ratio > 1f ) ratio = 1f;
    else if ( ratio < 0f ) ratio = 0f;
    float iRatio = 1.0f - ratio;

    int i1 = c1.getRGB();
    int i2 = c2.getRGB();

    int a1 = (i1 >> 24 & 0xff);
    int r1 = ((i1 & 0xff0000) >> 16);
    int g1 = ((i1 & 0xff00) >> 8);
    int b1 = (i1 & 0xff);

    int a2 = (i2 >> 24 & 0xff);
    int r2 = ((i2 & 0xff0000) >> 16);
    int g2 = ((i2 & 0xff00) >> 8);
    int b2 = (i2 & 0xff);

    int a = (int)((a1 * iRatio) + (a2 * ratio));
    int r = (int)((r1 * iRatio) + (r2 * ratio));
    int g = (int)((g1 * iRatio) + (g2 * ratio));
    int b = (int)((b1 * iRatio) + (b2 * ratio));

    return new Color( a << 24 | r << 16 | g << 8 | b );
}

【讨论】:

    【解决方案3】:

    感谢 JuliusB、dARKpRINCE 和 bmauter。
    根据您的输入,我创建了以下函数,它以相等的比例混合 n 种颜色:

    public static Color blend(Color... c) {
        if (c == null || c.length <= 0) {
            return null;
        }
        float ratio = 1f / ((float) c.length);
    
        int a = 0;
        int r = 0;
        int g = 0;
        int b = 0;
    
        for (int i = 0; i < c.length; i++) {
            int rgb = c[i].getRGB();
            int a1 = (rgb >> 24 & 0xff);
            int r1 = ((rgb & 0xff0000) >> 16);
            int g1 = ((rgb & 0xff00) >> 8);
            int b1 = (rgb & 0xff);
            a += ((int) a1 * ratio);
            r += ((int) r1 * ratio);
            g += ((int) g1 * ratio);
            b += ((int) b1 * ratio);
        }
    
        return new Color(a << 24 | r << 16 | g << 8 | b);
    }
    

    【讨论】:

      【解决方案4】:

      @dARKpRINCE 的回答是正确的,但我有一些小提示:

      1. 您的函数应该是静态的,因为它不依赖于任何对象字段。

      2. 在提取颜色的 alpha 分量时,您可以通过使用 x &gt;&gt;&gt; 24 而不是 (x &gt;&gt; 24) &amp; 0xFF 来节省一项操作。

      3. 任何形式:

        (a * (1 - ratio)) + (b * ratio)
        

        可以写成:

        a + (b - a) * ratio
        

        这将您需要的乘法次数减半。

      【讨论】:

        【解决方案5】:

        最简单的答案可能是:

        public static Color mixColors(Color... colors) {
            float ratio = 1f / ((float) colors.length);
            int r = 0, g = 0, b = 0, a = 0;
            for (Color color : colors) {
                r += color.getRed() * ratio;
                g += color.getGreen() * ratio;
                b += color.getBlue() * ratio;
                a += color.getAlpha() * ratio;
            }
            return new Color(r, g, b, a);
        }
        

        【讨论】:

          【解决方案6】:

          如果有人对在 LibGDX 中混合颜色感兴趣(基于上述解决方案,但为 LibGDX API 量身定制):

          static Color blend( Color c1, Color c2, float ratio ) {
              if ( ratio > 1f ) ratio = 1f;
              else if ( ratio < 0f ) ratio = 0f;
              float iRatio = 1.0f - ratio;
          
              int i1 = Color.argb8888(c1);
              int i2 = Color.argb8888(c2);
          
              int a1 = (i1 >> 24 & 0xff);
              int r1 = ((i1 & 0xff0000) >> 16);
              int g1 = ((i1 & 0xff00) >> 8);
              int b1 = (i1 & 0xff);
          
              int a2 = (i2 >> 24 & 0xff);
              int r2 = ((i2 & 0xff0000) >> 16);
              int g2 = ((i2 & 0xff00) >> 8);
              int b2 = (i2 & 0xff);
          
              int a = (int)((a1 * iRatio) + (a2 * ratio));
              int r = (int)((r1 * iRatio) + (r2 * ratio));
              int g = (int)((g1 * iRatio) + (g2 * ratio));
              int b = (int)((b1 * iRatio) + (b2 * ratio));
          
              return new Color(r << 24 | g << 16 | b << 8 | a);
          }
          

          【讨论】:

            猜你喜欢
            • 2012-10-20
            • 1970-01-01
            • 2014-05-04
            • 2023-01-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-04-09
            相关资源
            最近更新 更多