2012-11-29 66 views
7

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

} 

Trả lời

3

Bạn luôn có thể tạo ra một BufferedImage, vẽ bất cứ điều gì cần phải được màu xám quy mô cho đối tượng Graphics cho hình ảnh rằng việc sử dụng bufferedImage.createGraphics(), và sau đó sử dụng javax.swing.GreyFilter để tạo ra một bản sao màu xám quy mô của hình ảnh.

This page shows you how to use a Filter.

Bạn cũng có thể muốn so sánh cách tiếp cận của mình với sốcủa SwingX, điều mà tôi mong đợi cũng giống như bạn đang làm. BlendComposite có chế độ Saturation cho phép có thang màu xám. (Nó cũng có chế độ nhiều hơn nữa.)

This page has a demo of BlendComposite.

Về hiệu quả, tôi hy vọng không có sự khác biệt quan trọng giữa chúng, bởi vì có bước trung gian, và từ những gì tôi có thể thấy, đầy đủ các bản sao của dữ liệu hình ảnh với cả hai. Nhưng nếu bạn giữ lại hình ảnh được chia tỷ lệ màu xám bằng phương pháp đầu tiên tôi đề xuất, bạn có thể ngăn tính toán lại các điều khiển không động.

Nếu bạn thực hiện một trong những điều trên, hiệu suất sẽ chính xác và tôi hy vọng đó là những gì bạn thực sự muốn.

Từ nhận xét của bạn, tôi đoán bạn có thể chỉ muốn áp dụng hiệu ứng cho một thành phần. Đối với điều này bạn có thể sử dụng JLayer, chỉ có sẵn trong Java 7. Từ Javadoc có một ví dụ về phủ một màu xanh lá cây mờ. Bạn có thể thay thế bằng màu xám. Nếu bạn muốn sử dụng JLayer trong các phiên bản Java trước, bạn có thể sử dụng JXLayer, một phần của dự án SwingX.

+0

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

+0

@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

+0

@Durandal bạn có thể tạo 'Graphics' cho BufferedImage và sau đó gọi' paintComponent' với cá thể đồ họa đó. – Tom

0

Tôi rất tiếc nếu tôi không hiểu câu hỏi của bạn đúng cách nhưng maybe this sẽ giúp bạn? Nó sử dụng css để tạo ảnh màu xám.

Ngoài ra this có thể là những gì bạn đang tìm kiếm? Nó sử dụng jquery và canvas để thao tác hình ảnh.