배경 : "사용 중지됨"으로 이미지를 만들 수 있어야합니다. 일반적으로 제안되는 방법은 이미지를 그레이 스케일로 변환하고 그레이 스케일 된 이미지를 표시하는 것입니다. 단점은 이미지에서만 작동하므로 비활성화 된 상태의 이미지에 즉시 액세스 할 수없는 그래픽을 표시하는 것이 번거롭다는 것입니다. 이제는 이것이 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);
}
}
}
BlendComposite는 유용한 도구처럼 보입니다. 힌트를 주셔서 감사합니다. 비록 짤막한 것으로부터 compose() - 메소드의 모든 가능한 ColorModel에서 작동하지 않는 것처럼 보일지라도 실제로는 다른 ColorModel은 실제로 관련이 없습니다. "당신은 항상 BufferedImage를 만들 수 있습니다."에 관해서는 compose() - 메소드 구현에서 어떻게 할 수 있는지 보지 못했습니다. paintComponent()에서 어딘가에 할 수는 있지만 Composite를 설정 한 다음 일반 렌더링 체인을 진행하는 것보다 융통성이 떨어집니다. – Durandal
@Durandal 모든 색상 모델에 적합한 지 여부는 잘 모르겠다. (나는 추측 할 수 있지만,이 컨텍스트에서 어떤 ColorModel이 사용되는지 알지 못한다.) 내가 아는 것은 무엇이며, 내가 제안한 이유는, SwingX는 공식 Swing 팀의 의견을 받았기 때문에 일반적인 용도로 사용할 수 있어야합니다. 필자의 첫 번째 제안으로 Composite를 사용하지 않을 것이고 paintComponent에서 할 것입니다 - 유연하고 더 많은 작업 (도면 크기로 이미지를 작성, 그리기, 필터링, 페인트) 및 캐시 ....). – Tom
@Durandal 당신은 BufferedImage에 대한'Graphics'을 생성하고 그 그래픽 인스턴스로'paintComponent'를 호출 할 수 있습니다. – Tom