2012-11-29 12 views
7

背景:私は、「無効」な外観の画像を作成できる必要があります。一般的に示唆されている方法は、画像をグレースケールに変換し、グレースケール画像を表示することです。欠点は、画像でのみ機能するため、無効状態の画像にすぐにアクセスできないグラフィックを表示するのが面倒です。 これはjava.awt.Compositeを使って即座に実行できると思いました(アイコンを無効にするためにアイコンがどのように実装されているか知る必要はありません)。グレイスケールに変換する実装がないように思われるので、自分で作成する必要がありました。java.awt.Compositeを効率的に実装するにはどうすればよいですか?

私は実装をハッキングしました。しかし、実際にすべてのケースで正しく動作するかどうかはわかりません(複雑な操作の場合、Composite/CompositeContextのJavadocは非常に薄いようです)。そして私の実装から見ると、関連するラスタによって指示されていない形式でピクセルを一括して読み書きする簡単な方法がないように、ピクセル単位で処理するラウンドアバウトの方法があります。

詳細なドキュメント/サンプル/ヒントへのポインタは、歓迎します。

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.createGraphics()を使用して、そのイメージのグレースケールGraphics対象になり、その後、画像のグレースケールのコピーを作成するjavax.swing.GreyFilterを使用する必要があるものは何でも描き、BufferedImageを作成することができます。

This page shows you how to use a Filter

また、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を使ってイメージを操作します。

関連する問題