#!/usr/bin/env python

"""software_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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
"""

# Based on Batch resize code by Carol Spears
# Based on contactsheet by R. Gilham and E. Sullock Enzlin
# Photoprint by Elmar Sullock Enzlin at moroquendo@gmail.com
# See for details my website at www.sullockenzlin.demon.nl

# pdb.python_fu_photo_print(.......) #to be changed

import os
import os.path
import gimp
from gimpfu import *
from math import ceil, floor

#==============================================================================
#================= localization with "photoprint.mo" ==========================
#==============================================================================
#no photoprint.mo yet
gettext.install("photoprint", gimp.locale_directory, unicode=True) 


#==============================================================================
#=========== function only used for testpurposes and error logging ============
#==============================================================================
def Log(text):
    filename = ("c:/tmp/gimp.log")
    f=file(filename, "a+")
    f.write(text+"\n")
    f.close()
    return


#==============================================================================
#=============== Makes an overview of the images and directorys ===============
#==============================================================================
# input: text:              text to save
#        contact_location:  directory to save
# output: txt file with imagename and dirname were the image is located
#==============================================================================
def LogFileName(text, contact_location,  FirstRun):
    Filename = (contact_location + '/' + 'photoprint' + '.txt')
    if (FirstRun == True):
        if (os.path.isfile(Filename) == True):
            os.remove(Filename)
            
    f=file(Filename, "a+")
    f.write(text + "\n")
    f.close()
    return


#==============================================================================
#================= get images from eventually all dirs ========================
#==============================================================================
# input: FileType:          array contains one or more extensions
#        original_location: directory to start
#        all_subdirs:       bool to include subdirectory's too
#        DirFileList:       bool to give a txt list of images with their dir
# output: images:           array with images
#==============================================================================
def get_images(FileType, original_location, all_subdirs):
    images = []

    if (FileType == 5):
        FileType = '.jpg .jpeg .JPG .JPEG .png .PNG .tiff .tif .TIF .TIFF .pcx .PCX .xcf .XCF'
    elif (FileType == 4):
        FileType = '.xcf .XCF'
    elif (FileType == 3):
        FileType = '.pcx .PCX'
    elif (FileType == 2):
        FileType = '.tiff .tif .TIF .TIFF'
    elif (FileType == 1):
        FileType = '.png .PNG'
    elif(FileType == 0):
        FileType = '.jpg .jpeg .JPG .JPEG'
    else:
        FileType = ''
        Log("error in file type")

    if (all_subdirs == True):                       #include all subdirectory's
       for dirpath, dirnames, filenames in os.walk(original_location, topdown=True):
           for filename in filenames:
              basename, ext = os.path.splitext(filename)
              if ((len(ext)>2) and (ext in FileType)):
                 imagefile = os.path.join(dirpath, filename)
                 original_image = {'extension':ext,'base_name':basename,'image_file':imagefile}
                 if os.path.isfile(imagefile):
                    images.append(original_image)
    else:                                           #only the choosen directory
        for filename in os.listdir(original_location):
            basename, ext = os.path.splitext(filename)
            if ((len(ext)>2) and (ext in FileType)):
                imagefile = os.path.join(original_location, filename)
                original_image = {'extension':ext,'base_name':basename,'image_file':imagefile}
                if os.path.isfile(imagefile):
                    images.append(original_image)
#                    Log(str(original_image))

    return images



#==============================================================================
#================= save photoprint as a png file ==============================
#==============================================================================
def save_png(image, drawable, new_filelocation, use_comment):
    compression = 9
    interlace, bkgd = False, False
    gama, offs, phys = False, False, False
    time, svtrans = True, False
    pdb.file_png_save2(image, drawable, new_filelocation, new_filelocation,
                       interlace, compression, bkgd, gama, offs, phys, time,
                       use_comment, svtrans) 

#==============================================================================
#================= save photoprint as a jpg file ==============================
#==============================================================================
#save in highest quality
def save_jpeg(image, name, comment=""):
    jpeg_save_defaults = (1.0, 0.0, 1, 0, "", 1, 0, 0, 0)
    args = list(jpeg_save_defaults)
    args[4] = comment

    pdb.file_jpeg_save(image, image.active_layer, name, name, *args)


