簡體   English   中英

在java中,如何將java.awt.image.BufferedImage寫入8位png文件?

[英]In java, how do you write a java.awt.image.BufferedImage to an 8-bit png file?

我試圖從java.awt.image.BufferedImage寫出一個png文件。 一切正常,但生成的png是一個32位文件。

有沒有辦法讓png文件成為8位? 圖像是灰度的,但我確實需要透明度,因為這是一個疊加圖像。 我正在使用java 6,我寧願返回一個OutputStream,這樣我就可以讓調用類處理將文件寫入磁盤/數據庫。

以下是代碼的相關部分:

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

無論源圖像是什么,imageio png writer中的構建都會在我使用它的所有平台上寫入32位png文件。 您還應該知道,許多人抱怨所產生的壓縮比png格式的壓縮要低得多。 有幾個獨立的png庫可用於指定確切的格式,但我實際上並沒有任何經驗。

這是一個有趣的問題......已經很晚了,明天我會做實驗。 我將首先嘗試使用BufferedImage.TYPE_BYTE_INDEXED(可能在繪制之后)來查看Java是否足夠智能以生成8位PNG。
或許某些圖像庫可以允許這樣做。

[編輯]幾年后......實際上,我當時制作了代碼,但忘了更新這個帖子......我使用了Kat指出的代碼 ,稍微改進了透明度的處理,並節省了PNG格式而不是Gif格式。 它可用於制作具有全部或全無透明度的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);
  }
}

我找到了如何將RGBA轉換為索引的答案: http//www.eichberger.de/2007/07/transparent-gifs-in-java.html

但是,生成的8位png文件只有100%或0%的透明度。 您可以調整IndexColorModel數組,但我們已經決定將生成的文件(什么是疊加掩碼)放入底層jpg中,並使用靜態基礎作為透明疊加層。

感謝您的回復,我打算嘗試使用IndexColorModel進行TYPE_BYTE_INDEXED ,但是如果ImageIO寫出32位,無論看起來我是在浪費我的時間。

我試圖寫出的圖像可能非常大(高達8000x4000)但只是下面圖像的簡單掩模,因此只有~30%透明灰色和100%透明切口。 我會使用GIF,但IE6似乎在顯示一個大的時候有問題。

它只生成一次並在內部設置類型屏幕中生成,因此性能也不是問題,但它必須在Java代碼中完成,而不是由脫機實用程序完成。

您指定的庫可能會在寫入時用於轉換它...我將去檢查它。

如果有人有更好的方法,請告訴我!

謝謝!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM