from PSPApp import *
import string
import PSPUtils

def ScriptProperties():
    return {
        'Author': u'Corel Corporation',
        'Copyright': u'Copyright (c) 2002-2006 Corel Corporation. All rights reserved.',
        'Description': "Put EXIF camera and exposure information at the bottom of the image.",
        'Host': u'Paint Shop Pro 9',
        'Host Version': u'9.00',
        }


def Do(Environment):
    ''' This script extracts data from the active document to place a caption at the lower right corner
        of the image.  The caption contains the camera make/model number, aperture and exposure time.
        This does require that the image contain this information to being with - if no EXIF data is
        found it puts up a message box and returns.

        The text is placed at the bottom right corner of the image.  To make it easier to read, the area
        around the text is filled with a dark gray.

        To isolate the caption and backdrop from the rest of the image, a layer group is created.
        Following execution of the script, three additional layers will be created, placed above the
        layer that was active when the script was run:
        EXIF Caption - the group layer
          EXIF Text - this is a vector layer containing the text we created
          Caption Background - this is a raster layer that is filled with grey around the text
    '''
    if PSPUtils.RequireADoc( Environment ) == App.Constants.Boolean.false:
        return

    
    # first extract the EXIF data - if we can't find any just return without changing the image
    ImageInfo = App.Do( Environment, 'ReturnImageInfo', {'GeneralSettings': {'Version': ((9,0,0),1) }} )
    if ImageInfo['ExifMake'] == '' or ImageInfo['ExifModel'] == '' or \
       ImageInfo['ExifFNumber' ] == '' or ImageInfo['ExifExposureTime'] == '':
        App.Do(Environment,  'MsgBox', {
                'Buttons': App.Constants.MsgButtons.OK, 
                'Icon': App.Constants.MsgIcons.Stop, 
                'Text': PSPUtils.NoEXIFData,
                'GeneralSettings': {'Version': ((9,0,0),1) }
                })
        return


    # save any existing selection
    SelSaver = PSPUtils.SaveSelection( Environment, App.TargetDocument )
    
    # assemble the camera string by concatenating the camera make and model.  Some camera
    # manufacturers have the barbaric practice of CAPITALIZING everything in their make and model
    # strings, so convert it to initial caps only for a more civilized appearance
    CaptionTextCamera = unicode(string.capwords( ImageInfo['ExifMake'] + ' ' + ImageInfo[ 'ExifModel' ] ))
    
    # now assemble exposure information by using the aperture and exposure
    Aperture = float(ImageInfo['ExifFNumber'])
    CaptionTextExposure = PSPUtils.ExposureMsg % (Aperture, ImageInfo['ExifExposureTime'].strip())

    # first we create a raster layer at 50% opacity as a backdrop for the caption    
    # for now the raster layer is empty - we'll fill it in later
    # the new layer becomes the active layer
    App.Do( Environment, 'NewRasterLayer', {
            'General': {
                'Opacity': 50, 
                'Name': PSPUtils.CaptionBackground, 
                'IsVisible': App.Constants.Boolean.true, 
                }, 
            'GeneralSettings': {
                'ExecutionMode': App.Constants.ExecutionMode.Silent,
                'Version': ((9,0,0),1)
                }
            })
    
    # create a layer group.  This will place the raster layer in the group
    # the group is the active layer on completion
    App.Do( Environment, 'NewLayerGroup', {
            'General': {
                'Opacity': 100, 
                'Name': PSPUtils.EXIFCaption, 
                }, 
            'GeneralSettings': {
                'ExecutionMode': App.Constants.ExecutionMode.Silent,
                'Version': ((9,0,0),1)
                }
            })

    # select the raster layer so that the vector layer gets created above it
    App.Do( Environment, 'SelectLayer', {
            'Path': (0,0,[1],App.Constants.Boolean.false),
            'GeneralSettings': {'Version': ((9,0,0),1) }
            })
    
    # now create a vector layer to put text on - creating the layer will make it active
    App.Do( Environment, 'NewVectorLayer', {
            'General': {
                'Opacity': 100, 
                'Name': PSPUtils.EXIFText, 
                }, 
            'GeneralSettings': {
                'ExecutionMode': App.Constants.ExecutionMode.Silent,
                'Version': ((9,0,0),1)
                }
            })

    # Figure out how big the text should be by examining the overall image size.  We'll do a rough
    # scale based on 1000 pixels.  We won't paint text less than 16 point in any event.
    ImageMaxDimension = max(App.TargetDocument.Width, App.TargetDocument.Height)
    TextScaleFactor = max(0.25, float(ImageMaxDimension) / 1000.0)
    TextSize = int(16.0 * TextScaleFactor)
 
    # now place the text - use right justification at the lower right corner of the image.
    # we are placing 16 pixel text, so to leave some room for leading we place the first
    # line of text 24 pixels up from the bottom, and the second will be only 4 pixels up
    # from the bottom.
    # since we use a black backdrop for the text, make the text color white.
    TextPlacementLine1 = (App.TargetDocument.Width - 4 * TextScaleFactor, App.TargetDocument.Height - (24 * TextScaleFactor))
    App.Do( Environment, 'TextEx', {
            'Visibility': True, 
            'CreateAs': App.Constants.CreateAs.Vector, 
            'TextFlow': App.Constants.TextFlow.HorizontalDown, 
            'TextType': App.Constants.TextType.TextBase, 
            'AutoKern': False, 
            'AntialiasStyle': App.Constants.AntialiasEx.Smooth, 
            'Fill': {
                'Color': (255,255,255), 
                'Pattern': None, 
                'Gradient': None, 
                'Texture': None
                }, 
            'Font': PSPUtils.CaptionFontName, 
            'PointSize': TextSize, 
            'Start': TextPlacementLine1, 
            'Stroke': None,
            'LineStyle': None,
            'LineWidth':0,
            'SetText': App.Constants.Justify.Right, 
            'Characters': CaptionTextCamera, 
            'GeneralSettings': {
                'ExecutionMode': App.Constants.ExecutionMode.Silent, 
                'AutoActionMode': App.Constants.AutoActionMode.Match,
                'Version': ((9,0,0),1)
                }
            })

    # place the second line of text
    TextPlacementLine2 = (App.TargetDocument.Width - 4 * TextScaleFactor, App.TargetDocument.Height - (4 * TextScaleFactor) )
    App.Do( Environment, 'TextEx', {
            'Visibility': True, 
            'CreateAs': App.Constants.CreateAs.Vector, 
            'TextFlow': App.Constants.TextFlow.HorizontalDown, 
            'TextType': App.Constants.TextType.TextBase, 
            'AutoKern': False, 
            'AntialiasStyle': App.Constants.AntialiasEx.Smooth, 
            'Fill': {
                'Color': (255,255,255), 
                'Pattern': None, 
                'Gradient': None, 
                'Texture': None
                }, 
            'Font': PSPUtils.CaptionFontName, 
            'PointSize': TextSize, 
            'Start': TextPlacementLine2, 
            'Stroke': None,
            'LineStyle': None,
            'LineWidth':0,
            'SetText': App.Constants.Justify.Right, 
            'Characters': CaptionTextExposure, 
            'GeneralSettings': {
                'ExecutionMode': App.Constants.ExecutionMode.Silent, 
                'AutoActionMode': App.Constants.AutoActionMode.Match,
                'Version': ((9,0,0),1)
                }
            })

    # we have the text down, but we want to put a backdrop behind it so that the text remains
    # visible.  How big do we make the backdrop?  Who knows, so we just ask the vector layer how
    # big it is
    Result = App.Do( Environment, 'ReturnLayerProperties', {'GeneralSettings': {'Version': ((9,0,0),1) }} )
    TextRectangle = Result[ 'LayerRect' ]
    FillStartPoint = ( TextRectangle[0][0] - (4 * TextScaleFactor), TextRectangle[0][1] - (4 * TextScaleFactor) )
    FillEndPoint = ( App.TargetDocument.Width, App.TargetDocument.Height )
    
    # select the raster layer - it is immediately below the vector layer
    App.Do( Environment, 'SelectLayer', {
            'Path': (0,-1,[],App.Constants.Boolean.false),
            'GeneralSettings': {'Version': ((9,0,0),1) }
            })

    # make a selection around the bounding box of the text.  Once we have a selection we'll fill it
    App.Do( Environment, 'Selection', {
            'General': {
                'Mode': App.Constants.SelectionOperation.Replace, 
                'Antialias': App.Constants.Boolean.true, 
                'Feather': 0
                }, 
            'SelectionShape': App.Constants.SelectionShape.Rectangle, 
            'Start': FillStartPoint, 
            'End': FillEndPoint, 
            'GeneralSettings': {
                'ExecutionMode': App.Constants.ExecutionMode.Silent,
                'Version': ((9,0,0),1)
                }
            })

    # now do a flood fill, making sure the point we click on is inside of our selection
    # use a dark grey for the fill so that we can see the text on top of it
    App.Do( Environment, 'Fill', {
            'BlendMode': 0, 
            'MatchMode': 1, 
            'Material': {
                'Color': (32,32,32), 
                'Pattern': None, 
                'Gradient': None, 
                'Texture': None
                }, 
            'Opacity': 100, 
            'Point': (FillStartPoint[0] + 1, FillStartPoint[1] + 1), 
            'Tolerance': 20, 
            'GeneralSettings': {
                'ExecutionMode': App.Constants.ExecutionMode.Silent,
                'Version': ((9,0,0),1)
                }
            })

    # restore the original selectoin
    SelSaver.RestoreSelection()
    
    # All done!