#==============================================================================
#========= resize and eventually rotate and crop photo to allowed size ========
#==============================================================================
# input: filename:          photo to resize
#        Photo_width:       maximum photo width
#        Photo_height:      maximum photo height
#        crop:              crop yes or no
#        aspect_ratio       photo has a fixed size or not
# output: img:              resized photo
#         new[0]            x-size of the photo
#         new[1]            y-size of the photo
#==============================================================================    
def generate_foto(filename, Photo_width, Photo_height, crop, aspect_ratio):

#    Log('Entering generate_foto routine')

    if (aspect_ratio < 7):                          #sizes depends on settings
        fixed_size = False
        if (aspect_ratio == 0):
            AR = 4/float(3)
        elif (aspect_ratio == 1):
            AR = 16/float(9)
        elif (aspect_ratio == 2):
            AR = 3/float(2)
        elif (aspect_ratio == 3):
            AR = 5/float(4)
        elif (aspect_ratio == 4):
            AR = 6/float(7)
        elif (aspect_ratio == 5):
            AR = 1/float(1)
        elif (aspect_ratio == 6):                   #none
            AR = 4/float(3)
    else:                                           #fixed sizes
        crop = True
        fixed_size = True
        AR = 0
    
    img = pdb.gimp_file_load(filename,filename)     #load Photo

    #first rotate the photo 90 degrees if the longest side is vertical
    if (img.height>img.width):
        pdb.gimp_image_rotate(img,0)

    crop_x = False
    crop_y = False
    ratio = img.width/float(img.height)             #aspect of the image

#    Log('AR: ' + str(AR) + '  ratio: ' + str(ratio))
    
    if (fixed_size == False):
        if (aspect_ratio == 6):                 #none, ratio depends on photo
            #Log('aspect ratio = none and fixed size = False')
            if (crop == False):
                new_Photo_size = (int(Photo_height*ratio),Photo_height)
                #Log(str(new_Photo_size))
                if (new_Photo_size[0]>Photo_width):
                    new_Photo_size = (Photo_width, int(Photo_width/ratio)) #exactly fits
            else:
                scale_y = Photo_height/float(img.height)    #image should be scaled lineair
                scale_x = Photo_width/float(img.width)
                if (scale_x < scale_y):             #scale lineair at maximum and crop width
                    new_Photo_size = (Photo_height*ratio, Photo_height) #height is correct
                    crop_x = True
                else:                               #scale lineair at maximum and crop height
                    new_Photo_size = (Photo_width, Photo_width/ratio) #width is correct
                    crop_y = True
        else:                                   #given aspect ratio
            #Log('aspect ratio <> none')
            if (crop ==False):
                #scale minimum it's the same as none, aspect of photo will be kept
                new_Photo_size = (int(Photo_height*ratio),Photo_height)
                #Log(str(new_Photo_size))
                if (new_Photo_size[0]>Photo_width):
                    new_Photo_size = (Photo_width, int(Photo_width/ratio)) #exactly fits
            else:
                #scale maximum and crop photo to given aspect
                scale_y = Photo_height/float(img.height)#image should be scaled lineair first
                scale_x = Photo_width/float(img.width)
                if (scale_x < scale_y):             #scale lineair at maximum and crop width
                    new_Photo_size = (Photo_height*ratio, Photo_height) #height is correct
                    crop_x = True
                else:                               #scale lineair at maximum and crop height
                    new_Photo_size = (Photo_width, Photo_width/ratio) #width is correct
                    crop_y = True
    else:                                           #predefined fixed sizes
        scale_y = Photo_height/float(img.height)    #image should be scaled lineair
        scale_x = Photo_width/float(img.width)
        if (scale_x < scale_y):                     #scale lineair at maximum and crop width
            new_Photo_size = (Photo_height*ratio, Photo_height) #height is correct
            crop_x = True
        else:                                       #scale lineair at maximum and crop height
            new_Photo_size = (Photo_width, Photo_width/ratio) #width is correct
            crop_y = True


    #Log('crop_x: '+ str(crop_x) + '   crop_y: '+ str(crop_y))
    #Log('size_x: '+ str(new_Photo_size[0])+ ' size_y: '+ str(new_Photo_size[1]))
    #Log('max. photosize_x: ' + str(Photo_width) + ' photosize_y: '+ str(Photo_height))
        
    if (crop == True):                          #scale maximum and crop
        pdb.gimp_image_scale(img,new_Photo_size[0],new_Photo_size[1]) #scale first
        #and now crop to fixed size or given aspect ratio
        if (crop_x == True):
            if (aspect_ratio < 7):
                #Log('crop_x is True en aspect ratio <7')
                #crop met aspect
                offx = (new_Photo_size[0] - Photo_width)/float(2)
                offy = 0
            else:
                #Log('crop_x is True en aspect ratio >6')
                offx = (new_Photo_size[0] - Photo_width)/float(2)
                offy = 0
                new_Photo_size = (Photo_width, Photo_height)
                
            #Log('offx: ' + str(offx) + '  offy: ' + str(offy))    
            pdb.gimp_image_crop(img, Photo_width, new_Photo_size[1], offx , offy)
        else:
            if (aspect_ratio < 7):
                #Log('crop_x is False en aspect ratio <7')
                #crop met aspect
                offx = 0
                offy = (new_Photo_size[1] - Photo_height)/float(2)
            else:
                #Log('crop_x is False en aspect ratio >6')
                offx = 0
                offy = (new_Photo_size[1] - Photo_height)/float(2)
                new_Photo_size = (Photo_width, Photo_height)
                
            #Log('offx: ' + str(offx) + '  offy: ' + str(offy))              
            pdb.gimp_image_crop(img, new_Photo_size[0], Photo_height, offx, offy) 
    else:                                       #scale minimum and no cropping
        #or is gimp_image_resize better ??????
        pdb.gimp_image_scale(img,new_Photo_size[0],new_Photo_size[1])   #scale photo


    return img,new_Photo_size[0],new_Photo_size[1]

        

