복붙노트

[SCALA] 어떻게 하나 개의 큰 PNG 파일에 여러 개의 PNG 파일을 결합?

SCALA

어떻게 하나 개의 큰 PNG 파일에 여러 개의 PNG 파일을 결합?

나는 약이있다. 6000 개 PNG 파일 (256 * 256 픽셀) 및 프로그래밍 모두를 들고 큰 PNG로 결합하고 싶다.

그렇게 할 수있는 최선의 / 가장 빠른 방법은 무엇입니까?

(목적은 그래서, 그림 파일이 많은 사용 오류를 제거 할 옵션을 선택하지 않습니다 일부 웹 기술을 사용하고 하나를 가지고, 용지에 인쇄됩니다.)

나는 파드의 제안을 시도하지만 높은 폭 24,576 픽셀 15,360 픽셀 BufferedImage를 만들려고 할 때 나는 NullPointerException이 얻을. 어떤 아이디어?

해결법

  1. ==============================

    1.당신이 쓸 것이다 큰 이미지를 만듭니다. 당신이 원하는 얼마나 많은 행과 열을 기반으로 차원을 작업 할 수 있습니다.

    당신이 쓸 것이다 큰 이미지를 만듭니다. 당신이 원하는 얼마나 많은 행과 열을 기반으로 차원을 작업 할 수 있습니다.

        BufferedImage result = new BufferedImage(
                                   width, height, //work these out
                                   BufferedImage.TYPE_INT_RGB);
        Graphics g = result.getGraphics();
    

    이제 이미지를 통해 루프는 그들을 잡아 :

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

    마지막으로 파일에 쓰는 :

        ImageIO.write(result,"png",new File("result.png"));
    
  2. ==============================

    2.나는 (완전히 메모리에이 옵션이 아니었다 16 bitdepth-와 나는 내 경우, 큰 이미지 -와) 몇 시간 전에 몇 가지 유사한 필요가 있었다. 그리고 순차적 인 방법으로 읽기 / 쓰기를 할 수있는 PNG 라이브러리를 코딩했다. 경우 누군가 그것은 여기, 유용 찾을 수 있습니다.

    나는 (완전히 메모리에이 옵션이 아니었다 16 bitdepth-와 나는 내 경우, 큰 이미지 -와) 몇 시간 전에 몇 가지 유사한 필요가 있었다. 그리고 순차적 인 방법으로 읽기 / 쓰기를 할 수있는 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");
            }
    }
    
  3. ==============================

    3.나는 그것이 "처리 및 재 인코딩없이"가능할 것이다 표시되지 않습니다. 당신이 자바를 사용하여 주장하는 경우 난 그냥 당신이 JAI (프로젝트 페이지 여기)를 사용하는 것이 좋습니다. 당신은 하나의 큰 BufferedImage를 만드는 작은 이미지를로드하고 더 큰 하나를 그릴 것이라고으로.

    나는 그것이 "처리 및 재 인코딩없이"가능할 것이다 표시되지 않습니다. 당신이 자바를 사용하여 주장하는 경우 난 그냥 당신이 JAI (프로젝트 페이지 여기)를 사용하는 것이 좋습니다. 당신은 하나의 큰 BufferedImage를 만드는 작은 이미지를로드하고 더 큰 하나를 그릴 것이라고으로.

    아니면 그냥 ImageMagick이 몽타주를 사용합니다 :

    montage *.png output.png
    

    몽타주에 대한 자세한 내용은 사용을 참조하십시오.

  4. ==============================

    4.PNG 형식은 타일에 대한 지원이 없다, 그래서 당신은 최소한 압축 해제 및 데이터 스트림을 다시 압축에서 탈출 할 수있는 방법은 없습니다. 모든 이미지의 팔레트가 동일 (또는 모든 결석) 인 경우, 이것은 당신이 정말로해야 할 유일한 일이다. (나는 또한 이미지가 인터레이스되지 않습니다 있으리라 믿고있어.)

    PNG 형식은 타일에 대한 지원이 없다, 그래서 당신은 최소한 압축 해제 및 데이터 스트림을 다시 압축에서 탈출 할 수있는 방법은 없습니다. 모든 이미지의 팔레트가 동일 (또는 모든 결석) 인 경우, 이것은 당신이 정말로해야 할 유일한 일이다. (나는 또한 이미지가 인터레이스되지 않습니다 있으리라 믿고있어.)

    당신은 한 번에 PNG 파일 오픈 한 "행"을 가진 데이터 스트림에서 적절한 크기의 청크를 읽고 출력 스트림을 작성, 스트리밍 방식으로이 작업을 수행 할 수 있습니다. 이 방법은 메모리에 전체 이미지를 보관할 필요가없는 것입니다. 가장 효율적인 방법은 자신을 libpng를 상단에이 프로그램을하는 것입니다. 당신 때문에 화소 예측의 메모리에 픽셀 조금 더보다 주사선을 유지해야 할 수도 있습니다.

    그러나 단지 ImageMagick를, netpbm의 명령 줄 유틸리티를 사용하거나 비슷한 당신에게 약간의 이득이 될 것인가에 대한 개발 많은 시간을 절약 할 수 있습니다.

  5. ==============================

    5.다른 사람들이 지적했듯이, 자바를 사용하는 것은 반드시 여기에 가장 좋은 방법이 아니다.

    다른 사람들이 지적했듯이, 자바를 사용하는 것은 반드시 여기에 가장 좋은 방법이 아니다.

    자바, 당신의 최선의 방법을 사용하려고하는 경우 - 당신은 당신이 메모리 여러 번에 전체 데이터 집합을 읽은 다음 다시 그것을 쓸 수 있도록 메모리에 충분히 짧은있어 가정 -와의 RenderedImage을 구현하는 것입니다 수요에 따라 디스크 떨어져 당신의 PNG 파일을 읽 클래스입니다. 당신이 당신의 자신의 새로운 BufferedImage를 만든 다음 그것을 작성하려고하면, PNG 작가는 데이터의 추가 사본이 생성됩니다. 당신이 당신의 자신의 RenderedImage를 작성하는 경우, 당신은 ImageIO.write (myImageSet, "PNG", myFileName)에 전달할 수 있습니다. 희망 그들은 모두 같은 것 - 당신은 당신의 첫번째 PNG에서의 SampleModel와 ColorModel의 정보를 복사 할 수 있습니다.

    당신은 전체 이미지가 여러 타일 (원본 이미지 당 하나 개의 타일) 인 척하면, ImageIO.write는 전체 이미지 데이터 세트의 크기 가지는 WritableRaster를 생성하며, 그것을 채우기 위해 RenderedImage.copyData의 구현을 호출합니다 데이터. setRect (DX, DY, 래스터) 방법을 사용하여 - - 당신이 충분한 메모리가있는 경우, 이것은 당신이 데이터의 거대한 목표 세트를 얻을 그냥 그것으로 모든 이미지 데이터를 덤프 할 수 있기 때문에 (갈 수있는 가장 쉬운 방법은 다음 ) 다시에 대해 걱정할 필요가 없습니다. 나는이 메모리를 절약 할 수 있는지 여부를 테스트하지 않은,하지만 그것을해야 나에게 보인다.

    당신은 전체 이미지가 하나의 타일 인 척하는 경우 또는, ImageIO.write는 래스터를 들어으로 getTile (0,0)를 사용하여, 그 전체 이미지에 해당하는 대응을 요청합니다. 그래서 당신은 차례로 자신의 DataBuffer를 만들 수 있습니다 자신의 래스터를 만들어야합니다. 나는이 방법을 시도했을 때, 최소 메모리 사용량이 있음을 성공적으로 15360x25600 RGB PNG가 기록 된 이미지의 픽셀 당 겨우 4 바이트 이상이다, (우연히 스칼라에서), 그래서 약간의 오버 헤드를 위 한 전체 이미지에있다 -Xmx1700M했다 썼다 기억.

    안타깝게도 PNG 작가의 기본 구현은 메모리에 전체 픽셀 배열을한다고 가정하지만 - 그것은 덩어리 괜찮 작동합니다 - PNG 데이터 형식 자체는 메모리에 전체 이미지를 필요 아니다.

  6. ==============================

    6.빗질 이미지

    빗질 이미지

    private static void combineALLImages(String screenNames, int screens) throws IOException, InterruptedException {
        System.out.println("screenNames --> D:\\screenshots\\screen   screens --> 0,1,2 to 10/..");
        int rows = screens + 1;
        int cols = 1;
        int chunks = rows * cols ; 
    
         File[] imgFiles = new File[chunks];
        String files = "";
        for (int i = 0; i < chunks; i++) {
            files = screenNames + i + ".jpg";
            imgFiles[i] = new File(files);          
            System.out.println(screenNames + i + ".jpg"+"\t Screens : "+screens);    
    
        }
    
        BufferedImage sample = ImageIO.read(imgFiles[0]);
        //Initializing the final image
        BufferedImage finalImg = new BufferedImage(sample.getWidth() * cols, sample.getHeight() * rows, sample.getType());
    
        int index = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                BufferedImage temp = ImageIO.read(imgFiles[index]);
                finalImg.createGraphics().drawImage(temp, sample.getWidth() * j, sample.getHeight() * i, null);
                System.out.println(screenNames + index + ".jpg");
                index++;
            }
        }
        File final_Image = new File("D:\\Screenshots\\FinalImage.jpg");
        ImageIO.write(finalImg, "jpeg", final_Image);
    
    }
    
  7. ==============================

    7.당신은 다른 (무손실) 이미지 형식 떨어져 일을 튀는 것이 가장 좋은 선택 일 수 있습니다. (당신은 기껏 타일의 한 행을 저장해야하므로이 디스크에 단지 하나의 큰 배열의 프로그래밍 방식에 타일을 넣어)하지만, 픽셀 당 12 바이트 (공간이 매우 낭비이다 PPM은 사용에 죽은 쉽습니다! ).

    당신은 다른 (무손실) 이미지 형식 떨어져 일을 튀는 것이 가장 좋은 선택 일 수 있습니다. (당신은 기껏 타일의 한 행을 저장해야하므로이 디스크에 단지 하나의 큰 배열의 프로그래밍 방식에 타일을 넣어)하지만, 픽셀 당 12 바이트 (공간이 매우 낭비이다 PPM은 사용에 죽은 쉽습니다! ).

    이어서 거대 PNG 형식으로 중간 및 회전을 취하는 표준 컨버터 (예컨대 ppm2png)를 사용한다.

  8. ==============================

    8.하나 개의 큰 이미지로 타일에 합류에 대한 간단한 파이썬 스크립트 :

    하나 개의 큰 이미지로 타일에 합류에 대한 간단한 파이썬 스크립트 :

    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 )
    

    운영:

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

    예를 들어 15_18188_11097.png를 들어, % ZOOM_ % XCORD_ % YCORD.png처럼라는 이름의 파일에 사용

  9. ==============================

    9.이 같은 사용 ImageMagick과의 몽타주 :

    이 같은 사용 ImageMagick과의 몽타주 :

    montage *.png montage.png
    

    당신은 여기에서 매개 변수에 대한 자세한 정보를 찾을 수 있습니다

    행운을 빕니다

  10. from https://stackoverflow.com/questions/3922276/how-to-combine-multiple-pngs-into-one-big-png-file by cc-by-sa and MIT license