using Mac OS X CoreGraphics via ctypes

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Daniel

    #1

    using Mac OS X CoreGraphics via ctypes

    I'm trying to implement a routine that converts a PDF document to
    image files using ctypes and the Apple CoreGraphics library as per the
    'Splitting a PDF File' example on Apple's web site [0]. Unfortunately
    I cannot use the CoreGraphics module used in that example because I'm
    using Python 2.5 (AFAIK that module is only available in the system
    default Python 2.3.5). There are three questions in the code snippet
    below. Each problem area has been commented out in the example so it
    runs through to the end. The code is obviously not complete, but it's
    enough do demonstrate my problems so far.

    BTW, this is the only way I have found to convert a PDF (generated by
    ReportLab) to an image that can be fed into a PyQt (v3) QPrinter
    object. If anyone knows another way to gain access to the system print
    services on Mac OS X using Python please do tell. Oh yes, I'd rather
    not include PyObjC because I'm already packaging PyQt, and that would
    make the resulting app a lot bigger.

    # BEGIN CODE
    from ctypes import cdll, c_void_p
    from ctypes.util import find_library

    cglib = cdll.LoadLibrar y(find_library( 'ApplicationSer vices'))

    # the next line causes a segfault - what's the right way to do this?
    #GCS_RGB = cglib.kCGColorS paceGenericRGB( )
    #cs = cglib.CGColorSp aceCreateWithNa me(GCS_RGB)

    # the next line causes the following error:
    #CGPDFDocumentR ef = cglib.CGPDFDocu mentRef
    # AttributeError: dlsym(0x1018c0, CGPDFDocumentRe f): symbol not found

    CGPDFDocumentCr eateWithProvide r =
    cglib.CGPDFDocu mentCreateWithP rovider
    CGPDFDocumentCr eateWithProvide r.restype = c_void_p #CGPDFDocumentR ef

    provider = cglib.CGDataPro viderCreateWith Filename("sampl e.pdf")
    pdf = CGPDFDocumentCr eateWithProvide r(provider)

    #for page in xrange(1, pdf.getNumberOf Pages() + 1):
    # print page
    # pdf.getNumberOf Pages caues the following error:
    # AttributeError: 'int' object has no attribute 'getNumberOfPag es'
    # I presume the 'pdf' object is a pointer. How do I get a real
    # CGPDFDocuemnt instance that has a getNumberOfPage s method?

    cglib.CGPDFDocu mentRelease(pdf )
    # END CODE

    [0] Splitting a PDF File <http://developer.apple.com/graphicsimaging/
    pythonandquartz .html>

    Thanks in advance for any hints you can provide.

    ~ Daniel

  • Diez B. Roggisch

    #2
    Re: using Mac OS X CoreGraphics via ctypes

    Daniel schrieb:
    I'm trying to implement a routine that converts a PDF document to
    image files using ctypes and the Apple CoreGraphics library as per the
    'Splitting a PDF File' example on Apple's web site [0]. Unfortunately
    I cannot use the CoreGraphics module used in that example because I'm
    using Python 2.5 (AFAIK that module is only available in the system
    default Python 2.3.5). There are three questions in the code snippet
    below. Each problem area has been commented out in the example so it
    runs through to the end. The code is obviously not complete, but it's
    enough do demonstrate my problems so far.
    >
    BTW, this is the only way I have found to convert a PDF (generated by
    ReportLab) to an image that can be fed into a PyQt (v3) QPrinter
    object. If anyone knows another way to gain access to the system print
    services on Mac OS X using Python please do tell. Oh yes, I'd rather
    not include PyObjC because I'm already packaging PyQt, and that would
    make the resulting app a lot bigger.
    # BEGIN CODE
    from ctypes import cdll, c_void_p
    from ctypes.util import find_library
    >
    cglib = cdll.LoadLibrar y(find_library( 'ApplicationSer vices'))
    >
    # the next line causes a segfault - what's the right way to do this?
    #GCS_RGB = cglib.kCGColorS paceGenericRGB( )
    Usually, things in the OSX lib that start with k* are a constant - not a
    function. As is this.


    Diez

    Comment

    • Daniel

      #3
      Re: using Mac OS X CoreGraphics via ctypes

      # the next line causes a segfault - what's the right way to do this?
      #GCS_RGB = cglib.kCGColorS paceGenericRGB( )
      >
      Usually, things in the OSX lib that start with k* are a constant - not a
      function. As is this.
      >
      Diez
      That's what I thought too. But when I try passing it directly as if it
      were a constant:

      GCS_RGB = cglib.kCGColorS paceGenericRGB
      cs = cglib.CGColorSp aceCreateWithNa me(GCS_RGB)

      I get a segfault too. ctypes said kCGColorSpaceGe nericRGB was a
      function pointer, so I thought maybe I needed to call it to get the
      value (not very good reasoning, I know).

      ~ Daniel

      Comment

      • Diez B. Roggisch

        #4
        Re: using Mac OS X CoreGraphics via ctypes

        Daniel wrote:
        # the next line causes a segfault - what's the right way to do this?
        #GCS_RGB = cglib.kCGColorS paceGenericRGB( )
        >>
        >Usually, things in the OSX lib that start with k* are a constant - not a
        >function. As is this.
        >>
        >Diez
        >
        That's what I thought too. But when I try passing it directly as if it
        were a constant:
        >
        GCS_RGB = cglib.kCGColorS paceGenericRGB
        cs = cglib.CGColorSp aceCreateWithNa me(GCS_RGB)
        >
        I get a segfault too. ctypes said kCGColorSpaceGe nericRGB was a
        function pointer, so I thought maybe I needed to call it to get the
        value (not very good reasoning, I know).
        I'm not sure what that constant exported is - but how about looking the
        constant up in the ref docs and pass it as value? Usually these thingies
        are some 4-byte-string, or a normal zero-terminated one.

        Diez

        Comment

        • Daniel

          #5
          Re: using Mac OS X CoreGraphics via ctypes

          On Jun 18, 6:07 am, "Diez B. Roggisch" <d...@nospam.we b.dewrote:
          Daniel wrote:
          # the next line causes a segfault - what's the right way to do this?
          #GCS_RGB = cglib.kCGColorS paceGenericRGB( )
          >
          Usually, things in the OSX lib that start with k* are a constant - not a
          function. As is this.
          >
          Diez
          >
          That's what I thought too. But when I try passing it directly as if it
          were a constant:
          >
          GCS_RGB = cglib.kCGColorS paceGenericRGB
          cs = cglib.CGColorSp aceCreateWithNa me(GCS_RGB)
          >
          I get a segfault too. ctypes said kCGColorSpaceGe nericRGB was a
          function pointer, so I thought maybe I needed to call it to get the
          value (not very good reasoning, I know).
          >
          I'm not sure what that constant exported is - but how about looking the
          constant up in the ref docs and pass it as value? Usually these thingies
          are some 4-byte-string, or a normal zero-terminated one.
          >
          Thanks Diez. I'll try that if I decide to keep going with ctypes. I
          got a bit further but had some problems with memory management (i.e.
          retaining and releasing object references). It seemed like Python/
          ctypes was accessing referenced objects after I had released them,
          which caused segfaults. I may resort to writing an extension in C that
          will handle the entire print process for me rather than fiddling
          around with something that gets me half way there. For anyone
          interested, here is the code I ended up with:


          from ctypes import cdll, cast, c_void_p
          from ctypes.util import find_library
          cglib = cdll.LoadLibrar y(find_library( "ApplicationSer vices"))

          CFStringRef = c_void_p

          CGColorSpaceCre ateWithName = cglib.CGColorSp aceCreateWithNa me
          CGColorSpaceCre ateWithName.res type = c_void_p
          CGColorSpaceCre ateWithName.arg types = [CFStringRef]

          CGPDFDocumentCr eateWithProvide r =
          cglib.CGPDFDocu mentCreateWithP rovider
          CGPDFDocumentCr eateWithProvide r.restype = c_void_p

          provider = cglib.CGDataPro viderCreateWith Filename("sampl e.pdf")
          if provider:
          BMP_INFO = cglib.kCGBitmap ByteOrderDefaul t
          CS_RGB = cast(cglib.kCGC olorSpaceGeneri cRGB, CFStringRef)

          #cs = CGColorSpaceCre ateWithName(CS_ RGB) # segfault
          pdf = CGPDFDocumentCr eateWithProvide r(provider)
          npages = cglib.CGPDFDocu mentGetNumberOf Pages(pdf)

          for pnum in xrange(1, npages + 1):
          print "processing page", pnum
          page = cglib.CGPDFDocu mentGetPage(pdf , pnum)
          rect = cglib.CGPDFPage GetBoxRect(page , 0) # kCGPDFMediaBox = 0
          page_w = cglib.CGRectGet Width(rect)
          page_h = cglib.CGRectGet Height(rect)

          # incorrect constructor for bitmap
          #bitmap = cglib.CGBitmapC ontextCreate(No ne, page_w, page_h,
          cs, BMP_INFO)
          #cglib.CGContex tDrawPDFDocumen t(bitmap, rect, pdf, pnum)

          #cglib.CGPDFDoc umentRelease(pd f) # segfault
          #cglib.CGColorS paceRelease(cs)
          cglib.CGDataPro viderRelease(pr ovider)

          ~ Daniel

          Comment

          • Richard Jones

            #6
            Re: using Mac OS X CoreGraphics via ctypes

            Daniel wrote:
            Thanks Diez. I'll try that if I decide to keep going with ctypes. I
            got a bit further but had some problems with memory management (i.e.
            retaining and releasing object references). It seemed like Python/
            ctypes was accessing referenced objects after I had released them,
            which caused segfaults.
            I would be unlikely that this is the case. Much more likely is that you've
            got some memory allocated by Python which is being passed on to a C library
            and is subsequently freed by Python before the C library is finished with
            it. Happens all the time. Just make sure you keep a reference in Python
            land to any objects you've handed over to C for the lifetime that the C
            library is likely to use it.

            Having said that, it doesn't look like that's what's happening with your
            CGPDFDocumentRe lease call, though perhaps you needed to clean up the page
            or rect that you obtained in the loop?

            "k" constants defined as strings are 32-bit numbers derived from 4 character
            strings. You'll need to convert those strings to the correct number. Once
            you've done that I believe your CGColorSpaceCre ateWithName call will work.


            Richard

            Comment

            Working...