soc*_*soc 29 java png scala image image-processing
我有约.6000个PNG文件(256*256像素),并希望将它们组合成一个大PNG,以编程方式保存所有这些文件.
最好/最快的方法是什么?
(目的是在纸上打印,因此使用某些网络技术不是一种选择,只有一个单一图片文件将消除许多使用错误.)
我尝试了fahd的建议,NullPointerException但当我尝试创建一个BufferedImage宽24576像素,高15360像素的时候,我得到了一个.有任何想法吗?
dog*_*ane 54
创建一个要写入的大图像.根据您想要的行数和列数来计算其维度.
BufferedImage result = new BufferedImage(
width, height, //work these out
BufferedImage.TYPE_INT_RGB);
Graphics g = result.getGraphics();
Run Code Online (Sandbox Code Playgroud)
现在循环浏览图像并绘制它们:
for(String image : images){
BufferedImage bi = ImageIO.read(new File(image));
g.drawImage(bi, x, y, null);
x += 256;
if(x > result.getWidth()){
x = 0;
y += bi.getHeight();
}
}
Run Code Online (Sandbox Code Playgroud)
最后把它写到文件中:
ImageIO.write(result,"png",new File("result.png"));
Run Code Online (Sandbox Code Playgroud)
前段时间我有一些相似的需求(巨大的图像 - 而且,我的情况是16位深度 - 将它们完全放在内存中不是一种选择).我结束了PNG库的编码,以顺序方式进行读/写.如果有人发现它有用,它就在这里.
更新:这是一个示例代码:
/**
* Takes several tiles and join them in a single image
*
* @param tiles Filenames of PNG files to tile
* @param dest Destination PNG filename
* @param nTilesX How many tiles per row?
*/
public class SampleTileImage {
public static void doTiling(String tiles[], String dest, int nTilesX) {
int ntiles = tiles.length;
int nTilesY = (ntiles + nTilesX - 1) / nTilesX; // integer ceil
ImageInfo imi1, imi2; // 1:small tile 2:big image
PngReader pngr = new PngReader(new File(tiles[0]));
imi1 = pngr.imgInfo;
PngReader[] readers = new PngReader[nTilesX];
imi2 = new ImageInfo(imi1.cols * nTilesX, imi1.rows * nTilesY, imi1.bitDepth, imi1.alpha, imi1.greyscale,
imi1.indexed);
PngWriter pngw = new PngWriter(new File(dest), imi2, true);
// copy palette and transparency if necessary (more chunks?)
pngw.copyChunksFrom(pngr.getChunksList(), ChunkCopyBehaviour.COPY_PALETTE
| ChunkCopyBehaviour.COPY_TRANSPARENCY);
pngr.readSkippingAllRows(); // reads only metadata
pngr.end(); // close, we'll reopen it again soon
ImageLineInt line2 = new ImageLineInt(imi2);
int row2 = 0;
for (int ty = 0; ty < nTilesY; ty++) {
int nTilesXcur = ty < nTilesY - 1 ? nTilesX : ntiles - (nTilesY - 1) * nTilesX;
Arrays.fill(line2.getScanline(), 0);
for (int tx = 0; tx < nTilesXcur; tx++) { // open several readers
readers[tx] = new PngReader(new File(tiles[tx + ty * nTilesX]));
readers[tx].setChunkLoadBehaviour(ChunkLoadBehaviour.LOAD_CHUNK_NEVER);
if (!readers[tx].imgInfo.equals(imi1))
throw new RuntimeException("different tile ? " + readers[tx].imgInfo);
}
for (int row1 = 0; row1 < imi1.rows; row1++, row2++) {
for (int tx = 0; tx < nTilesXcur; tx++) {
ImageLineInt line1 = (ImageLineInt) readers[tx].readRow(row1); // read line
System.arraycopy(line1.getScanline(), 0, line2.getScanline(), line1.getScanline().length * tx,
line1.getScanline().length);
}
pngw.writeRow(line2, row2); // write to full image
}
for (int tx = 0; tx < nTilesXcur; tx++)
readers[tx].end(); // close readers
}
pngw.end(); // close writer
}
public static void main(String[] args) {
doTiling(new String[] { "t1.png", "t2.png", "t3.png", "t4.png", "t5.png", "t6.png" }, "tiled.png", 2);
System.out.println("done");
}
}
Run Code Online (Sandbox Code Playgroud)
我没有看到"如果没有处理和重新编码",它将如何成为可能.如果你坚持使用Java然后我就建议你使用JAI(项目页面这里).有了它,你将创建一个大的BufferedImage,加载较小的图像,并在较大的图像上绘制它们.
或者只使用ImageMagick montage:
montage *.png output.png
Run Code Online (Sandbox Code Playgroud)
有关更多信息montage,请参阅用法.