使用具有 alpha 的 PNG 改进 Java ImageIO read/write
Improving Java ImageIO read/write with PNG that has alpha
我有一个大的 PNG 图像 (600x600),我的应用程序使图像不透明并写出文件。问题是 ImageIO 的性能很糟糕。还有其他选择吗?我要求图像不透明。以下是我正在做的事情:
BufferedImage buf = ImageIO.read(localUrl);
float[] scales = {1f, 1f, 1f, 1f}; // R, G, B, A
float[] offsets = {0f, 0f, 0f, 1f}; // R, G, B, A
RescaleOp rescaler = new RescaleOp(scales, offsets, null);
BufferedImage opaque = rescaler.filter(buf, null);
File outputfile = new File(localUrl.getPath());
ImageIO.write(opaque, "png", outputfile);
如果您只是想摆脱透明度,那么在这里使用 RescaleOp
并不是完全必要的。一个更简单的解决方案是在背景上绘制图像,如下所示:
Color bgColor = Color.WHITE;
BufferedImage foreground = ImageIO.read(localUrl);
int width = foreground.getWidth();
int height = foreground.getHeight();
BufferedImage background = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = background.createGraphics();
g.setColor(bgColor);
g.fillRect(0, 0, width, height);
g.drawImage(foreground, 0, 0, null);
g.dispose();
File outputfile = new File(localUrl.getPath());
ImageIO.write(background, "png", outputfile);
这似乎是一种更简单的处理方法,可能需要更少的处理能力,但我怀疑会有很大的不同。如果您对从硬盘驱动器读取/写入图像的速度不满意,您几乎无能为力。
与PNGJ:
private static void removeAlpha(File file1,File file2) {
PngReaderByte reader = new PngReaderByte(file1);
ImageInfo info = reader.imgInfo;
PngWriter writer = new PngWriter(file2,info);
writer.setFilterPreserve(true);
writer.setCompLevel(6);
writer.copyChunksFrom(reader.getChunksList(), ChunkCopyBehaviour.COPY_ALL_SAFE);
if( info.bitDepth != 8 ||info.channels!=4) throw new RuntimeException("expected 8bits RGBA ");
while(reader.hasMoreRows()) {
ImageLineByte line = reader.readRowByte();
byte [] buf = line.getScanlineByte();
for(int i=0,j=3;i<info.cols;i++,j+=4)
buf[j]=(byte)255;
writer.writeRow(line);
}
reader.end();
writer.end();
}
我不确定这是否会提高性能。请记住,(与 Parker Hoyes 的回答相反)这只会杀死 alpha 通道,但它不会与某些背景颜色混合(因此 "original" 颜色将出现在以前透明的现在不透明的区域中).
我有一个大的 PNG 图像 (600x600),我的应用程序使图像不透明并写出文件。问题是 ImageIO 的性能很糟糕。还有其他选择吗?我要求图像不透明。以下是我正在做的事情:
BufferedImage buf = ImageIO.read(localUrl);
float[] scales = {1f, 1f, 1f, 1f}; // R, G, B, A
float[] offsets = {0f, 0f, 0f, 1f}; // R, G, B, A
RescaleOp rescaler = new RescaleOp(scales, offsets, null);
BufferedImage opaque = rescaler.filter(buf, null);
File outputfile = new File(localUrl.getPath());
ImageIO.write(opaque, "png", outputfile);
如果您只是想摆脱透明度,那么在这里使用 RescaleOp
并不是完全必要的。一个更简单的解决方案是在背景上绘制图像,如下所示:
Color bgColor = Color.WHITE;
BufferedImage foreground = ImageIO.read(localUrl);
int width = foreground.getWidth();
int height = foreground.getHeight();
BufferedImage background = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = background.createGraphics();
g.setColor(bgColor);
g.fillRect(0, 0, width, height);
g.drawImage(foreground, 0, 0, null);
g.dispose();
File outputfile = new File(localUrl.getPath());
ImageIO.write(background, "png", outputfile);
这似乎是一种更简单的处理方法,可能需要更少的处理能力,但我怀疑会有很大的不同。如果您对从硬盘驱动器读取/写入图像的速度不满意,您几乎无能为力。
与PNGJ:
private static void removeAlpha(File file1,File file2) {
PngReaderByte reader = new PngReaderByte(file1);
ImageInfo info = reader.imgInfo;
PngWriter writer = new PngWriter(file2,info);
writer.setFilterPreserve(true);
writer.setCompLevel(6);
writer.copyChunksFrom(reader.getChunksList(), ChunkCopyBehaviour.COPY_ALL_SAFE);
if( info.bitDepth != 8 ||info.channels!=4) throw new RuntimeException("expected 8bits RGBA ");
while(reader.hasMoreRows()) {
ImageLineByte line = reader.readRowByte();
byte [] buf = line.getScanlineByte();
for(int i=0,j=3;i<info.cols;i++,j+=4)
buf[j]=(byte)255;
writer.writeRow(line);
}
reader.end();
writer.end();
}
我不确定这是否会提高性能。请记住,(与 Parker Hoyes 的回答相反)这只会杀死 alpha 通道,但它不会与某些背景颜色混合(因此 "original" 颜色将出现在以前透明的现在不透明的区域中).