Making a photobook from a directory of images using a script
This is yet another script to layout photos in a book. It differs from Automatic import of images: Versions not requiring Tkinter and Automatic import of images from a directory using a script in that it is not meant to be fuly automatic, and it allows for a variable number of images per page in mixtures of landscape and portrait orientation.
It's intended to produce a book in the same format as Adobe Photoshop Album: US Letter, landscape orientation.
Usage
Running photobook_layout.py without an open document will bring up a dialog to select a directory. The script will then add all JPEG files (*.jpg) to a new document, 3 to a page. It will then go through each page, re-orienting and resizing the photos to nicely fit the page.
You can then re-arrange the photos, dragging them from page to page to get a nice layout. Re-running the photobook_layout.py script will go through all of the pages, re-laying them out.
The script can handle 1-4 photos per page, in any combination of portrait and landscape.
There are some auxilliary scripts. pb_layout_current.py will lay out only the current page. pb_layout_from_current.py will lay out all pages from the current one to the end of the document. pb_flip_h.py and pb_flip_v.py will flip arrangement of images on the current page.
photobook_layout.py
<nowiki> #!/usr/bin/env python # -*- coding: ascii -*- # File: photobook_layout.py # Created: 25th May 2007 by Chris Crouch # This script will create a photobook. It can both create a photobook from a folder full of images, # and lay images out on the pages in a nice way. You can move the images from page to page, and have # the script re-layout them for you. It lays out landscape and portrait images neatly. # Requires the Python Image Library from http://www.pythonware.com/products/pil/ (to work out image orientation) # Developed on a Windows machine running Scribus 1.3.3.9 # This is designed for Letter pages in Landscape orientation, with images that are 3:2 aspect ratio (DSLR) # To change these, change the constants at the top for the paper size, then you'll need to just fiddle # with the size & positions in pb_layout_page() so that (a) the image frames are the correct aspect ratio, # and (b) the sizes and positions look good on the page. Trial and error is how I got these. # There are some auxilliary scripts that just allow you to directly invoke some of the functions in this script. import glob try: import Image except ImportError: print "This script requires the Python Image Library" sys.exit(1) try: from scribus import * except ImportError: print "This script only runs from within Scribus." sys.exit(1) ###### Constants page_size = (279.4, 215.9) #Letter, mm page_margins_left = (5, 5, 20, 5) #mm page_margins_right = (20, 5, 5, 5) #mm page_margins_points = (56.69, 14.17, 14.17, 14.17) #margins_right as points ###### def cmpObj(obj1, obj2): # compare 2 image objects to sort by horizontal loc # (if ==, the vert. pos; then by name pos1 = getPosition(obj1) pos2 = getPosition(obj2) if pos1[0] > pos2[0]: return 1 if pos1[0] < pos2[0]: return -1 if pos1[1] > pos2[1]: return 1 if pos1[1] < pos2[1]: return -1 return obj1 > obj2 ###### def get_page_margins(): if (currentPage() % 2) == 1: return page_margins_right; else: return page_margins_left; ###### def placeobj(obj_size, x_place, y_place, obj): # move obj to specified position and specified size # obj_size - (w, h) # x_place, y_place: 0.0 - 1.0 normalized page_margins = get_page_margins() page_width = page_size[0] - page_margins[0] - page_margins[2] page_height = page_size[1] - page_margins[1] - page_margins[3] xpos = (page_width * x_place) + page_margins[0] - obj_size[0]/2 ypos = (page_height * y_place) + page_margins[1] - obj_size[1]/2 selectObject(obj) sizeObject(obj_size[0], obj_size[1], obj) moveObjectAbs(xpos, ypos, obj) deselectAll() return ###### def get_images_on_page(): # returns a list of the image objects on the current page # get all the items on the page item_list = getPageItems() # refine it to a list of only image objects objs = []; for item in item_list: if item[1] == 2: #type 2 == image objs.append(item[0]) return objs ###### def pb_layout_page(): # Nicely layout all of the images on the current page deselectAll() # get all of the images on this page and sort them by position objs = get_images_on_page() if len(objs) == 0: return objs.sort(cmpObj) # refine it to lists of landscape & portrait images port = [] land = [] for obj in objs: file = getImageFile(obj) im = Image.open(file) sz = im.size if sz[0] > sz[1]: land.append(obj) else: port.append(obj) np = len(port) # number of portrait images nl = len(land) # number of landscape images # layouts for different numbers of portrait and landscape images if np==0 and nl==1: placeobj((240, 160), 0.5, 0.5, land[0]) elif np==0 and nl==2: placeobj((150, 100), 0.4, 0.25, land[0]) placeobj((150, 100), 0.6, 0.75, land[1]) elif np==0 and nl==3: placeobj((120, 80), 0.25, 0.21, land[0]) placeobj((165, 110), 0.5, 0.7, land[1]) placeobj((120, 80), 0.75, 0.21, land[2]) elif np==0 and nl==4: placeobj((120, 80), 0.25, 0.25, land[0]) placeobj((120, 80), 0.75, 0.25, land[1]) placeobj((120, 80), 0.25, 0.75, land[2]) placeobj((120, 80), 0.75, 0.75, land[3]) elif np==1 and nl==0: placeobj((144, 216), 0.74, 0.5, port[0]) elif np==1 and nl==1: placeobj((90, 135), 0.205, 0.5, port[0]) placeobj((150, 100), 0.7, 0.5, land[0]) elif np==1 and nl==2: placeobj((120, 180), 0.25, 0.5, port[0]) placeobj((120, 80), 0.75, 0.27, land[0]) placeobj((120, 80), 0.75, 0.73, land[1]) elif np==1 and nl==3: placeobj((130, 195), 0.27, 0.5, port[0]) placeobj((90, 60), 0.75, 0.18, land[0]) placeobj((90, 60), 0.75, 0.5, land[1]) placeobj((90, 60), 0.75, 0.82, land[2]) elif np==2 and nl==0: placeobj((120, 180), 0.25, 0.5, port[0]) placeobj((120, 180), 0.75, 0.5, port[1]) elif np==2 and nl==1: placeobj((60, 90), 0.14, 0.25, port[0]) placeobj((60, 90), 0.14, 0.75, port[1]) placeobj((180, 120), 0.63, 0.5, land[0]) elif np==2 and nl==2: placeobj((70, 105), 0.22, 0.27, port[0]) placeobj((70, 105), 0.78, 0.73, port[1]) placeobj((135, 90), 0.65, 0.24, land[0]) placeobj((135, 90), 0.35, 0.76, land[1]) elif np==3 and nl==0: placeobj((80, 120), 0.17, 0.5, port[0]) placeobj((80, 120), 0.5, 0.5, port[1]) placeobj((80, 120), 0.83, 0.5, port[2]) elif np==3 and nl==1: placeobj((120, 180), 0.25, 0.5, port[0]) placeobj((60, 90), 0.62, 0.72, port[1]) placeobj((60, 90), 0.87, 0.72, port[2]) placeobj((120, 80), 0.745, 0.26, land[0]) elif np==4 and nl==0: placeobj((90, 135), 0.19, 0.5, port[0]) placeobj((60, 90), 0.5, 0.25, port[1]) placeobj((60, 90), 0.5, 0.75, port[2]) placeobj((90, 135), 0.81, 0.5, port[3]) docChanged(True) deselectAll() return ###### def pb_layout_all_pages(): # re-layout all pages from the current page to the end of the document progressReset() progressTotal(pageCount()+1) messagebarText("Arranging pictures"); for i in range(currentPage(), pageCount()+1): gotoPage(i) progressSet(i) messagebarText("Page "+str(i)) pb_layout_page() progressReset() messagebarText(""); ###### def pb_create_album(): # Prompt the user for a directory to process. # Create a new document with all jpg files from the selected directory added as images # to the document, 3 to the page. # When finished, process the document to layout the images in a "nice" manner dirname = fileDialog("Select Directory","","",False,False,True) files = glob.glob(dirname + "*.jpg") if len(files) == 0: return # it seems that you _have_ to specify page margins in points newDocument(PAPER_LETTER, page_margins_points, LANDSCAPE, 1, UNIT_POINTS, PAGE_2, FACINGPAGES, FIRSTPAGERIGHT) zoomDocument(50) setUnit(UNIT_MILLIMETERS) setMargins(page_margins_right[0], page_margins_right[1], page_margins_right[2], page_margins_right[3]) progressReset() progressTotal(len(files)) messagebarText("Creating pages..."); progress = 0; num_on_page = 0; for file in files: messagebarText("Adding "+file) progressSet(progress) progress = progress + 1 num_on_page = num_on_page + 1 if num_on_page == 4: newPage(-1) num_on_page = 1 im = Image.open(file) sz = im.size if sz[0] > sz[1]: f = createImage(num_on_page*90-80, 60, 90, 60) else: f = createImage(num_on_page*90-80, 10, 80, 120) loadImage(file, f) setScaleImageToFrame(scaletoframe=1, proportional=1, name=f) progressReset() messagebarText(""); deselectAll() # now layout the pages nicely gotoPage(1) pb_layout_all_pages() deselectAll() ###### if __name__ == '__main__': # either create a new album document, or re-layout the entire existing document if haveDoc(): gotoPage(1) pb_layout_all_pages() else: pb_create_album() </nowiki