Search code examples
pythonpdfpng

Multiple pngs/pdfs per page using python


I have a set of images I have saved as .png and .pdf. I was wondering if there is anyway to combine either the pngs or pdfs together in such a way I could have multiple per page. I know how to use PdfFileMerger() to merge several pdfs together, but this only puts one item per page. Is there any way to accomplish this? I have both pdfs and pngs so whichever one I need to use I can.

I basically want to do something like:

Take image1.png, image2.png, image3.png, and image4.png and create something like:

outputfile1:

-----------------------------
              |
              |
image1.png    | image2.png
              |
              |
-----------------------------
              |
              |
image3.png    | image4.png
              |
              |
-----------------------------

I would really appreciate it!


Solution

  • You can use PIL/pillow to create big empty image and then put small images on this image in different places.

    from PIL import Image
    
    # get images    
    img1 = Image.open('image1.png')
    img2 = Image.open('image2.png')
    img3 = Image.open('image3.png')
    img4 = Image.open('image4.png')
    
    # get width and height
    w1, h1 = img1.size
    w2, h2 = img2.size
    w3, h3 = img3.size
    w4, h4 = img4.size
    
    # to calculate size of new image 
    w = max(w1, w2, w3, w4)
    h = max(h1, h2, h3, h4)
    
    # create big empty image with place for images
    new_image = Image.new('RGB', (w*2, h*2))
    
    # put images on new_image
    new_image.paste(img1, (0, 0))
    new_image.paste(img2, (w, 0))
    new_image.paste(img3, (0, h))
    new_image.paste(img4, (w, h))
    
    # save it
    new_image.save('new.png')
    

    BTW: you could write it in for-loop(s).


    The same with program ImageMagick without Python.

    But you can use these commands in Python with os.system('convert ...')

    $ convert image1.png image2.png +append row1.png
    $ convert image3.png image4.png +append row2.png
    $ convert row1.png row2.png -append new.png
    

    +append join in row, -append join in column.

    It is possible to do it even in one command: Stitching Image Set Together

    $ convert image1.png image2.png image3.png image4.png +append -crop 2x1@ -append new.png
    

    If you use new.pdf instead of new.png then it can create PDF


    There is Python module Wand which uses ImageMagick. Code is similar to pillow.

    from wand.image import Image
    
    img1 = Image(filename='image1.png')
    img2 = Image(filename='image2.png')
    img3 = Image(filename='image3.png')
    img4 = Image(filename='image4.png')
    
    w1, h1 = img1.size
    w2, h2 = img2.size
    w3, h3 = img3.size
    w4, h4 = img4.size
    
    w = max(w1, w2, w3, w4)
    h = max(h1, h2, h3, h4)
    
    new_image = Image(width=w*2, height=h*2)
    
    new_image.composite(image=img1, left=0, top=0)
    new_image.composite(image=img2, left=w, top=0)
    new_image.composite(image=img3, left=0, top=h)
    new_image.composite(image=img4, left=w, top=h)
    
    new_image.save(filename='new.png')
    

    Example with cv2 and numpy but it works when images have the same size. If they have different then they need empty rows and columns to have the same size.

    import cv2
    import numpy as np
    
    img1 = cv2.imread('image1.png')
    img2 = cv2.imread('image2.png')
    img3 = cv2.imread('image3.png')
    img4 = cv2.imread('image4.png')
    
    row1 = np.concatenate((img1, img2), axis=1)
    row2 = np.concatenate((img3, img4), axis=1)
    new_image = np.concatenate((row1, row2))
    
    # or
    row1 = np.hstack((img1, img2))
    row2 = np.hstack((img3, img4))
    new_image = np.vstack((row1, row2))
    
    cv2.imwrite('new.png', new_image)
    

    Similar with matplotlib and numpy

    import matplotlib.image
    import numpy as np
    
    img1 = matplotlib.image.imread('image1.png')
    img2 = matplotlib.image.imread('image2.png')
    img3 = matplotlib.image.imread('image3.png')
    img4 = matplotlib.image.imread('image4.png')
    
    row1 = np.concatenate((img1, img2), axis=1)
    row2 = np.concatenate((img3, img4), axis=1)
    new_image = np.concatenate((row1, row2))
    
    # or
    row1 = np.hstack((img1, img2))
    row2 = np.hstack((img3, img4))
    new_image = np.vstack((row1, row2))
    
    matplotlib.image.imsave('new.png', new_image)
    

    Similar with imageio and numpy

    import imageio
    import numpy as np
    
    img1 = imageio.imread('image1.png')
    img2 = imageio.imread('image2.png')
    img3 = imageio.imread('image3.png')
    img4 = imageio.imread('image4.png')
    
    row1 = np.concatenate((img1, img2), axis=1)
    row2 = np.concatenate((img3, img4), axis=1)
    new_image = np.concatenate((row1, row2))
    
    # or
    row1 = np.hstack((img1, img2))
    row2 = np.hstack((img3, img4))
    new_image = np.vstack((row1, row2))
    
    imageio.imwrite('new.png', new_image)