Automatic import of images: Multiple image directories

From Scribus Wiki
Revision as of 16:47, 28 June 2011 by Hhartley (talk | contribs) (Script now supports image titles from accompanying text file)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

As an amateur photographer, I take a lot of pictures and in general I post them to a web site with one or more galleries being generated most days. For general purposes, that's enough. Occasionally, however, I've found it useful to have a printed version of my images, to be used more as like the contact sheet of old than as publication quality images. I'd like these documents to have small versions of all the images in each gallery, labeled with the file name and an option title that identified the subject of the photograph. Since the display of images on the web site is driven by text files with file names, titles, and descriptions, I it made sense to reuse that text file for labeling the pictures on the contact sheets.

Starting with the script found on the page Automatic import of images: Versions not requiring Tkinter#album_letter_2.py, I have created a new script that will take a collection of image directories and create 12-images-per-page documents from each of them in turn, save the documents and generate PDF files from each.

The initial input and output directories are specified in the code and will need to be changed based on your own configuration. They are defined on lines 27 and 31. The file that I use to list the images is index.txt but this file name may also be changed on line 42. Finally, the font to use is set on line 45. While there are many other settings that may be adjusted, the script should work well enough with just those four items set. Note that the script will not create the output directory so you'll need to make sure it exists before you start.

The basic idea here is to go through the source directory and gather all the sub-directory names. Then, go through each of those sub-directories, open the index.txt file, and generate a document with the images listed there, 12 per page. The document places the sub-directory name at the top of each page, arranges the images in four rows of three images with the file names centered under each. Page numbers are added. Since I print these documents double sided, the page numbers move from side to side and the entire page contents are shifted a little to the right (odd numbered pages) or the left (even numbered pages). Each gallery gets its own file.

Once generated, an SLA file is saved in the outputDirectory specified on line 31. Then, a PDF is generated with all pages and saved to the same location. Both files are named the same as the image sub-directory but with .sla and .pdf extensions respectively.

CAUTION: if you have directories with too many or very large image files, this can take a long while to run. Documents for directories with a couple dozen images of the appropriate size are created, saved, and exported to PDF in a matter of seconds. Documents for directories with images much larger than necessary or with more than a couple hundred images can take many minutes to be created. Since the images are printed at just over 1.4 by 2.1 inches, even at 300 dpi they will only need to be 420 by 633 pixels and you can probably get away with less. I would be cautious running this script on directories with lots of images or those copied directly from your digital camera. I've successfully produced documents with 640 images this way but it took a good while.

For publication to my web site I use a script that creates thumbnail, small, and large versions of each photo. Since the small size images are 467 by 700 pixels, I use those when generating contact sheets with this script. That works quite well and I've created documents with 1,500 images without any problem. Note that images are the same size whether they are vertical or horizontal. Even with this precaution, when I run this on a large number of directories, I often, eventually, get a Scribus crash with the message:

Scribus crashes due to the following exception : EXCEPTION_ACCESS_VIOLATION

I just close Scribus, move the image directories that have already been processed and start again. If anyone knows what's causing that and can fix it, that would be wonderful.

Considerable credit and thanks to Gregory Pittman, who wrote the original script on which this is based.

#!/usr/bin/env python

"""
This is contact-sheet.py. This script will load the images from any number
of directories, creating a new document of US Letter size from each directory.

AUTHOR: Henry Hartley
DATE: December 2, 2010 (original version)
MODIFICATIONS:
    June 28, 2011 - Added support for reading file information from index.txt

LICENSE: This program is free software; you can redistribute it and/or modify 
it under the terms of the GNU General Public License as published by the Free 
Software Foundation; either version 2 of the License, or (at your option) any 
later version.

http://wiki.scribus.net/index.php/Automatic_import_of_images:_Multiple_image_directories



You will probably need to edit the following:

"""
# The directory that contains images or subdirectories with images.
# All subdirectories under this location will be used to create 
# separate output files
sourceDirectory = "C:/temp/photo/"

# The directory, which should already exist, where you want your output files 
# to be written
outputDirectory = "C:/temp/photo/"

# The name of a file that contains one line per image. Each line should consist of 
# a tab delimited string with the following file information: 
# 
#   0 - count       -- Actually, anything can be here except a blank space or a hash
#                      mark (#), which will cause the line to be ignored.
#   1 - file name   -- The name of the file without the .jpg extension
#   2 - image title -- The title to use in labeling the file (optional)
#   3 - description -- A longer description (optional) (currently not used)
# 
sourceFileList = 'index.txt'

# The font to use for documents
labelFont = 'Garamond Regular'


####################################################################################
## While you might want to edit setting below here, you 
## shouldn't need to in order to run the script
####################################################################################

import scribus
import os

# All of these numbers can be adjusted but what is here seems to work pretty well

firstPageNumber = '1'

marginX   = 36
marginY   = 36

# Image height and width
iHorW   = 152
iVerW   = 101
iVerH  = iHorW
iHorH  = iVerW

