2013-01-08 7 views
3

Я искал простой способ подкрасить изображение на Java, но я не нашел ничего, что бы соответствовало моим потребностям. Я перешел к следующему решению:Tinting Image в улучшении Java

Сначала создайте новое изображение, которое служит копией изображения, которое я хочу покрасить, затем создаю второе изображение, которое является прозрачной маской изображения, которое я хочу оттенять, а затем рисую подкраска - маска над моей копией и вернуть копию:

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; 
} 

раствор для изображений, которые не имели никаких прозрачных пикселей (например, не использовать альфа - канал) было просто использовать FillRect() в целом изображение, но это не сработало на изображениях с прозрачными пикселями, а затем выбранный цвет, а не невидимый.

Кто-нибудь знает способ сделать это более эффективно, так как методы, которые я нашел здесь, были довольно неудовлетворительными, и я планирую сделать это подкрашивание на многих изображениях (большинство из них имеют оттенок серого цвета, поэтому их легко подкрашивать) во время работы около 50 раз в секунду.

Pre-Генерация всех необходимых изображений при запуске и/или кэшировании сгенерированных изображений может быть решением, но мне это кажется неудобным, хотя если ничего не поделаешь, ничего не поделаешь.

Кто-то связывает это: http://www.javalobby.org/articles/ultimate-image/

Это было полезно, но не покрывал тонировка.

+1

Нравится? http://stackoverflow.com/a/4248459/59087 –

+0

Уже прочитал это, и он не работает с setXORMode - он генерирует странные результаты, которые не являются предсказуемыми, и я действительно не понимаю предварительных условий, которые у него есть (черное изображение и т. д.).), чтобы использовать это правильно. – salbeira

+0

Редактирование: хорошо прочитайте его снова, и теперь я знаю проблему: цвет XORing добавляет оттенок в пиксель и не «переопределяет» его часть на нужный цвет - поскольку такие «серые» изменяются на «белый» при применении красно-желтоватый оттенок, потому что «серый» уже имеет нагрузку 1-го в его растровом изображении rgba. (Хотя некоторые 1s должны вернуться к 0 ... так что ... я не понимаю, почему он всегда белеет). – salbeira

ответ

6

По существу, вы должны использовать маленькую черную магию, и это не мешало бы иметь в жертву или два на руке ...

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); 
     } 

    } 

} 

Основная идея этого метода заключается в чтобы создать «маску» изображения, я не беру на себя ответственность за эту идею, я украл ее в Интернете, если я найду, где я отправлю ссылку.

Как только у вас есть маска, вы можете визуализировать два изображения вместе. Поскольку я уже применил альфа-уровень к маске, мне не нужно повторно применять альфа-композицию, как только я закончу.

PS - Я создаю совместимое изображение для этого примера. Я делаю это просто потому, что он будет отображаться быстрее на графическом устройстве, это не является обязательным требованием, это просто код, который у меня есть;)

+0

Uhm ... это именно то, что я сделал ... – salbeira

+0

Ах, нет, это не так ... – MadProgrammer

+0

Да, глядя на всю часть кода, вы делаете что-то интересное, хотя идея оттенок-маска такая же. Я хотел бы знать, что именно происходит в вашем методе «generateMask», поскольку вы просто используете «fill rect» со всем экраном. Это из-за AlphaComposite.SRC_IN? – salbeira