Image crop, resize and CMYK conversion. Save and reload in TIFF format

From Scribus Wiki
Revision as of 01:44, 5 August 2010 by Meira (talk | contribs)
Jump to navigation Jump to search

This scripter script crop and resize an image, save it and reload it in TIFF format. Optionaly, convert color space from RGB to CMYK. Use Python Image Library. Caveat: PIL currently freeze Scribus in Ubuntu 10.04. Run OK in Windows XP.

#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Crop and resample selected photo in Scribus
By prof. MS. José Antonio Meira da Rocha
mailto:joseantoniomeira@gmail.com
http://meiradarocha.jor.br
License GPL
2010-08-04a
PIL docs: http://infohost.nmt.edu/tcc/help/pubs/pil/image-constructors.html
http://www.pythonware.com/library/pil/handbook/index.htm
"""

import sys
if sys.platform != 'win32':
    sys.path.append("/usr/lib/python2.6") # prevent 'import re' PIL bug in Scribus 1.3.8, Ubuntu 10.04

try:
    import scribus
except ImportError,err:
    print "This Python script is written for the Scribus scripting interface."
    print "It can only be run from within Scribus."
    sys.exit(1)

from scribus import UNIT_POINTS, UNIT_MILLIMETERS, UNIT_INCHES, LINE_SOLID, JOIN_MITTER, BUTTON_OK, BUTTON_NO, BUTTON_YES, ICON_WARNING, ICON_INFORMATION, pt, mm

#########################
# USER IMPORTS GO HERE  #
#########################
import os

#############################################
# OS string encoding for PIL handle filenames
# (too much time to discover this)
#############################################
encoding = sys.getfilesystemencoding()

################################
# User can change this variables
################################
imageResolution = 200  # resolution for printing

###################
# Scribus Constants
UNDER_FRAME  = 0
AROUND_FRAME = 1
BOUNDING_BOX = 2
CONTOUR_LINE = 3
SCALETOFRAME = 1
FREESCALE = 0
PROPORTIONAL = 1
DISTORTED = 0

######################
# Locale strings
######################
# Textos para abrir documento
askResolutionLabel="Abra um documento"
askResolution = "<h2>Qual a resolução</h2>" \
    + "<p></p>"
#    
openImageErrorLabel = 'Erro de abertura'
openImageErrorMsg = '<h2>Erro de abertura</h2>' \
    + '<p>Houve um erro ao tentar abrir o arquivo de foto. <br>Talvez o arquivo tenha sido perdido.</p>'
#    
openDocLabel="Abra um documento"
askOpenDoc = "<h2>Abra um documento</h2>" \
    + "<p>Por favor, abra um documento e selecione um quadro antes de usar este script.</p>"
# Textos para abrir quadro
imageFrameLabel = "Selecione um quadro de imagem"
askSelectImageFrame = "<h2>Selecione um quadro de imagem</h2>\n" \
    + "Selecione <b>um quadro de imagem</b>\n" \
    + "para cortar a foto dentro dele." 
# 
outOfRangeLabel = 'Foto fora de faixa'
msgOutOfRange = '<h2>Foto fora de faixa</h2>A foto não está ocupando todo o quadro.'
# Error on save image
errorOnSaveLabel = 'Erro ao gravar'
errorOnSaveMsg = '<h2>Erro ao gravar</h2>Houve um erro ao gravar o arquivo de imagem.'
#Error on cropping
cropErrorLabel = 'Erro ao cortar a imagem'
cropErrorMsg = '<h2>Erro ao cortar a imagem</h2><p>Houve um erro ao cortar a imagem. Talvez este tipo de arquivo não seja suportado.'
# Error on loading image
errorOnLoadLabel = 'Erro ao importar a imagem'
errorOnLoadMsg = '<h2>Erro ao importar a imagem</h2>Houve um erro ao importar a imagem.'

#########################################
# Localized group name
# Put your language string for group names in dictionary
# For use by isGroup() function
stringsDic = {'en_US':'Group', 'en_GB':'Group', 'en_AU':'Group', 'pt_BR':'Agrup','pt': 'Agrup'}
lang = scribus.getGuiLanguage()
try:
    groupString = stringsDic[lang]
except:
    scribus.messageBox('Missing group string','Put <b>group</b> string in your language in "stringsDic".',ICON_WARNING,BUTTON_OK)
    sys.exit(1)

# cropped sufix
cropsufix = '_cortado'  # '_cropped'
    
# foot msg
statusText = "Running script..."

#
# End Locale strings
####################

#############
# PIL library
#############
# 'import Image' cause Scribus freeze after script run, in Ubuntu 10.04. 
#  OK in Windows XP, Python 2.5.4, PIL 1.1.7
try:
    import Image
except ImportError,err:
    print "This Python script is written for the PIL graphic interface."
    print "It should be instaled in Scribus Python tree."
    sys.exit(1)

##############################################
# Test object type
#############################################

def isGroup(obj):
    """Verify if object is group"""
    type = scribus.getObjectType(obj)
    if (type == 'Polygon') and (scribus.selectionCount() > 1) and (obj.find(groupString) != -1):
        return 1
    else:
        return 0

def isTextFrame(obj):
    """Verify if object is text frame.
    Devolve zero se não é texto."""
    type = scribus.getObjectType(obj)
    if (type == 'TextFrame'):
        return 1
    else:
        return 0

def isGraphicFrame(obj):
    """Verify if object is image frame
    Devolve zero se não é grupo imagem."""
    type = scribus.getObjectType(obj)
    if (type == 'ImageFrame'):
        return 1
    else:
        return 0

######################
# Open image
######################
def openImage(imageFrame):
    imf = scribus.getImageFile(imageFrame)
    try:
        image = Image.open(imf.encode(encoding)) # encode to let PIL handle accented filenames
    except:
        scribus.messageBox(openImageErrorLabel,openImageErrorMsg,ICON_WARNING,BUTTON_OK)
        image,imageFile = "",""
        sys.exit(1)
    return image,imf

##################
# Crop Image
##################
def cropImage(image,imageFrame):
    imageXOffset = scribus.getProperty(imageFrame,'imageXOffset')
    imageYOffset = scribus.getProperty(imageFrame,'imageYOffset')
    # spawn error if offset is positive
    if (imageXOffset > 0) or (imageYOffset > 0):
        scribus.messageBox(outOfRangeLabel,msgOutOfRange,ICON_WARNING,BUTTON_OK)
        sys.exit(1)
    # Calculate image resample to press resolution (DPI)
    unit = scribus.getUnit()
    scribus.setUnit(UNIT_INCHES)
    frameSizeX,frameSizeY = scribus.getSize(imageFrame)
    newWidth = frameSizeX * imageResolution
    newHeight = frameSizeY * imageResolution
    scribus.setUnit(unit)
    # Calculate cropping
    frameSizeX,frameSizeY = scribus.getSize(imageFrame)
    imageXScale = scribus.getProperty(imageFrame,'imageXScale')
    imageYScale = scribus.getProperty(imageFrame,'imageYScale')
    imageSizeX, imageSizeY = image.size
    left = imageXOffset * -1 # 
    top = imageYOffset * -1 # 
    right = left + (frameSizeX / imageXScale)
    bottom = top + (frameSizeY / imageYScale)
    try:
        im = image.crop((left,top,right,bottom))
        im = im.resize((int(newWidth),int(newHeight)),Image.ANTIALIAS)# BICUBIC,NEAREST, BILINEAR, ANTIALIAS
    except:
        scribus.messageBox(cropErrorLabel,cropErrorMsg,ICON_WARNING,BUTTON_OK)
        sys.exit(1)
    # Uncomment this 2 lines if you wish color space conversion. 
    #if im.mode == 'RGB':
    #    im = im.convert('CMYK')
    return im

#################
# Save Image
#################    
def saveImage(newImage,imageFile):
    name,ext = os.path.splitext(imageFile)
    newImageFile = name+cropsufix+'.tif' # force tiff format
    try:
        # 'encode' let PIL handle accented filenames
        newImage.save(newImageFile.encode(encoding),dpi=(imageResolution,imageResolution))
    except:
        scribus.messageBox(errorOnSaveLabel,errorOnSaveMsg,ICON_WARNING,BUTTON_OK)
        sys.exit(1)
    return newImageFile

#######################
# Reload image to frame
#######################
def reloadImage(newImageFile,imageFrame):
    try:
        scribus.loadImage(newImageFile,imageFrame)
    except:
        scribus.messageBox(errorOnLoadLabel,errorOnLoadMsg,ICON_WARNING,BUTTON_OK)
        sys.exit(1)
    scribus.setScaleImageToFrame(SCALETOFRAME,PROPORTIONAL,imageFrame)

##################
# Handle Image
##################
def handleImage(imageFrame):
    image,imageFile = openImage(imageFrame)
    newImage = cropImage(image,imageFrame)
    newImageFile = saveImage(newImage,imageFile)
    reloadImage(newImageFile,imageFrame)

##################
# Handle selection
##################
def handleSelection():
    """Handle selected objects."""
    if (scribus.selectionCount() == 1) and isGraphicFrame(scribus.getSelectedObject()):
        imageFrame = scribus.getSelectedObject()
        handleImage(imageFrame)        
    else:
        scribus.messageBox(imageFrameLabel,askSelectImageFrame,ICON_WARNING,BUTTON_OK)

#####################
# Handle document
#####################
def handleDocument(): 
    """Handle documents """
    # If there are open document
    if scribus.haveDoc():
        # turn off redraw
        scribus.setRedraw(False)
        # Save unit
        unit = scribus.getUnit() 
        # Define unit in points
        scribus.setUnit(UNIT_POINTS) # pre-press mesure system
        print
        ###############################
        # Handle selection
        ###############################
        handleSelection()
        # Recover units
        scribus.setUnit(unit)
    else:  # If there not open document.
        scribus.messageBox(openDocLabel,askOpenDoc,ICON_WARNING,BUTTON_OK)

def myCode(): 
    """ User code """
    #########################
    #  USER CODE GOES HERE  #
    #########################
    # Gerencia documento (aberto, abre etc)
    handleDocument()
    #########################
    #  USER CODE ENDS HERE  #
    #########################

def main(argv):
    """Main entry point"""
    myCode()

def main_wrapper(argv):
    try:
        scribus.statusMessage(statusText)
        scribus.progressReset()
        main(argv)
    finally:
        if scribus.haveDoc():
            scribus.setRedraw(True)
        scribus.statusMessage("")
        scribus.progressReset()

if __name__ == '__main__':
    main_wrapper(sys.argv)