2012-11-29 4 views
7

배경 : "사용 중지됨"으로 이미지를 만들 수 있어야합니다. 일반적으로 제안되는 방법은 이미지를 그레이 스케일로 변환하고 그레이 스케일 된 이미지를 표시하는 것입니다. 단점은 이미지에서만 작동하므로 비활성화 된 상태의 이미지에 즉시 액세스 할 수없는 그래픽을 표시하는 것이 번거롭다는 것입니다. 이제는 이것이 java.awt.Composite를 사용하여 즉시 수행 될 수 있다고 생각했습니다. (예를 들어 아이콘이 비활성화되도록 렌더링하는 방법을 알 필요가 없습니다.) 오직 회색 음영으로 변환 할 구현이없는 것 같습니다. 그래서 내 자신을 만들어야했습니다. ...java.awt.Composite를 어떻게 효과적으로 구현할 수 있습니까?

그런 말로하면 구현을 해킹했습니다 (그리고 예상 한대로 렌더링 됨). 하지만 모든 경우에 실제로 제대로 작동하는지 확신 할 수 없습니다 (복잡한 작업의 경우 Javadocs/CompositeContext가 매우 얇은 것처럼 보임). 그리고 내 구현에서 볼 수 있듯이, 관련된 래스터에 의해 지시되지 않는 형식으로 픽셀을 대량으로 읽고 쓸 수있는 간단한 방법이없는 것처럼 픽셀 단위로 처리하는 로터리 방식을 사용합니다.

더 자세한 문서/예제/힌트에 대한 안내는 환영합니다.

다음은 SSCCE입니다. DisabledComposite를 통해 (채색 된) GradientPaint를 렌더링하여 그라디언트를 회색조로 변환합니다. 실제 세계에서을 알지 못합니다. 무엇이 호출되는지 렌더링됩니다. 그라디언트는 실제로 예일뿐입니다 (미안하지만 너무 자주 사람들이 그것을 얻지 못하므로 이번에는이를 분명하게 할 것입니다).

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Composite; 
import java.awt.CompositeContext; 
import java.awt.Dimension; 
import java.awt.GradientPaint; 
import java.awt.Graphics; 
import java.awt.Graphics2D; 
import java.awt.RenderingHints; 
import java.awt.image.ColorModel; 
import java.awt.image.Raster; 
import java.awt.image.WritableRaster; 

import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 

public class CompositeSSCE implements Runnable { 

    static class DisabledComposite implements Composite { 
     @Override 
     public CompositeContext createContext(
      final ColorModel srcColorModel, 
      final ColorModel dstColorModel, 
      final RenderingHints hints) { 
      return new DisabledCompositeContext(srcColorModel, dstColorModel); 
     } 
    } 

    static class DisabledCompositeContext implements CompositeContext { 

     private final ColorModel srcCM; 
     private final ColorModel dstCM; 

     final static int PRECBITS = 22; 
     final static int WEIGHT_R = (int) ((1 << PRECBITS) * 0.299); 
     final static int WEIGHT_G = (int) ((1 << PRECBITS) * 0.578); 
     final static int WEIGHT_B = (int) ((1 << PRECBITS) * 0.114); 
     final static int SRCALPHA = (int) ((1 << PRECBITS) * 0.667); 

     DisabledCompositeContext(final ColorModel srcCM, final ColorModel dstCM) { 
      this.srcCM = srcCM; 
      this.dstCM = dstCM; 
     } 

     public void compose(final Raster src, final Raster dstIn, final WritableRaster dstOut) { 
      final int w = Math.min(src.getWidth(), dstIn.getWidth()); 
      final int h = Math.min(src.getHeight(), dstIn.getHeight()); 
      for (int y = 0; y < h; ++y) { 
       for (int x = 0; x < w; ++x) { 
        int rgb1 = srcCM.getRGB(src.getDataElements(x, y, null)); 
        int a1 = ((rgb1 >>> 24) * SRCALPHA) >> PRECBITS; 
        int gray = (
         ((rgb1 >> 16) & 0xFF) * WEIGHT_R + 
         ((rgb1 >> 8) & 0xFF) * WEIGHT_G + 
         ((rgb1  ) & 0xFF) * WEIGHT_B 
         ) >> PRECBITS; 
        int rgb2 = dstCM.getRGB(dstIn.getDataElements(x, y, null)); 
        int a2 = rgb2 >>> 24; 
        int r2 = (rgb2 >> 16) & 0xFF; 
        int g2 = (rgb2 >> 8) & 0xFF; 
        int b2 = (rgb2  ) & 0xFF; 
        // mix the two pixels 
        gray = gray * a1/255; 
        final int ta = a2 * (255 - a1); 
        r2 = gray + (r2 * ta/(255*255)); 
        g2 = gray + (g2 * ta/(255*255)); 
        b2 = gray + (b2 * ta/(255*255)); 
        a2 = a1 + (ta/255); 
        rgb2 = (a2 << 24) | (r2 << 16) | (g2 << 8) | b2; 
        Object data = dstCM.getDataElements(rgb2, null); 
        dstOut.setDataElements(x, y, data); 
       } 
      } 
     } 

