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
The Watermark PDF Documents Action is now fixed in OS X 10.11 (El Capitan)
Typos, in above, -under s/b —under (or -u) and -xOffset s/b —xOffset (or -x), - output s/b —outptut (or -o):
~/Desktop/Watermark.py -—under -—xOffset 15 --yOffset 55 --angle 0 --scale 0.75 --opacity 0.5 --input "Filename.PDF" -—output "FilenameCOPY.PDF" ~/Desktop/Watermark(COPY).pngUsed Hiroto's updated Python script. Used the Waternark.png that you posted. Used your corrected command-line settings. There is no watermark produced, and the len(args) returns 1.
I tried Hiroto's small shell script with its args unchanged except for my input and output filenames. Like above, it runs ok, and there is no watermark on the output PDF.
Can I say frustrated?
Well Tony, this PyObjC code is a work in progress. I cleaned up all syntax issues, but:
Replace confidential.pdf with your document (expects text on transparent background)
Output: Lorem.watermarked.pdf
Hi!
Thanks to Tony T1 & Hiroto first - great work guys!
I'm used this with previous OSX versions and now under 10.10 it's broken. So I managed to read through these topics here. What I've done so far:
Created a new folder on my desktop which should contain the neccessary files. I downloaded the tool.py from this topic - chmod'ed it and it works within command line:
./tool.py -h
['./tool.py', '-h']
Usage: watermark --input <file> --output <file> <watermark files>...
Using the tool.py manually works great as well:
./tool.py --under --xOffset 30 --yOffset 60 --angle 0 --scale 0.24 --opacity 1 --input test.pdf --output output.PDF vorlage.png
['./tool.py', '--under', '--xOffset', '30', '--yOffset', '60', '--angle', '0', '--scale', '0.24', '--opacity', '1', '--input', 'test.pdf', '--output', 'output.PDF', 'vorlage.png']
--under
watermark under PDF
--xOffset 30
--yOffset 60
--angle 0
--scale 0.24
--opacity 1
--input test.pdf
--output output.PDF
Here it is: http://pastebin.com/WyUPdh7x
Now I created an automator action based on Tony T1's - "Ask for finder objects" - "filter finder objects" - "execute shell sctipt" - it's all in german for me.
Unfortunately I get the error on line 8. I already removed every space after the "\" and I already tried to put everything into one line - no success at all.
Any idea about this?
Line 8 is the input one. I already replaced that one completely with one from another quote here... no success so far.
Ideas? Thanks a lot!
Hello
Here's sample pybojc code to draw text watermark using Core Text CTLine as a proof of concept.
#!/usr/bin/python # coding: utf-8 import math from Quartz.CoreGraphics import * from CoreText import * def drawWatermarkText(ctx, line, xOffset, yOffset, angle, scale, opacity): # CGContextRef ctx # CTLineRef line # float xOffset, yOffset, angle ([degree]), scale, opacity ([0.0, 1.0]) if line: rect = CTLineGetImageBounds(line, ctx) imageWidth = rect.size.width imageHeight = rect.size.height 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) CGContextSetTextPosition(ctx, 0.0, 0.0); CTLineDraw(line, ctx); CGContextRestoreGState(ctx) # parameters ifile = 'input.pdf' ofile = 'output.pdf' text = 'Watermark Sample' xOffset, yOffset, angle, scale, opacity = 0.0, 400.0, 60.0, 2.0, 0.2 # create CoreText line (CTLine) font = CTFontCreateWithName('Helvetica', 36.0, None) astr = CFAttributedStringCreate(kCFAllocatorDefault, text, { kCTFontAttributeName : font }) line = CTLineCreateWithAttributedString(astr) # create output pdf context ourl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, ofile, len(ofile), False) ctx = CGPDFContextCreateWithURL(ourl, None, None) # create input pdf document iurl = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, ifile, len(ifile), False) pdf = CGPDFDocumentCreateWithURL(iurl) if pdf: for i in range(0, CGPDFDocumentGetNumberOfPages(pdf)): page = CGPDFDocumentGetPage(pdf, i + 1) if page: mbox = CGPDFPageGetBoxRect(page, kCGPDFMediaBox) if CGRectIsEmpty(mbox): mbox = None CGContextBeginPage(ctx, mbox) CGContextDrawPDFPage(ctx, page) # elementary test CGContextSetTextPosition(ctx, 10.0, 10.0) CTLineDraw(line, ctx) # using general function drawWatermarkText(ctx, line, xOffset, yOffset, angle, scale, opacity) CGContextEndPage(ctx) del pdf CGPDFContextClose(ctx) del ctx
Briefly tested with pybojc 2.2b3 and python 2.6.1 under OS X 10.6.8.
Good luck,
H
Since error is related to matching quotes, try deleting and re-entering every "
Frank,
The tool.py file had a ton of Python syntax noise that I cleaned up. When I run it in the Terminal following precisely its command-line argument order, there appears to remain a consistent problem on line 31 with one of the Core Graphics methods, and a variable that was referenced before set. Will have to spend more cross-checking with the Dev docs. Maybe I can fix it.
I was trying to get the Python bit to work, because a UNIX executable living in MacOS that may also be a contributing factor to this misadventure.
I had tried that (with scale = 1.0) and got the same "ValueError: depythonifying 'pointer', got 'str'" error.
But as I said, I get the same error in terminal with OS X 10.7.5, yet it works within Automator (on 10.7.5), so there's something else in the Action that's resolving this issue (in 10.7.5) — but this does nothing to help in resolving the issue in 10.10. Looks like Apple needs to fix (I'll file a bug report)
Hiroto wrote:
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.
Thanks for the effort, but doesn't work in Terminal in OS X 10.10.
Another interesting quirk with the workflow in Yosemite is that when you add the Watermark PDF Documents action to the workflow, in Mavericks the gray box to the left of the adjustments is filled with a pdf document from the actions resource folder, Bears.pdf, to enable you see what the watermark will look like. In Yosemite that dummy file is not loaded.
In my case, I want to get rid of the original file and replace it with a watermarked file with the same filename. This can be done with the following AppleScript. You don't need to "Dispense Items Incrementally" with this. Note I am moving the original file to an arbitrary folder called trashFolder.
It appears that this is the python script that the Automater Actions runs
/System/Library/Automator/Watermark PDF Documents.action/Contents/Resources/tool.py
and according to the error I get from Automator
It appears the script is throwing an error. Not a python scriptor but one of you might be bale to see what trouble is.
I am learning more about this Python code. The correct command-line input for Hiroto's patch that does not produce any Python errors:
odin: ~$ tool2.py --angle 0.45 --over --input Lorem.pdf --output LoremD.pdf Draft.png
['./tool2.py', '--angle', '0.45', '--over', '--input', 'Lorem.pdf', '--output', 'LoremD.pdf', 'Draft.png']
--angle 0.45
--over
watermark over PDF
--input Lorem.pdf
--output LoremD.pdfAn output PDF is written — and silently ignores the Draft.png file — so there is no watermark applied.
Automator Watermark PDF Workflow