File size: 4,708 Bytes
d82cf6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
from ctypes import c_void_p, c_ubyte

from pyglet.image import ImageData, Animation, AnimationFrame
from pyglet.image.codecs import *

from pyglet.libs.darwin.cocoapy import cf, quartz, NSMakeRect
from pyglet.libs.darwin.cocoapy import cfnumber_to_number
from pyglet.libs.darwin.cocoapy import kCGImageAlphaPremultipliedLast
from pyglet.libs.darwin.cocoapy import kCGImagePropertyGIFDictionary
from pyglet.libs.darwin.cocoapy import kCGImagePropertyGIFDelayTime


class QuartzImageDecoder(ImageDecoder):
    def get_file_extensions(self):
        # Quartz can actually decode many more formats, but these are the most common.
        return [ '.bmp', '.cur', '.gif', '.ico', '.jp2', '.jpg', '.jpeg',
                 '.pcx', '.png', '.tga', '.tif', '.tiff', '.xbm', '.xpm' ]

    def get_animation_file_extensions(self):
        return ['.gif']

    def _get_pyglet_ImageData_from_source_at_index(self, sourceRef, index):
        imageRef = c_void_p(quartz.CGImageSourceCreateImageAtIndex(sourceRef, index, None))

        # Regardless of the internal format of the image (L, LA, RGB, RGBA, etc)
        # we just automatically convert everything to an RGBA format.
        format = 'RGBA'
        rgbColorSpace = c_void_p(quartz.CGColorSpaceCreateDeviceRGB())
        bitsPerComponent = 8
        width = quartz.CGImageGetWidth(imageRef)
        height = quartz.CGImageGetHeight(imageRef)
        bytesPerRow = 4 * width

        # Create a buffer to store the RGBA formatted data.
        bufferSize = height * bytesPerRow
        buffer = (c_ubyte * bufferSize)()

        # Create a bitmap context for the RGBA formatted data.
        # Note that premultiplied alpha is required:
        # http://developer.apple.com/library/mac/#qa/qa1037/_index.html
        bitmap = c_void_p(quartz.CGBitmapContextCreate(buffer,
                                                       width, height,
                                                       bitsPerComponent,
                                                       bytesPerRow,
                                                       rgbColorSpace,
                                                       kCGImageAlphaPremultipliedLast))

        # Write the image data into the bitmap.
        quartz.CGContextDrawImage(bitmap, NSMakeRect(0,0,width,height), imageRef)

        quartz.CGImageRelease(imageRef)
        quartz.CGContextRelease(bitmap)
        quartz.CGColorSpaceRelease(rgbColorSpace)

        pitch = bytesPerRow
        return ImageData(width, height, format, buffer, -pitch)

    def decode(self, filename, file):
        if not file:
            file = open(filename, 'rb')
        file_bytes = file.read()
        data = c_void_p(cf.CFDataCreate(None, file_bytes, len(file_bytes)))
        # Second argument is an options dictionary.  It might be a good idea to provide
        # a value for kCGImageSourceTypeIdentifierHint here using filename extension.
        sourceRef = c_void_p(quartz.CGImageSourceCreateWithData(data, None))
        image = self._get_pyglet_ImageData_from_source_at_index(sourceRef, 0)

        cf.CFRelease(data)
        cf.CFRelease(sourceRef)

        return image

    def decode_animation(self, filename, file):
        if not file:
            file = open(filename, 'rb')
        # If file is not an animated GIF, it will be loaded as a single-frame animation.
        file_bytes = file.read()
        data = c_void_p(cf.CFDataCreate(None, file_bytes, len(file_bytes)))
        sourceRef = c_void_p(quartz.CGImageSourceCreateWithData(data, None))

        # Get number of frames in the animation.
        count = quartz.CGImageSourceGetCount(sourceRef)

        frames = []

        for index in range(count):
            # Try to determine frame duration from GIF properties dictionary.
            duration = 0.1  # default duration if none found
            props = c_void_p(quartz.CGImageSourceCopyPropertiesAtIndex(sourceRef, index, None))
            if cf.CFDictionaryContainsKey(props, kCGImagePropertyGIFDictionary):
                gif_props = c_void_p(cf.CFDictionaryGetValue(props, kCGImagePropertyGIFDictionary))
                if cf.CFDictionaryContainsKey(gif_props, kCGImagePropertyGIFDelayTime):
                    duration = cfnumber_to_number(c_void_p(cf.CFDictionaryGetValue(gif_props, kCGImagePropertyGIFDelayTime)))

            cf.CFRelease(props)
            image = self._get_pyglet_ImageData_from_source_at_index(sourceRef, index)
            frames.append( AnimationFrame(image, duration) )

        cf.CFRelease(data)
        cf.CFRelease(sourceRef)

        return Animation(frames)


def get_decoders():
    return [ QuartzImageDecoder() ]

def get_encoders():
    return []