     @Override 
     public void dispose() { 
      // nothing for this implementation 
     } 
    } 

    // from here on out its only the fluff to make this a runnable example 
    public static void main(String[] argv) { 
     Runnable r = new CompositeSSCE(); 
     SwingUtilities.invokeLater(r); 
    } 

    // simple component to use composite to render 
    static class DemoComponent extends JComponent { 
     // demonstrate rendering an icon in grayscale with the composite 
     protected void paintComponent(Graphics g) { 
      Graphics2D g2d = (Graphics2D) g; 
      GradientPaint p = new GradientPaint(0, 0, Color.GREEN, 127, 127, Color.BLUE, true); 
      g2d.setComposite(new DisabledComposite()); 
      g2d.setPaint(p); 
      g2d.fillRect(0, 0, getWidth(), getHeight()); 
     } 
    } 

    // Fluff to use the Composite in Swing 
    public void run() { 
     try { 
      JFrame f = new JFrame("Test grayscale composite"); 
      DemoComponent c = new DemoComponent(); 
      c.setPreferredSize(new Dimension(500, 300)); 
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
      f.setLayout(new BorderLayout()); 
      f.add(c, BorderLayout.CENTER); 
      f.pack(); 
      f.setVisible(true); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 

} 

답변

3

항상하는 BufferedImage을 만들 그레이 스케일 bufferedImage.createGraphics()을 사용하여 해당 이미지에 대한 Graphics 개체를 할 필요가 무엇이든 그린 다음 이미지의 그레이 스케일 복사본을 만들 수 javax.swing.GreyFilter를 사용할 수 있습니다.

.

SwingX의 BlendComposite과 사용자의 접근 방식을 비교하고 싶을 수도 있습니다. BlendComposite는 그레이 스케일을 허용하는 채도 모드를 가지고 있습니다. (또한 더 많은 모드가 있습니다.) 효율성에 대해

This page has a demo of BlendComposite.

, 나는 중간 단계가 있기 때문에 그들 사이에는 중요한 차이가 없습니다 기대와에서 내가 무엇을 볼 수있는, 모두 이미지 데이터의 완전한 사본. 그러나 제안한 첫 번째 방법을 사용하여 그레이 스케일 이미지를 유지하면 비 동적 컨트롤의 재 계산을 방지 할 수 있습니다.

위의 작업 중 하나를 수행하면 성능이 정확하며 원하는 결과를 얻을 수 있습니다.

의견을 말씀 드리 자면 구성 요소에 효과를 적용하기를 원할 것입니다. 이를 위해 JLayer을 사용할 수 있으며 Java 7에서만 사용할 수 있습니다. Javadoc에서 반투명 녹색을 중첩하는 예가 있습니다. 이것을 회색으로 바꿀 수 있습니다. 이전 버전의 Java에서 JLayer를 사용하려면 SwingX 프로젝트의 일부인 JXLayer을 사용할 수 있습니다.

+0

BlendComposite는 유용한 도구처럼 보입니다. 힌트를 주셔서 감사합니다. 비록 짤막한 것으로부터 compose() - 메소드의 모든 가능한 ColorModel에서 작동하지 않는 것처럼 보일지라도 실제로는 다른 ColorModel은 실제로 관련이 없습니다. "당신은 항상 BufferedImage를 만들 수 있습니다."에 관해서는 compose() - 메소드 구현에서 어떻게 할 수 있는지 보지 못했습니다. paintComponent()에서 어딘가에 할 수는 있지만 Composite를 설정 한 다음 일반 렌더링 체인을 진행하는 것보다 융통성이 떨어집니다. – Durandal

+0

@Durandal 모든 색상 모델에 적합한 지 여부는 잘 모르겠다. (나는 추측 할 수 있지만,이 컨텍스트에서 어떤 ColorModel이 사용되는지 알지 못한다.) 내가 아는 것은 무엇이며, 내가 제안한 이유는, SwingX는 공식 Swing 팀의 의견을 받았기 때문에 일반적인 용도로 사용할 수 있어야합니다. 필자의 첫 번째 제안으로 Composite를 사용하지 않을 것이고 paintComponent에서 할 것입니다 - 유연하고 더 많은 작업 (도면 크기로 이미지를 작성, 그리기, 필터링, 페인트) 및 캐시 ....). – Tom

+0

@Durandal 당신은 BufferedImage에 대한'Graphics'을 생성하고 그 그래픽 인스턴스로'paintComponent'를 호출 할 수 있습니다. – Tom

0

귀하의 질문을 올바르게 이해하지 못해 죄송합니다. maybe this이 도움이 될 수 있습니까? css를 사용하여 이미지를 회색조로 만듭니다.

this도 찾고 계실 수 있습니다. jquery와 canvas를 사용하여 이미지를 조작합니다.

관련 문제