#==============================================================================
#================= modify fontsize so it fits Photo width =====================
#==============================================================================
def CalcFontSize(text, Font, Size, CalcTextHeight, max_width):
    #this procedure calculates the text size to fit within the
    #width param, the text is reduced until the width is small enough
    txtw,txtH,txte,txtd = pdb.gimp_text_get_extents_fontname(text,Size,PIXELS,Font)
    if (txtw<=max_width):
        return Size,txtw
    while ((txtw>max_width) and (Size>0)):
        Size = Size -1
        txtw,txtH,txte,txtd = pdb.gimp_text_get_extents_fontname(text,Size,PIXELS,Font)
    return Size,txtw


#==============================================================================
#===================== calculate papersize in pixels ==========================
#==============================================================================
#input: Contactsize     papersize
#       dpi             desired resolution
#output:width           width in pixels of the papersize
#       height          height in pixels of the papersize
#==============================================================================
def CalcPaperSize(ContactSize, dpi, orient):
    if (ContactSize == 0):             #Jumbo
        width,height = (102,152)       #sizes are in mm (bxh)
    elif (ContactSize == 1):           #6x8
        width,height = (152,203)
    elif (ContactSize == 2):           #8x10
        width,height = (203,254)        
    elif (ContactSize == 3):           #A4
        width,height = (210,297)
    elif (ContactSize == 4):           #A3
        width,height = (297,420)        
    elif (ContactSize == 5):           #Letter
        width,height = (216,279)
    elif (ContactSize == 6):           #Legal
        width,height = (216,356)
    elif (ContactSize == 7):           #Tabloid
        width,height = (279,432)
    else:
        width,height = (210,297)       #Default
        Log("error in pagesize, pagesize doesnot exist")

    if (orient == "land"):
        Height = int(width * dpi / 25.4)        # calculate width in px
        Width = int(height * dpi / 25.4)        # calculate height in px
        #Log('Landscape papiergrootte in px (bxh): ' + str(Width) + ' , ' + str(Height))
    else:
        Width = int(width * dpi / 25.4)         # calculate width in px
        Height = int(height * dpi / 25.4)       # calculate height in px
        #Log('Portret papiergrootte in px (bxh): ' + str(Width) + ' , ' + str(Height))

    return Width, Height                        #size in pixels (integer)


