On merging & thinning & adjusting pdfs 4 up of each page of the pdf ====================== http://pdfbooklet.sourceforge.net/ x copies / row: 2 no change + autoscale (otherwise it goes into A2 or bad quality reduction) Merge pdf's in sharp quality ===================== Considering that pdfunite is part of poppler it has a higher chance to be installed, usage is also simpler than pdftk: pdfunite in-1.pdf in-2.pdf in-n.pdf out.pdf 4UP with psnup ================ pdf2ps photos.ebook.pdf - | \ psnup -p a4 -4 | \ ps2pdf - photos.4up.pdf Changing the resolution of images in a PDF (to match an output device) ========================================== SOURCE: http://tech-vaults.blogspot.be/2012/01/resampling-jpegs-inside-pdf-to.html ebook is very a good setting for screen (better than the actual "screen" setting as it allows a little zooming in still) In short, use ghostscript: gs -sDEVICE=pdfwrite -dPDFSETTINGS=/ebook -dNOPAUSE -dQUIET -dBATCH -sOutputFile=output.pdf input.pdf The PDFSETTINGS presets equate to the following resolutions: /screen ... screen-view-only quality, 72 dpi images /ebook ... low quality, 150 dpi images /printer ... high quality, 300 dpi images /prepress ... high quality, color preserving, 300 dpi images /default ... similar to /screen Other suggested command line arguments made various places: -dCompatibilityLevel=1.4 -dColorImageResolution=38 -dColorImageDownsampleType=/Average -dGrayImageDownsampleType=/Average -dGrayImageResolution=38 -dMonoImageResolution=38 -dMonoImageDownsampleType=/Average -dOptimize=true -dDownsampleColorImages=true -dDownsampleGrayImages=true -dDownsampleMonoImages=true -dUseCIEColor -dColorConversionStrategy=/sRGB -dMaxSubsetPct=100 More tips (very useful page) http://www.peteryu.ca/tutorials/publishing/pdf_manipulation_tips PHotobooks with Python + FLAT ============================= Flat is a great pure python library that can make PDFs. NB: The resulting PDFs are not *exactly* Adobe standard compliant -- using the ghostscript resolution fix above is useful to "cleanup" / fix the outputs of these scripts. First get FLAT: pip install flat ====================================== photobook.py ===================================== from argparse import ArgumentParser from flat import rgb, font, shape, strike, document, image import glob p = ArgumentParser("create a photo book pdf") p.add_argument("--width", default=210, type=int, help="width in mm, default: 210 (A4)") p.add_argument("--height", default=297, type=int, help="width in mm, default: 297 (A4)") p.add_argument("--border", default=10, type=int, help="border in mm, default: 10") p.add_argument("--input", help="input filenames in a text file") p.add_argument("--output", default="output.pdf", help="output filename for PDF file, default: output.pdf") p.add_argument("input", nargs="+", default=[], help="image filenames") args = p.parse_args() w = args.width # 210 h = args.height # 297 border = args.border # 10 d = document(w, h, 'mm') hh = args.height / 2 page = None paths = args.input paths.sort() def fitbox (image, placed, w, h): fit_h = image.height * (float(w) / image.width) if fit_h > h: placed.fitheight(h) else: placed.fitwidth(w) for impath in paths: print impath im = image.open(impath) if im.height > im.width: page = d.addpage() placed = page.place(im).frame(border, border, w-(border*2), h-(border*2)) fitbox(im, placed, w-(border*2), h-(border*2)) # placed.fitheight(h-(border*2)) page = None else: # place in partial frame if page == None: page = d.addpage() placed = page.place(im).frame(border, border, w-(border*2), hh-(border*2)) fitbox(im, placed, w-(border*2), hh-(border*2)) # placed.fitheight(hh-(border*2)) else: placed = page.place(im).frame(border, hh+border, w-(border*2), hh-(border*2)) fitbox(im, placed, w-(border*2), hh-(border*2)) # placed.fitheight(hh-(border*2)) page = None d.pdf(args.output) ====================================== photobook2.py (2x2 grid) ===================================== from argparse import ArgumentParser from flat import rgb, font, shape, strike, document, image import glob from random import shuffle p = ArgumentParser("create a photo book pdf") p.add_argument("--width", default=210, type=int, help="width in mm, default: 210 (A4)") p.add_argument("--height", default=297, type=int, help="width in mm, default: 297 (A4)") p.add_argument("--border", default=10, type=int, help="border in mm, default: 10") p.add_argument("--input", help="input filenames in a text file") p.add_argument("--output", default="output.pdf", help="output filename for PDF file, default: output.pdf") p.add_argument("--shuffle", default=False, action="store_true", help="shuffle the order, default: False") p.add_argument("input", nargs="+", default=[], help="image filenames") args = p.parse_args() w = args.width # 210 h = args.height # 297 border = args.border # 10 d = document(w, h, 'mm') hw = args.width / 2.0 hh = args.height / 2.0 page = None paths = args.input paths.sort() if args.shuffle: shuffle(paths) def fitbox (image, placed, w, h): fit_h = image.height * (float(w) / image.width) if fit_h > h: placed.fitheight(h) else: placed.fitwidth(w) x, y = 0, 0 def newline(): global page, x, y y += 1 x = 0 if y == 2: y = 0 page = None def ensurepage(): global page if page == None: page = d.addpage() border2 = 2*args.border for impath in paths: print impath im = image.open(impath) if im.width > im.height: # place across 2 cells if x != 0: newline() # px = x * hw py = y * hh ensurepage() placed = page.place(im).frame(0 + border, py + border, w - border2, hh - border2) fitbox(im, placed, w - border2, hh - border2) newline() else: px = x * hw py = y * hh ensurepage() placed = page.place(im).frame(px + border, py+border, hw-border2, hh-border2) fitbox(im, placed, hw-border2, hh-border2) x += 1 if x == 2: newline() d.pdf(args.output) makefile ============= all: screenshots.prepress.pdf bookpdfs.prepress.pdf bookphotos.prepress.pdf photobooks: python photobook.py pictures/photos/* --output photos.raw.pdf python photobook2.py pictures/bookphotos/* --shuffle --output bookphotos.raw.pdf python photobook2.py pictures/bookpdfs/*.jpg --shuffle --output bookpdfs.raw.pdf python photobook2.py pictures/screenshots/* --shuffle --output screenshots.raw.pdf %.prepress.pdf: %.raw.pdf gs -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -dNOPAUSE -dQUIET -dBATCH -sOutputFile=$@ $< %.ebook.pdf: %.raw.pdf gs -sDEVICE=pdfwrite -dPDFSETTINGS=/ebook -dNOPAUSE -dQUIET -dBATCH -sOutputFile=$@ $< %.4up.pdf: %.ebook.pdf pdf2ps $< - | \ psnup -p a4 -4 | \ ps2pdf - $@ %.screen.pdf: %.pdf gs -sDEVICE=pdfwrite -dPDFSETTINGS=/screen -dNOPAUSE -dQUIET -dBATCH -sOutputFile=$@ $<