Thông tin cơ bản: Tôi cần có thể tạo hình ảnh ở giao diện "đã tắt". Cách tiếp cận thường được đề xuất là chuyển đổi hình ảnh thành thang độ xám và hiển thị hình ảnh màu xám. Hạn chế là nó chỉ hoạt động với hình ảnh, làm cho nó cồng kềnh để hiển thị đồ họa, nơi bạn không có quyền truy cập ngay lập tức vào một hình ảnh ở trạng thái vô hiệu hóa. Bây giờ tôi nghĩ rằng điều này có thể được thực hiện trên bay với java.awt.Composite (và sau đó tôi sẽ không cần phải biết làm thế nào ví dụ một biểu tượng được thực hiện để làm cho nó bị vô hiệu hóa). Chỉ có vẻ như không có triển khai nào để chuyển sang màu xám, vì vậy tôi phải tạo riêng của mình ...Tôi làm cách nào để triển khai java.awt.Composite một cách hiệu quả?
Điều đó nói rằng, tôi đã cùng nhau triển khai (và hiển thị những gì tôi mong đợi). Nhưng tôi không chắc chắn nó sẽ thực sự hoạt động đúng cho tất cả các trường hợp (Javadocs của Composite/CompositeContext có vẻ rất mỏng cho một hoạt động phức tạp như vậy). Và như bạn có thể thấy từ việc thực hiện của tôi, tôi đi một vòng xoay để xử lý pixel theo pixel, vì dường như không có cách đơn giản để đọc/ghi pixel với số lượng lớn theo định dạng không được quyết định bởi các raster liên quan.
Bất kỳ con trỏ nào đến tài liệu/ví dụ/gợi ý mở rộng đều được chào đón.
Đây là SSCCE - nó hiển thị GradientPaint (màu) thông qua DisabledComposite để chuyển đổi độ dốc thành thang độ xám. Lưu ý rằng trong thế giới thực, bạn sẽ không biết những gì được hiển thị với những cuộc gọi nào. Gradient thực sự chỉ là một ví dụ (xin lỗi, nhưng thường thì mọi người không hiểu điều đó, vì vậy tôi sẽ làm cho nó rõ ràng lần này).
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 trông giống như một Công cụ hữu ích, cảm ơn gợi ý. Mặc dù từ một cái nhìn nhanh chóng nó có vẻ như là nếu không làm việc với mọi ColorModel có thể trong phương thức soạn() của nó, có lẽ các ColorModels khác không liên quan trong thực tế ?. Đối với "Bạn luôn có thể tạo một BufferedImage", tôi không thấy làm thế nào tôi có thể làm điều đó trong compose() - phương pháp implementatin. Làm điều đó ở đâu đó trong paintComponent() sẽ là có thể, nhưng nó ít linh hoạt hơn nhiều so với việc chỉ thiết lập Composite và sau đó tiếp tục với chuỗi kết xuất bình thường. – Durandal
@Durandal Tôi không biết liệu nó có phù hợp với tất cả các mẫu màu (và tôi thực sự không biết ColorModel được sử dụng gì trong ngữ cảnh này, mặc dù tôi có thể đoán), những gì tôi biết và lý do tôi đề xuất là SwingX có/có đầu vào từ nhóm Swing chính thức, vì vậy nó phải linh hoạt để sử dụng phổ biến. Với đề nghị đầu tiên của tôi, bạn sẽ không sử dụng Composite, và tôi sẽ làm điều đó trong paintComponent - nó chỉ là linh hoạt, chỉ cần thêm công việc (tạo ra hình ảnh với kích thước bản vẽ, vẽ nó, lọc nó, tô nó và cache người cuối cùng sử dụng nếu kích thước giống nhau) .... – Tom
@Durandal bạn có thể tạo 'Graphics' cho BufferedImage và sau đó gọi' paintComponent' với cá thể đồ họa đó. – Tom