#==============================================================================
#================== calculate maximum photosize in pixels =====================
#==============================================================================
#input: CanvasWidth         canvaswidth in px
#       CanvasHeight        canvasheight in px
#       numcols             int number of columns
#       numrows             int number of rows
#       AspectRatio         int number
#       PhotoMargin         margin in pixels
#output:MaxPhotoWidth       maximum width in pixels
#       MaxPhotoHeight      maximum height in pixels
#==============================================================================
## most common aspect ratio's (bxh)
##  4:3 -> TV
##  16:9 -> movie
##  3:2 -> SLR digital camera
##  5:4
##  6:7
##  1:1
##  none -> maximum size depends on paper, rows and columns
##
## otherwise predefined papersizes (bxh)
## 7x10 cm  ->
## 9x12 cm  ->
## 10x15 cm  ->
## 13x18 cm  ->
## 18x24 cm  ->
## else??
#==============================================================================
def CalcMaxPhotoSize(CanvasWidth, CanvasHeight, numcols, numrows, AspectRatio,
                     PhotoMargin, dpi):
    
    fixed_size = False
#------------------------size declarations--------------------------------------
##  Don't add new aspect ratios, unless you know what you are doing. Several lines
##  should be new coded
##    
##  ("Aspect ratio: "), 0 ,["4:3", "16:9", "3:2", "5:4","6:7", "1:1", "none", ..])
##  or predefined photosizes
    if (AspectRatio == 0):                      #4:3 (bxh)
        PhotoSize_x,PhotoSize_y = (4,3)
    elif (AspectRatio == 1):                    #16:9
        PhotoSize_x,PhotoSize_y = (16,9)
    elif (AspectRatio == 2):                    #3:2
        PhotoSize_x,PhotoSize_y = (3,2)        
    elif (AspectRatio == 3):                    #5:4
        PhotoSize_x,PhotoSize_y = (5,4)
    elif (AspectRatio == 4):                    #6:7
        PhotoSize_x,PhotoSize_y = (6,7)        
    elif (AspectRatio == 5):                    #1:1
        PhotoSize_x,PhotoSize_y = (1,1)
    elif (AspectRatio == 6):                    #none
        PhotoSize_x,PhotoSize_y = (4,3)
    else:
##  this section contains the fixed photosizes in mm (bxh)
##  You can add additional sizes here and to the register without modifying a
##  lot of the code. The tallest size should be noted first (=width).
        fixed_size = True
        if (AspectRatio == 7):                    #7x10 cm predefined section
            PhotoSize_x,PhotoSize_y = (100,70)
        elif (AspectRatio == 8):                  #9x13 cm
            PhotoSize_x,PhotoSize_y = (127,89)        
        elif (AspectRatio == 9):                  #10x15 cm
            PhotoSize_x,PhotoSize_y = (152,102)
        elif (AspectRatio == 10):                 #13x18 cm
            PhotoSize_x,PhotoSize_y = (178,127)        
        elif (AspectRatio == 11):                 #18x24 cm
            PhotoSize_x,PhotoSize_y = (240,180)
        else:
            fixed_size = False
            PhotoSize_x,PhotoSize_y = (4,3)       #none is the default
            #Log("Error in routine CalcMaxPhotoSize (AR), size doesn't exist.")

    AR =  PhotoSize_x/float(PhotoSize_y) 

#------------------------------size calculations-------------------------------
    if (fixed_size == False):
        PhotoSize_x = int((CanvasWidth-(numcols-1)*PhotoMargin)/(numcols))
        PhotoSize_y = int((CanvasHeight-(numrows-1)*PhotoMargin)/(numrows))
        #Log('CalcMaxPhotoSize voor(bxh): ' + str(PhotoSize_x) + ' , ' + str(PhotoSize_y))
        #Log('Aspect ratio: ' + str(AspectRatio))
        
        # correct for aspect ratio if necessary
        if (AspectRatio < 6):                      #given aspect ratio else none
            #AR = PhotoSize_x/float(PhotoSize_y)     #floating(aspect-ratio)
            #Log('Routine aspect ratio: ' + str(AR))
            
            if (PhotoSize_y > int(PhotoSize_x / AR)):     #aspect ratio is wrong
                PhotoSize_y = int(PhotoSize_x / AR)     #resize y, x is oke
                #Log('Photosize_y aanpassen')
            else:
                PhotoSize_x = int(AR * PhotoSize_y)         #resize x, y is oke
                #Log('Photosize_x aanpassen')

        MaxPhotoWidth = PhotoSize_x         #sizes are now conform the aspect ratio
        MaxPhotoHeight = PhotoSize_y
    else:                                       #fixed_size is true
        MaxPhotoWidth = int(PhotoSize_x * dpi / 25.4)
        MaxPhotoHeight = int(PhotoSize_y * dpi / 25.4)


    #Log('CalcMaxPhotoSize na(bxh): ' + str(MaxPhotoWidth) + ' , ' + str(MaxPhotoHeight))

    return MaxPhotoWidth, MaxPhotoHeight        #sizes are in px (integers)



