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, 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)