# Gap sizes and page offsets
gapW      = 24
gapH      = 21
xOffset   = 36
yOffset   = 24

# Page title text frame
titleFS   = 12
titleX    = marginX
titleY    = marginY
titleW    = iHorW + iHorW + gapW + iHorW + gapW
titleH    = titleFS * 2

# Image label text frame
# Height is enough to allow a second line of text if desired.
labelGap  = 0
labelFS   = 6
labelH    = labelFS * 4

# Page number text frame
pNumFS    = 8
pNumY     = 759
pNumXt    = 2
pNumW     = 18
pNumH     = pNumFS * 1.5

H2V = int((iHorW-iHorH)/2)
V2H = int((iVerH-iVerW)/2)

# It's quite likely that these longs lists could be replaced by a formula.
# If anyone has the time to do that, it would probably make this script easier
# to maintain. Still, this works.
xPosH = [marginX, marginX + iHorW + gapW, marginX + (2 * iHorW) + (2 * gapW), marginX, marginX + iHorW + gapW, marginX + (2 * iHorW) + (2 * gapW), marginX, marginX + iHorW + gapW, marginX + (2 * iHorW) + (2 * gapW), marginX, marginX + iHorW + gapW, marginX + (2 * iHorW) + (2 * gapW)]
yPosH = [marginY + yOffset + V2H, marginY + yOffset + V2H, marginY + yOffset + V2H, marginY + yOffset + iVerH + gapH + V2H, marginY + yOffset + iVerH + gapH + V2H, marginY + yOffset + iVerH + gapH + V2H, marginY + yOffset + (2 * iVerH) + (2 * gapH) + V2H, marginY + yOffset + (2 * iVerH) + (2 * gapH) + V2H, marginY + yOffset + (2 * iVerH) + (2 * gapH) + V2H, marginY + yOffset + (3 * iVerH) + (3 * gapH) + V2H, marginY + yOffset + (3 * iVerH) + (3 * gapH) + V2H, marginY + yOffset + (3 * iVerH) + (3 * gapH) + V2H]
xPosV = [marginX + H2V, marginX + iHorW + gapW + H2V, marginX + (2 * iHorW) + (2 * gapW) + H2V, marginX + H2V, marginX + iHorW + gapW + H2V, marginX + (2 * iHorW) + (2 * gapW) + H2V, marginX + H2V, marginX + iHorW + gapW + H2V, marginX + (2 * iHorW) + (2 * gapW) + H2V, marginX + H2V, marginX + iHorW + gapW + H2V, marginX + (2 * iHorW) + (2 * gapW) + H2V]
yPosV = [marginY + yOffset, marginY + yOffset, marginY + yOffset, marginY + yOffset + iVerH + gapH, marginY + yOffset + iVerH + gapH, marginY + yOffset + iVerH + gapH, marginY + yOffset + (2 * iVerH) + (2 * gapH), marginY + yOffset + (2 * iVerH) + (2 * gapH), marginY + yOffset + (2 * iVerH) + (2 * gapH), marginY + yOffset + (3 * iVerH) + (3 * gapH), marginY + yOffset + (3 * iVerH) + (3 * gapH), marginY + yOffset + (3 * iVerH) + (3 * gapH)]
imgID = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
imgRow = 3
imagedir = ""

dirCount = 0
dir = os.listdir(sourceDirectory)
DIR = []
for file in dir:
    #result = scribus.messageBox("Directory", "File: "+file)
    if os.path.isdir(sourceDirectory+file):
        DIR.append(file)
        dirCount += 1
DIR.sort()

#result = scribus.messageBox("Directory Count", "There were "+str(dirCount)+" directories added to the array")