#==============================================================================
#================= main routine generate photo print  =========================
#==============================================================================
def Photo_Print(file_type, location, all_subdirs, contact_name, contact_type,
                contact_location, aspect_ratio, crop_photos, contact_size,
                dpi, orient, num_col, num_rows, PageBorderL, PageBorderR, PageBorderT,
                PageBorderB, mmFOTO_MARGIN, print_direct):
   
    #collect 'all' images in the choosen directory and subdirs
    images = get_images(file_type, location, all_subdirs)
    num_images = len(images)                        #calculate number of images    
    
    #make  a new drawing canvas of the correct size
    width,height = CalcPaperSize(contact_size, dpi, orient) #papersize dimensions in px
    #Log('papiergrootte in px (bxh): ' + str(width) + ' , ' + str(height))

    #calculate the maximum size for the fotos based on the number of images
    #per row and number of rows.
    #Sizes are in px 
    LEFT_PAGE_BORDER = int(PageBorderL * dpi / 25.4)   
    RIGHT_PAGE_BORDER = int(PageBorderR * dpi / 25.4)
    BOTTOM_PAGE_BORDER = int(PageBorderB * dpi / 25.4)
    TOP_PAGE_BORDER = int(PageBorderT * dpi / 25.4)
    PHOTO_MARGIN = int(mmFOTO_MARGIN * dpi / 25.4)
    
    #calculate canvas size in px (the printable sheet dimensions)
    CanvasWidth = width - LEFT_PAGE_BORDER - RIGHT_PAGE_BORDER
    CanvasHeight = height - BOTTOM_PAGE_BORDER - TOP_PAGE_BORDER
    #Log('canvasgrootte in px (bxh): ' + str(CanvasWidth) + ' , ' + str(CanvasHeight))

    #calculate max photo size in px
    Photo_width, Photo_height = CalcMaxPhotoSize(CanvasWidth, CanvasHeight,
                                                 num_col, num_rows, aspect_ratio,
                                                 PHOTO_MARGIN, dpi)
    #Log('foto grootte in px (bxh): ' + str(Photo_width) + ' , ' + str(Photo_height))


    PhotosPerSheet = int(num_col*num_rows)
    img_no = 1
    for sheetcount in range(int(ceil(num_images/float(PhotosPerSheet)))):
    
        sheetimg = gimp.Image(width,height,RGB)   #make sheet of the desired size
        bklayer = gimp.Layer(sheetimg,"Background",width,height,
                                 RGB_IMAGE,100,NORMAL_MODE)

        sheetimg.disable_undo()
        sheetimg.add_layer(bklayer,0)
        sheetimg.resolution = (float(dpi), float(dpi))
        
        bklayer.fill(WHITE_FILL)
        bklayer.flush()
        sheetdsp = gimp.Display(sheetimg)
        gimp.displays_flush()        
        
        CalcTextHeight =0
        txtw,txth,txte,txtd = (0,0,0,0)

        files = images[sheetcount*PhotosPerSheet:(sheetcount+1)*PhotosPerSheet]
        #now for each of the image files generate a photo
        rcount = 0
        ccount = 0
        #generate photo
        for file in files:
            thumbimg,x_size,y_size = generate_foto(file['image_file'],Photo_width,Photo_height,
                                                   crop_photos, aspect_ratio)
            cpy = pdb.gimp_edit_copy(thumbimg.active_layer)
            #center image within its minipage
            if (x_size>y_size):
                #landscape image, center vertical
                y_offset = (Photo_width - y_size)/2
                x_offset = 0
            else:
                #portrait image, center horizontal
                x_offset = (Photo_height - x_size)/2
                y_offset = 0

            gimp.delete(thumbimg)
            #now paste the new thumb into contact sheet
            newselect = pdb.gimp_edit_paste(sheetimg.active_layer,True)

            #positition in top left corner 
            newselect.translate(-newselect.offsets[0],-newselect.offsets[1])
            #now position in correct position, modified with x- and y-offset

            xpos = LEFT_PAGE_BORDER + ccount * (Photo_width + PHOTO_MARGIN)
            ypos = TOP_PAGE_BORDER + rcount * (Photo_height + PHOTO_MARGIN )

            newselect.translate(xpos,ypos)
            pdb.gimp_floating_sel_anchor(newselect)

            ccount = ccount + 1
            if (ccount>= num_col):
                ccount = 0
                rcount = rcount + 1
            gimp.displays_flush()

        #save photoprint
        contact_filename = contact_name + "_%03d" % (sheetcount) + contact_type
        contact_full_filename = os.path.join(contact_location, contact_filename)
        #print "File to save " + contact_full_filename
        if (contact_type == ".jpg"):
            save_jpeg(sheetimg,contact_full_filename,"")
        else:
            save_png(sheetimg,pdb.gimp_image_get_active_drawable(sheetimg),
                     contact_full_filename,False)


        if (print_direct == True):
            pdb.file_print_gtk(sheetimg)

        gimp.delete(sheetimg)
        pdb.gimp_display_delete(sheetdsp) 


