![](/img/trans.png)
[英]java.awt.image.BufferedImage 24-bit RGB to 8-bit Grayscale conversion using custom ColorSpace
[英]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.