【问题标题】:Multiply greyscale BufferedImage by custom Color in Java在 Java 中将灰度 BufferedImage 与自定义颜色相乘
【发布时间】:2015-10-29 14:55:28
【问题描述】:

到处搜索,找到了许多方法。然而,在逐像素方法中(从Raster 中提取byte 数据,位移/乘以ARGB 结果的值)我在弄清楚如何将Color 应用于该像素时有点卡住了。

图片如下:

这是我当前的方法和代码,但 foiled by a bug 将在后续的 JRE / JDK 版本中修复,但目前还没有 (8u66):

public BufferedImage applyShader(BufferedImage input) {
    BufferedImage output = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_ARGB);
    float red = new Float(Integer.toString(shader.getRed()));
    float blue = new Float(Integer.toString(shader.getBlue()));
    float green = new Float(Integer.toString(shader.getGreen()));
    if(red > 0.0f) red = 255.0f / red * 100f;
    if(blue > 0.0f) blue = 255.0f / blue * 100f;
    if(green > 0.0f) green = 255.0f / green * 100f;     
    System.out.println(red + ", " + blue + ", " + green);       

    float[] factors = new float[] {
        1.0f, 1.0f, 1.0f, 1.0f
    };

    float[] offsets = new float[] {
        red, blue, green
    };

    RescaleOp op = new RescaleOp(factors, offsets, null);
    output = op.filter(input, null);
    return output;
}

这是我以前的方法,希望正确输入颜色值 (Stack Overflow source),但它会无限期挂起(好吧,在我杀死它之前的几分钟)。可能是我的代码,但性能也可能需要考虑:

public BufferedImage applyShader(BufferedImage input) {
    BufferedImage output = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_ARGB);
    float red = new Float(Integer.toString(shader.getRed()));
    float blue = new Float(Integer.toString(shader.getBlue()));
    float green = new Float(Integer.toString(shader.getGreen()));
    int red1 = shader.getRed();
    int blue1 = shader.getBlue();
    int green1 = shader.getGreen();

    final byte[] pixels = ((DataBufferByte) input.getRaster().getDataBuffer()).getData();
    final int width = input.getWidth();
    final int height = input.getHeight();
    final boolean hasAlphaChannel = input.getAlphaRaster() != null;

    int[][] result = new int[height][width];
    if(hasAlphaChannel) {
        final int pixelLength = 4;
        for(int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
            int argb = 0;
            argb += (((int) pixels[pixel] & 0xff) << 24); // alpha
            argb += ((int) (pixels[pixel + 1] + blue1) & 0xff); // blue
            argb += (((int) (pixels[pixel + 2] + green1) & 0xff) << 8); // green
            argb += (((int) (pixels[pixel + 3] + red1) & 0xff) << 16); // red
            result[row][col] = argb;
            col++;
            if (col == width) {
                col = 0;
                row++;
            }
        }
    } else {
        final int pixelLength = 3;
        for(int pixel = 0, row = 0, col = 0; pixel < pixels.length; pixel += pixelLength) {
            int argb = 0;
            argb += -16777216; // 255 alpha
            argb += ((int) (pixels[pixel] + blue1) & 0xff); // blue
            argb += (((int) (pixels[pixel + 1] + green1) & 0xff) << 8); // green
            argb += (((int) (pixels[pixel + 2] + red1) & 0xff) << 16); // red
            result[row][col] = argb;
            col++;
            if (col == width) {
                col = 0;
                row++;
            }
        }
    }

    System.out.println(input.getRaster().getWidth() + " / " + input.getRaster().getHeight());
    WritableRaster raster = Raster.createWritableRaster(input.getSampleModel(), new Point(0, 0));
    for(int i = 0; i < input.getRaster().getWidth(); i++) {
        for(int j = 0; j < input.getRaster().getHeight(); j++) {
            int k = result[i][j];
            raster.setSample(i, j, 0, k);
        }
    }

    output.setData(raster);
    return output;
}

任何建议或链接?我在替代 byte 到 ARGB 方法中遗漏了一些简单的东西吗?

This is the closest question I've found,但令人惊讶的是连一票都没有,没关系回答。

【问题讨论】:

  • 你确定是那个bug?您似乎使用了 4 个因子(ARGB),但只有 3 个偏移量(RGB)。这些数组可能应该是相同的长度。另外,为什么要创建一个新的BufferedImage 并将其分配给output,但后来将null 作为第二个参数传递给op.filter(input, null)?这实际上只是丢弃了您创建的图像。您的意思是将output 作为第二个参数传递吗?
  • 通过添加0 作为第四个偏移量,上面的代码对我来说很好。您可能还想交换蓝色和绿色(它是 RGB,而不是 RBG)。 :-)
  • 我不完全确定您想要达到的效果。如果目标真的是乘法,比如在 GPU 着色器中,那么我可以稍后发布一些示例代码。否则,您可能只需要几行代码,例如此答案中的代码:stackoverflow.com/a/21385150/3182664(刚刚添加了屏幕截图以显示效果)

标签: java colors pixel bufferedimage


【解决方案1】:

从我上面的 cmets 中,使用 4 个因子和 4 个偏移量,使用第一个创建的 output 并将 RBG 顺序重新排列为 RGB,我有以下代码,它工作正常:

public class ShaderTest {
    private final Color shader;

    public ShaderTest(final Color shader) {
        this.shader = shader;
    }

    public  BufferedImage applyShader(BufferedImage input) {
        BufferedImage output = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_ARGB);
        float red = shader.getRed();
        float green = shader.getGreen();
        float blue = shader.getBlue();
        if(red > 0.0f) red = 255.0f / red * 100f;
        if(green > 0.0f) green = 255.0f / green * 100f;
        if(blue > 0.0f) blue = 255.0f / blue * 100f;
        System.out.println(red + ", " + green + ", " + blue);

        float[] factors = new float[] {
                1.0f, 1.0f, 1.0f, 1.0f
        };

        float[] offsets = new float[] {
                red, green, blue, 0
        };

        RescaleOp op = new RescaleOp(factors, offsets, null);
        return op.filter(input, output);
    }

    // Test code
    public static void main(String[] args) throws IOException {
        BufferedImage image = ImageIO.read(new File(args[0]));
        final BufferedImage shaded = new ShaderTest(Color.ORANGE).applyShader(image);

        // Show shaded image
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame("ShaderTest");
                frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
                frame.add(new JLabel(new ImageIcon(shaded)));

                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}

【讨论】:

  • 哈,我不敢相信我错过了 RBG / RGB。这就是盯着同一个屏幕一个下午的结果。感谢filter 的更正和额外的浮动,它为我排序。
猜你喜欢
  • 1970-01-01
  • 2011-06-13
  • 1970-01-01
  • 2011-11-16
  • 2015-07-21
  • 2011-02-16
  • 1970-01-01
  • 1970-01-01
  • 2020-06-09
相关资源
最近更新 更多