How to combine multiple PNGs into one big PNG file?

后端 未结 9 1999
天涯浪人
天涯浪人 2020-11-28 08:26

I have approx. 6000 PNG files (256*256 pixels) and want to combine them into a big PNG holding all of them programmatically.

What\'s the best/fastest way to do that?

相关标签:
9条回答
  • 2020-11-28 09:21

    simple python script for joining tiles into one big image:

    import Image
    
    TILESIZE = 256
    ZOOM = 15
    def merge_images( xmin, xmax, ymin, ymax, output) :
        out = Image.new( 'RGB', ((xmax-xmin+1) * TILESIZE, (ymax-ymin+1) * TILESIZE) ) 
    
        imx = 0;
        for x in range(xmin, xmax+1) :
            imy = 0
            for y in range(ymin, ymax+1) :
                tile = Image.open( "%s_%s_%s.png" % (ZOOM, x, y) )
                out.paste( tile, (imx, imy) )
                imy += TILESIZE
            imx += TILESIZE
    
        out.save( output )
    

    run:

    merge_images(18188, 18207, 11097, 11111, "output.png")
    

    works for files named like %ZOOM_%XCORD_%YCORD.png , for example 15_18188_11097.png

    0 讨论(0)
  • 2020-11-28 09:26

    Use imagemagick's montage like this:

    montage *.png montage.png
    

    You can find more information on the parameters here

    Good luck

    0 讨论(0)
  • 2020-11-28 09:29

    I had some similar need some time ago (huge images -and, I my case with 16 bitdepth- to have them fully in memory was not an option). And I ended coding a PNG library to do the read/write in a sequential way. In case someone find it useful, it's here.

    Updated: here's a sample code:

    /**
     * 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");
            }
    }
    
    0 讨论(0)
提交回复
热议问题