for imagedir in DIR:
    
    # Open the index.txt file
    f = open(sourceDirectory+imagedir+'/'+sourceFileList, 'r')
    D = []
    D = f.readlines()
    
    gallerytitle = imagedir
    
    imageCount = 0
    pageNumber = 1
    scribus.progressTotal(len(D))
    if len(D) > 0:
        if scribus.newDoc(scribus.PAPER_LETTER, (marginX, marginX, marginY, marginY),scribus.PORTRAIT, 1, scribus.UNIT_POINTS, scribus.NOFACINGPAGES, scribus.FIRSTPAGERIGHT):
            while imageCount < len(D):
                if imageCount > 0:
                    scribus.newPage(-1)
                
                # Here is where we're loading images into the page, four, six, or twelve at a time, then go back up for a newPage
                if pageNumber % 2 == 0:
                    pOffset = 0
                    pNumX = xPosH[0]
                else:
                    pOffset = xOffset
                    pNumX = xPosH[pNumXt] + iHorW + pOffset - pNumW
    
                # L is the frame at the top of each page showing the gallery title (read in above)
                L = scribus.createText(titleX + pOffset, titleY, titleW, titleH)
                scribus.setText(gallerytitle, L)
                scribus.setTextAlignment(scribus.ALIGN_CENTERED, L)
                scribus.setFont(labelFont, L)
                scribus.setFontSize(titleFS, L)
                
                for i in imgID:
                    if imageCount < len(D):
                        
                        if not D[imageCount].startswith("#") and not D[imageCount].startswith(" "):
                            Img = []
                            Img = D[imageCount].split("\t")
                            
                            scribus.statusMessage("Placing image " + Img[1] + " in document (" + `imageCount` + " of " + `len(D)` + ")")
                            scribus.progressSet(imageCount)
        
                            # Create a temporary image object. Size and location are irrelivant
                            tempImage = scribus.createImage(10, 10, 10, 10)
        
                            # Populate that object with your image
                            scribus.loadImage(sourceDirectory+imagedir + '/' + Img[1]+'.jpg', tempImage)
        
                            # Scale the image but NOT proportionally
                            scribus.setScaleImageToFrame(scaletoframe=1, proportional=0, name=tempImage)
        
                            # Use getImageScale to get the relative scaling in the x and y directions
                            imgx,imgy = scribus.getImageScale(tempImage)
        
                            # If imgx < imgy, you have an horizontal image, otherwise, 
                            # a vertical (or square) image. 
                            if imgx < imgy:
                                x = xPosH[i] + pOffset
                                y = yPosH[i]
                                pWidth = iHorW
                                pHeight = iHorH
                            else:
                                x = xPosV[i] + pOffset
                                y = yPosV[i]
                                pWidth = iVerW
                                pHeight = iVerH
        
                            # Can't have these cluttering up the page
                            scribus.deleteObject(tempImage)
                            
                            # Now we create the REAL image object placed appropriately
                            f = scribus.createImage(x, y, pWidth, pHeight)
                            
                            # and load the image
                            scribus.loadImage(sourceDirectory+imagedir + '/' + Img[1]+'.jpg', f)
                            
                            # this time when we scale the image, we do it proportionally
                            scribus.setScaleImageToFrame(scaletoframe=1, proportional=1, name=f)
                            
                            # Lpic is the label for each picture, the position is the same for all 
                            #    image orientations and the labels are centered under the pictures.
                            
                            # Create a text frame for the picture caption
                            Lpic = scribus.createText(xPosH[i] + pOffset - int(gapW/2)-1, yPosV[i] + iVerH + labelGap, iHorW + gapW-2, labelH)
                            
                            # populate with the file name and title (Img[2])
                            if len(Img[2]) > 0:
                                scribus.setText('File: '+Img[1]+', '+Img[2], Lpic)
                            else:
                                scribus.setText('File: '+Img[1], Lpic)
                            
                            # and format as desired
                            scribus.setTextAlignment(scribus.ALIGN_CENTERED, Lpic)
                            scribus.setFont(labelFont, Lpic)
                            scribus.setFontSize(labelFS, Lpic)
                            scribus.setLineSpacing(labelFS, Lpic)
                            #scribus.setFillColor("White", Lpic)
                            
                            # End of If/Then -- startswith()
                            
                        # increment the image count
                        imageCount += 1
                
                # Now the page number
                
                # Create a text frame
                pNum = scribus.createText(pNumX, pNumY, pNumW, pNumH)
                
                # Put the page number in it and format
                pageNumberPrint = pageNumber + (int(firstPageNumber)-1)
                scribus.setText(`pageNumberPrint`, pNum)
                if imageCount < len(D):
                    scribus.setTextAlignment(scribus.ALIGN_RIGHT, pNum)
                else:
                    scribus.setTextAlignment(scribus.ALIGN_LEFT, pNum)
                scribus.setFont(labelFont, pNum)
                scribus.setFontSize(pNumFS, pNum)
                #scribus.setFillColor("White", pNum)
                
                # Finally, we increment the page number
                pageNumber += 1
        scribus.setRedraw(1)
        scribus.redrawAll()
    
    else:
        result = scribus.messageBox ('Not Found','No Images found with\n this search selection',scribus.BUTTON_OK)
    
    scribus.setRedraw(1)
    scribus.redrawAll()
    
    scribus.statusMessage("Saving File as "+outputDirectory+imagedir+".sla")
    #result = scribus.messageBox("Save", "Saving SLA File as: "+outputDirectory+imagedir+".sla")
    scribus.saveDocAs(outputDirectory+imagedir+".sla")
    
    scribus.statusMessage("Saving PDF File as "+outputDirectory+imagedir+".pdf")
    pdfExport = scribus.PDFfile()
    pdfExport.info = outputDirectory+imagedir+".pdf"
    pNum = 1
    PDFPages = []
    while pNum < pageNumber:
        PDFPages.append(pNum)
        pNum += 1
    pdfExport.pages = PDFPages
    pdfExport.file = outputDirectory+imagedir+".pdf"
    pdfExport.save()
    
    scribus.closeDoc()
    
    scribus.statusMessage("")
    scribus.progressReset()