java - Java改进中的着色图像

标签 java image tint

我在寻找一种用 Java 为图像着色的简单方法,但没有找到适合我需要的方法。我去了以下解决方案:

首先创建一个新图像作为我想要着色的图像的副本,然后我创建第二个图像,它是我想要着色的图像的透明 mask ,然后在我的副本上绘制着色 mask 和返回副本:

public static BufferedImage tintImage(Image original, int r, int g, int b){
    int width = original.getWidth(null);
    int height = original.getHeight(null);
    BufferedImage tinted = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
    Graphics2D graphics = (Graphics2D) tinted.getGraphics();
    graphics.drawImage(original, 0, 0, width, height, null);
    Color c = new Color(r,g,b,128);
    Color n = new Color(0,0,0,0);
    BufferedImage tint = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
    for(int i = 0 ; i < width ; i++){
        for(int j = 0 ; j < height ; j++){
            if(tinted.getRGB(i, j) != n.getRGB()){
                tint.setRGB(i, j, c.getRGB());
            }
        }
    }
    graphics.drawImage(tint, 0, 0, null);
    graphics.dispose();
    return tinted;
}

对于没有透明像素的图像(例如,没有使用 alpha channel )的解决方案是简单地在整个图像上使用 fillRect(),但这不适用于当时具有透明像素的图像具有选定的颜色,而不是仍然不可见。

有谁知道更有效地做到这一点的方法,因为我在这里找到的方法相当不令人满意,我计划在许多图像上进行这种着色(大多数图像都带有灰色调,因此很容易着色)运行时间约为每秒 50 次。

预 - 在启动时生成所有需要的图像和/或缓存生成的图像可能是一个解决方案,但在某种程度上对我来说感觉很尴尬,但如果什么都做不了,那就什么也做不了。

有人链接了这个:http://www.javalobby.org/articles/ultimate-image/

它很有帮助,但没有涵盖着色。

最佳答案

本质上,你需要使用一点黑魔法,手头有一两个牺牲也没什么坏处......

enter image description here

public class TestTint {

    public static void main(String[] args) {
        new TestTint();
    }

    public TestTint() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static GraphicsConfiguration getGraphicsConfiguration() {
        return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
    }

    public static BufferedImage createCompatibleImage(int width, int height, int transparency) {
        BufferedImage image = getGraphicsConfiguration().createCompatibleImage(width, height, transparency);
        image.coerceData(true);
        return image;
    }

    public static void applyQualityRenderingHints(Graphics2D g2d) {
        g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
    }

    public static BufferedImage generateMask(BufferedImage imgSource, Color color, float alpha) {
        int imgWidth = imgSource.getWidth();
        int imgHeight = imgSource.getHeight();

        BufferedImage imgMask = createCompatibleImage(imgWidth, imgHeight, Transparency.TRANSLUCENT);
        Graphics2D g2 = imgMask.createGraphics();
        applyQualityRenderingHints(g2);

        g2.drawImage(imgSource, 0, 0, null);
        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, alpha));
        g2.setColor(color);

        g2.fillRect(0, 0, imgSource.getWidth(), imgSource.getHeight());
        g2.dispose();

        return imgMask;
    }

    public BufferedImage tint(BufferedImage master, BufferedImage tint) {
        int imgWidth = master.getWidth();
        int imgHeight = master.getHeight();

        BufferedImage tinted = createCompatibleImage(imgWidth, imgHeight, Transparency.TRANSLUCENT);
        Graphics2D g2 = tinted.createGraphics();
        applyQualityRenderingHints(g2);
        g2.drawImage(master, 0, 0, null);
        g2.drawImage(tint, 0, 0, null);
        g2.dispose();

        return tinted;
    }

    public class TestPane extends JPanel {

        private BufferedImage master;
        private BufferedImage mask;
        private BufferedImage tinted;

        public TestPane() {
            try {
                master = ImageIO.read(new File("C:/Users/swhitehead/Documents/My Dropbox/MegaTokyo/Miho_Small.png"));
                mask = generateMask(master, Color.RED, 0.5f);
                tinted = tint(master, mask);
            } catch (IOException exp) {
                exp.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            Dimension size = super.getPreferredSize();
            if (master != null && mask != null) {
                size = new Dimension(master.getWidth() + mask.getWidth() + tinted.getWidth(), Math.max(Math.max(master.getHeight(), mask.getHeight()), tinted.getHeight()));
            }
            return size;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            int x = (getWidth() - (master.getWidth() + mask.getWidth() + tinted.getWidth())) / 2;
            int y = (getHeight() - master.getHeight()) / 2;
            g.drawImage(master, x, y, this);

            x += mask.getWidth();
            y = (getHeight() - mask.getHeight()) / 2;
            g.drawImage(mask, x, y, this);

            x += tinted.getWidth();
            y = (getHeight() - tinted.getHeight()) / 2;
            g.drawImage(tinted, x, y, this);
        }

    }

}

这种技术背后的总体思想是生成图像的“掩码”,我不相信这个想法,我从网上偷了它,如果我能找到它,我会发布一个链接。

一旦你有了 mask ,你就可以一起渲染两个图像。因为我已经对蒙版应用了 alpha 级别,所以我不需要在完成后重新应用 alpha 合成。

PS - 我为这个例子创建了一个兼容的图像。我这样做只是因为它会在图形设备上渲染得更快,这不是必需的,它只是我手头的代码;)

关于java - Java改进中的着色图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14225518/

相关文章:

java - 如何组合图像以用作 SWT 光标

android - 工具栏中的色调导航图标

ios - 按住自定义 UIButton 时更改深灰色突出显示的颜色?

java - Bluej/Java 循环?

java - Micrometer/Prometheus 如何防止仪表值变为 NaN?

html - 保持图像纵横比的图像表

android - AppCompat 工具栏上的 MenuItem 着色

java - Wicket:需要实现带有选项卡错误指示器的 AjaxTabbedPanel

java - 用于内存字节数组的 RandomAccessFile-like API?

java - 获取图像的 JPEG 渲染的内存表示