#!/usr/bin/python import sys,re,os,os.path from CoreGraphics import * def doit(pdfname): if not re.search(".pdf$",pdfname): return print pdfname dirname = re.sub(".pdf$","",pdfname) try: os.mkdir(dirname) except: print "Can't create directory '%s'"%(dirname) return
pdf = CGPDFDocumentCreateWithProvider(CGDataProviderCreateWithFilename(pdfname)) cs = CGColorSpaceCreateDeviceRGB() bg = CGFloatArray(5) # create's an array of 5 0's which is good enough for me for i in range(1, pdf.getNumberOfPages() + 1): page = pdf.getPage(i) r = page.getBoxRect(kCGPDFMediaBox) h = r.getHeight() w = r.getWidth() del page #c = CGBitmapContextCreateWithColor(int(w), int(h), cs, (0,0,0,0)) c = CGBitmapContextCreateWithColor(int(w), int(h), cs, bg) c.saveGState() c.setInterpolationQuality(kCGInterpolationHigh) c.drawPDFDocument(r,pdf,i) c.restoreGState() c.writeToFile(os.path.join(dirname, "page%04d.jpg"%i),kCGImageFormatJPEG) del c del cs del pdf if __name__=='__main__': for a in sys.argv[1:]: doit(a)The original version of this script was broken by Snow Leopard (which upgraded Python to 2.6.1). The call to CGBitmapContextCreateWithColor() failed with an error message about the 4th argument which it seems to think shouldn't be a 'const float[5]'.
The solution is to pass in a CGFloatArray() object instead. I haven't been able to modify one of those, but the default thats produced when you use 'bg = CGFloatArray(5)' appears to be good enough. Those objects still look leaky as hell but what are ya gonna do?
Squirrel:~ jeff$ python Python 2.6.1 (r261:67515, Jul 7 2009, 23:51:51) [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> from CoreGraphics import CGFloatArray >>> a = CGFloatArray(5) >>> print repr(a) <CoreGraphics.CGFloatArray; proxy of <Swig Object of type 'CGFloatArray *' at 0x2287a0> > >>> print repr(a[0]) swig/python detected a memory leak of type 'CGFloat *', no destructor found. <Swig Object of type 'CGFloat *' at 0x224d10> >>>
There's an unmatched bracket on line 25. I've tried the script, but it does nothing but create a folder. If I comment out the return statement, it works.
ReplyDeleteI'd like to include a modified version of this in a suite of python scripts that leverage Quartz to do stuff. Would that be ok? I've recently posted to the Quartz Dev mailing list, if that helps. Ben BW
Thanks for that - I'm surprised at it since I'm pretty sure I cut/paste that in from my working script. I must have been messing around with the try/catch stuff.
DeleteFeel free to include this in anything you like - any code I publish here can be considered to be in the public domain.
Ah, no, I realise what's happened. Its a cut/paste indentation error. The return should only have happened in the except.
DeleteI'm enjoying learning python and using Quartz, but I'm also infuriated by it! Making sure the objects and methods have all the right bits is a nightmare.
ReplyDeleteThe other problem is that Apple keep deprecating stuff, so most of the code examples contain things that will break or don't work.
The problem with the FloatArray set to 0 is that it produces TIFFs with a transparent background. I've tried adding a white rectangle using:
CGContextSetFillColorWithColor (c, kCGColorWhite)
CGContextFillRect (c, CGRectMake (0, 0, w, y ))
But get a variety of errors. (Also, it seems I have to import Quartz AND CoreGraphics!! Various things remain undefined if I only import one or other.)
Also writeToFile is deprecated, and you're supposed to use CGImageDestination. I'm trying to create 300dpi TIFFs, which is difficult.
The scripts that I've produced so far (admittedly, mostly a garland of other people's flowers) can be found here: https://github.com/benwiggy/PDFsuite
To be honest, I have not used this script in years, I really only needed it way back when, so I can't guarantee it will continue to work into the future.
DeleteThe problem with using CoreGraphics via Python is that you are perilously close to the metal with these methods, talking to swig-generated wrappers rather than hand-crafted code, hence the weird leak message I described above.
Any time I'm tempted to do stuff like this these days, I knock up a app using my custom embedded framework that allows the app complete control over *how* it exposes the internal APIs to Python.
https://bitbucket.org/tristero/embeddedpython