8

java.awt.image.BufferedImageからpngファイルを書き出そうとしています。すべて正常に動作しますが、結果のpngは32ビットファイルです。

pngファイルを8ビットにする方法はありますか?画像はグレースケールですが、これはオーバーレイ画像であるため、透明度が必要です。私はjava6を使用していますが、OutputStreamを返して、呼び出し元のクラスがファイルをdisk/dbに書き出すことを処理できるようにしたいと思います。

コードの関連部分は次のとおりです。

 public static ByteArrayOutputStream createImage(InputStream originalStream)
            throws IOException {

        ByteArrayOutputStream oStream = null;

        java.awt.Image newImg = javax.imageio.ImageIO.read(originalStream);
        int imgWidth = newImg.getWidth(null);
        int imgHeight = newImg.getHeight(null);
        java.awt.image.BufferedImage bim = new java.awt.image.BufferedImage(imgWidth,
                imgHeight, java.awt.image.BufferedImage.TYPE_INT_ARGB);

        Color bckgrndColor = new Color(0x80, 0x80, 0x80);

        Graphics2D gf = (Graphics2D)bim.getGraphics();

        // set transparency for fill image
        gf.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
        gf.setColor(bckgrndColor);
        gf.fillRect(0, 0, imgWidth, imgHeight);

        oStream = new ByteArrayOutputStream();
        javax.imageio.ImageIO.write(bim, "png", oStream);
        oStream.close();

        return oStream;
    }
4

4 に答える 4

4

imageio png ライターのビルドは、ソース画像が何であれ、私が使用したすべてのプラットフォームで 32 ビットの png ファイルを書き込みます。また、結果として得られる圧縮が png 形式で可能なものよりもはるかに低いと多くの人が不満を述べていることにも注意してください。正確な形式を指定できる独立したpngライブラリがいくつかありますが、実際にはそれらのいずれも経験していません。

于 2008-11-06T18:23:35.440 に答える
1

興味深い質問です...遅くなりました。明日実験します。最初に BufferedImage.TYPE_BYTE_INDEXED を (おそらく描画後に) 使用して、Java が 8 ビット PNG を生成できるほどスマートかどうかを確認します。
または、一部の画像ライブラリでそれが可能になる場合があります。

[編集] 数年後...実際、私は当時コードを作成しましたが、このスレッドを更新するのを忘れていました... Kat によって指摘されたコードを使用し、透明性の処理と保存を少し改良しましたGIF形式ではなくPNG形式。オール オア ナッシングの透明度を持つ 8 ビットの PNG ファイルを作成する際に機能します。

ImageUtilクラス を使用して、http: //bazaar.launchpad.net/~philho/+junk/Java/view/head:/Tests/src/org/philhosoft/tests/image/AddTransparency.javaで動作するテスト ファイルを見つけることができます。.

コードはそれほど大きくないので、後世のために、いくつかの行を節約するために JavaDoc なしでここに投稿します。

public class ImageUtil
{
  public static int ALPHA_BIT_MASK = 0xFF000000;

  public static BufferedImage imageToBufferedImage(Image image, int width, int height)
  {
    return imageToBufferedImage(image, width, height, BufferedImage.TYPE_INT_ARGB);
  }

  public static BufferedImage imageToBufferedImage(Image image, int width, int height, int type)
  {
    BufferedImage dest = new BufferedImage(width, height, type);
    Graphics2D g2 = dest.createGraphics();
    g2.drawImage(image, 0, 0, null);
    g2.dispose();
    return dest;
  }

  public static BufferedImage convertRGBAToIndexed(BufferedImage srcImage)
  {
    // Create a non-transparent palletized image
    Image flattenedImage = transformTransparencyToMagenta(srcImage);
    BufferedImage flatImage = imageToBufferedImage(flattenedImage,
        srcImage.getWidth(), srcImage.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
    BufferedImage destImage = makeColorTransparent(flatImage, 0, 0);
    return destImage;
  }

  private static Image transformTransparencyToMagenta(BufferedImage image)
  {
    ImageFilter filter = new RGBImageFilter()
    {
      @Override
      public final int filterRGB(int x, int y, int rgb)
      {
        int pixelValue = 0;
        int opacity = (rgb & ALPHA_BIT_MASK) >>> 24;
        if (opacity < 128)
        {
          // Quite transparent: replace color with transparent magenta
          // (traditional color for binary transparency)
          pixelValue = 0x00FF00FF;
        }
        else
        {
          // Quite opaque: get pure color
          pixelValue = (rgb & 0xFFFFFF) | ALPHA_BIT_MASK;
        }
        return pixelValue;
      }
    };

    ImageProducer ip = new FilteredImageSource(image.getSource(), filter);
      return Toolkit.getDefaultToolkit().createImage(ip);
  }

  public static BufferedImage makeColorTransparent(BufferedImage image, int x, int y)
  {
    ColorModel cm = image.getColorModel();
    if (!(cm instanceof IndexColorModel))
      return image; // No transparency added as we don't have an indexed image

    IndexColorModel originalICM = (IndexColorModel) cm;
    WritableRaster raster = image.getRaster();
    int colorIndex = raster.getSample(x, y, 0); // colorIndex is an offset in the palette of the ICM'
    // Number of indexed colors
    int size = originalICM.getMapSize();
    byte[] reds = new byte[size];
    byte[] greens = new byte[size];
    byte[] blues = new byte[size];
    originalICM.getReds(reds);
    originalICM.getGreens(greens);
    originalICM.getBlues(blues);
    IndexColorModel newICM = new IndexColorModel(8, size, reds, greens, blues, colorIndex);
    return new BufferedImage(newICM, raster, image.isAlphaPremultiplied(), null);
  }
}
于 2008-11-06T00:44:14.157 に答える
1

ここで RGBA をインデックス付きに変換する方法に関する答えを見つけました: http://www.eichberger.de/2007/07/transparent-gifs-in-java.html

ただし、結果として得られる 8 ビットの png ファイルは、100% または 0% の透明度しかありません。おそらく IndexColorModel 配列を微調整できますが、生成されたファイル (オーバーレイ マスク) をアンダーレイ jpg にし、静的ベースを透明なオーバーレイとして使用することにしました。

于 2008-11-06T21:26:34.243 に答える
0

応答してくれてありがとう、私はIndexColorModelで試してみるつもりでしたが、TYPE_BYTE_INDEXEDそれでも可能性がありますが、ImageIOが32ビットを書き出す場合、そこで時間を無駄にしているように見えます。

私が書き出そうとしている画像は非常に大きくなる可能性がありますが(最大8000x4000)、下の画像の単純なマスクであるため、最大30%の透明な灰色と100%の透明な切り欠きしかありません。GIFを使用しますが、IE6ではそれほど大きなGIFを表示するのに問題があるようです。

これは、内部セットアップタイプ画面で一度だけ生成されるため、パフォーマンスも問題にはなりませんが、オフラインユーティリティではなく、Javaコード内で実行する必要があります。

あなたが指定したライブラリは、書き込み中にそれを変換するために使用される可能性があります...私はそれをチェックするつもりです。

誰かがもっと良い方法を持っているなら、私に知らせてください!

ありがとう!

于 2008-11-06T20:10:30.700 に答える