register(
        "python_fu_photo_print",
        _("Generates photoprint(s) for a directory of images. If you find this script useful or any bugs I would love to hear from you at moroquendo@gmail.com\n"),
        _("Generates photoprint(s) and print with a configurable number of photos for all photofiles located in a directory and subdirectory"),
        "E. Sullock Enzlin",
        "Licensed under the GPL v2",
        "2009",
        "<Toolbox>/Xtns/Batch/Photo Print",
        "",
        [
        (PF_OPTION, "file_type"  ,_("File type: "), 0 ,[".jpg", ".png", ".tif", ".pcx",
                                                        ".xcf", _("all registered formats")]),
        (PF_DIRNAME, "location",
                     _('Generate photo print of\n all files in this directory: '), ""),
        (PF_BOOL, "all_subdirs", _("Include all subdirs? "), False),
        (PF_STRING, "contact_name",  _('Photoprint base name: '), _('photoprint')),
        (PF_RADIO, "contact_type", _('Photo print image type: '), ".jpg",
                                 (("jpg", ".jpg"),
                                  ("png", ".png"))),
        (PF_DIRNAME, "contact_location", _('Where the photo print should be saved in: '), ""),
        (PF_OPTION, "aspect_ratio"  ,_("Aspect ratio or size: "), 0 ,
                                     ["4:3", "16:9", "3:2", "5:4","6:7", "1:1", "none",
                                      "7x10", "9x13", "10x15", "13x18", "18x24"]),
        (PF_BOOL, "crop_photos"  ,_("Crop photos? "), False),        
        (PF_OPTION, "contact_size", _("Photo page size: "), 3,
                 ["Jumbo (10.2x15.2 cm)",
                  "6x8 (15.2x20.3 cm)",
                  "8x10 (20.3x25.4 cm)",
                  "A4 (20.9x29.7 cm)",
                  "A3 (29.7x42.0 cm)",
                  "Letter (8.5x11 in)",
                  "Legal (8.5x14 in)",
                  "Tabloid (11x17 in)"]),
        (PF_SPINNER, "dpi", _("Photo page resolution"), 300,(150,1200,50)),
        (PF_RADIO, "orient", _("Photo page orientation:"), "port",
                            ((_("portrait"), "port"),
                             (_("landscape"),"land"))),
        (PF_SPINNER, "num_col", _("Number of photos per row"), 2, (1,8,1)),
        (PF_SPINNER, "num_rows", _("Number of rows"), 2, (1,8,1)),
        (PF_SPINNER, "PageBorderL", _("Left Page border [mm]"), 10, (1,32,1)),
        (PF_SPINNER, "PageBorderR", _("Right Page border [mm]"), 10, (1,32,1)), 
        (PF_SPINNER, "PageBorderT", _("Top Page border [mm]"), 10, (1,32,1)),
        (PF_SPINNER, "PageBorderB", _("Bottom Page border [mm]"), 10, (1,32,1)),
        (PF_SPINNER, "mmFOTO_Margin", _("Distance between photos [mm]"), 1, (0,10,1)),
        (PF_BOOL, "print_direct", _("Directly printing? "), False)
        ],
        [],
        Photo_Print,
        menu="<Save>",
        domain=("photoprint", gimp.locale_directory)
        )

main()
