Automator Watermark PDF Workflow
Seems with every major upgrade, Apple breaks the Automator Watermark PDF Workflow.
Can someone test this workflow in Yosemite so I know if the problem I'm having is with OS X 10.10.
OS X Yosemite (10.10)
Seems with every major upgrade, Apple breaks the Automator Watermark PDF Workflow.
Can someone test this workflow in Yosemite so I know if the problem I'm having is with OS X 10.10.
OS X Yosemite (10.10)
Hello
Under 10.6.8, Watermark PDF Documents.action/Contents/Resources/tool.py works happily without any errors when invoked as follows with a.pdf and watermark.png in ~/desktop/test/ :
#!/bin/bash py='/System/Library/Automator/Watermark PDF Documents.action/Contents/Resources/tool.py' cd ~/desktop/test || exit args=( --input a.pdf --output a_wm.pdf --verbose --over --xOffset 0.0 --yOffset -150.0 --angle 300.0 --scale 0.3 --opacity 0.1 watermark.png ) "$py" "${args[@]}"
If the said error – ValueError: depythonifying 'pointer', got 'str' – is raised at the line:
provider = CGDataProviderCreateWithFilename(imagePath)
I'd think it is because imagePath is not a C string pointer which the function expects but a CFStringRef or something which is implicitly converted from python string. Since I don't get this error with pyobjc 2.2b3 & python 2.6 under 10.6.8, it is caused by something introduced in later versions.
Anyway, the statement in question may be replaced with the following statements if it helps:
url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, imagePath, len(imagePath), False) provider = CGDataProviderCreateWithURL(url)
I modified the tool.py with these changes along with other minor fixes and run it successfully under 10.6.8. I'm not sure at all whether it works under later OSes as well. And even if it does, editing tool.py will require the Automator action to be re-codesigned.
Here's the revised tool.py.
#!/usr/bin/python # Watermark each page in a PDF document import sys #, os import getopt import math from Quartz.CoreGraphics import * from Quartz.ImageIO import * def drawWatermark(ctx, image, xOffset, yOffset, angle, scale, opacity): if image: imageWidth = CGImageGetWidth(image) imageHeight = CGImageGetHeight(image) imageBox = CGRectMake(0, 0, imageWidth, imageHeight) CGContextSaveGState(ctx) CGContextSetAlpha(ctx, opacity) CGContextTranslateCTM(ctx, xOffset, yOffset) CGContextScaleCTM(ctx, scale, scale) CGContextTranslateCTM(ctx, imageWidth / 2, imageHeight / 2) CGContextRotateCTM(ctx, angle * math.pi / 180) CGContextTranslateCTM(ctx, -imageWidth / 2, -imageHeight / 2) CGContextDrawImage(ctx, imageBox, image) CGContextRestoreGState(ctx) def createImage(imagePath): image = None # provider = CGDataProviderCreateWithFilename(imagePath) # FIXED: replaced by the following CGDataProviderCreateWithURL() url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, imagePath, len(imagePath), False) provider = CGDataProviderCreateWithURL(url) if provider: imageSrc = CGImageSourceCreateWithDataProvider(provider, None) if imageSrc: image = CGImageSourceCreateImageAtIndex(imageSrc, 0, None) if not image: print "Cannot import the image from file %s" % imagePath return image def watermark(inputFile, watermarkFiles, outputFile, under, xOffset, yOffset, angle, scale, opacity, verbose): images = map(createImage, watermarkFiles) ctx = CGPDFContextCreateWithURL(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, outputFile, len(outputFile), False), None, None) if ctx: pdf = CGPDFDocumentCreateWithURL(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, inputFile, len(inputFile), False)) if pdf: for i in range(1, CGPDFDocumentGetNumberOfPages(pdf) + 1): image = images[i % len(images) - 1] page = CGPDFDocumentGetPage(pdf, i) if page: mediaBox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox) if CGRectIsEmpty(mediaBox): mediaBox = None CGContextBeginPage(ctx, mediaBox) if under: drawWatermark(ctx, image, xOffset, yOffset, angle, scale, opacity) CGContextDrawPDFPage(ctx, page) if not under: drawWatermark(ctx, image, xOffset, yOffset, angle, scale, opacity) CGContextEndPage(ctx) del pdf CGPDFContextClose(ctx) del ctx def main(argv): verbose = False readFilename = None writeFilename = None under = False xOffset = 0.0 # FIXED: changed to float value yOffset = 0.0 # FIXED: changed to float value angle = 0.0 # FIXED: changed to float value scale = 1.0 # FIXED: added opacity = 1.0 # Parse the command line options try: options, args = getopt.getopt(argv, "vutx:y:a:p:s:i:o:", ["verbose", "under", "over", "xOffset=", "yOffset=", "angle=", "opacity=", "scale=", "input=", "output=", ]) except getopt.GetoptError: usage() sys.exit(2) for option, arg in options: print option, arg if option in ("-i", "--input") : if verbose: print "Reading pages from %s." % (arg) readFilename = arg elif option in ("-o", "--output") : if verbose: print "Setting %s as the output." % (arg) writeFilename = arg elif option in ("-v", "--verbose") : print "Verbose mode enabled." verbose = True elif option in ("-u", "--under"): print "watermark under PDF" under = True elif option in ("-t", "--over"): # FIXED: changed to "-t" from "t" print "watermark over PDF" under = False elif option in ("-x", "--xOffset"): xOffset = float(arg) elif option in ("-y", "--yOffset"): yOffset = float(arg) elif option in ("-a", "--angle"): angle = -float(arg) elif option in ("-s", "--scale"): scale = float(arg) elif option in ("-p", "--opacity"): opacity = float(arg) else: print "Unknown argument: %s" % (option) if (len(args) > 0): watermark(readFilename, args, writeFilename, under, xOffset, yOffset, angle, scale, opacity, verbose); else: shutil.copyfile(readFilename, writeFilename); def usage(): print "Usage: watermark --input <file> --output <file> <watermark files>..." if __name__ == "__main__": print sys.argv main(sys.argv[1:])
All the best,
H
Just be aware that your solution may break again with the next OS X update.
You can prevent this by putting your tool_2.py in your local Library (or other) folder.
True, thanks for the warning. I will make a backup of it but hope apple get a oficial fix soon.
For portability to other users, see if the $HOME variable works: $HOME/Desktop/tool.py (or ~/Desktop/tool.py)
Many thanks! That's great.
I've written a whole bunch of python Quartz scripts for manipulating PDFs. They are called "PDFSuite" on github.
I'll add this one, if that's OK.
I must have used an incorrect flag last night. Hiroto's code works in 10.10
Automator Watermark PDF Workflow