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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
"""Utility functions for cairo-specific operations
USE_BASE_ARRAY -- if False (default), uses numpy arrays,
currently this is the only version that works on 32-bit
machines.
"""
import pygame, struct, logging
big_endian = struct.pack( '=i', 1 ) == struct.pack( '>i', 1 )
log = logging.getLogger( 'olpcgames._cairoimage' )
##log.setLevel( logging.DEBUG )
USE_BASE_ARRAY = False
def newContext( width, height ):
"""Create a new render-to-image context
width, height -- pixel dimensions to be rendered
Produces an ARGB format Cairo ImageSurface for
rendering your data into using rsvg, Cairo or Pango.
returns (ImageSurface, CairoContext) for rendering
"""
import cairo
csrf = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
context = cairo.Context (csrf)
#log.info( 'Format (expect: %s): %s', cairo.FORMAT_ARGB32, csrf.get_format())
return csrf, context
def mangle_color(color):
"""Mange a colour depending on endian-ness, and swap-necessity
Converts a 3 or 4 int (or float) value in the range 0-255 into a
4-float value in the range 0.0-1.0
"""
r,g,b = color[:3]
if len(color) > 3:
a = color[3]
else:
a = 255.0
return map(_fixColorBase, (r,g,b,a) )
def _fixColorBase( v ):
"""Return a properly clamped colour in floating-point space"""
return max((0,min((v,255.0))))/255.0
def asImage( csrf ):
"""Get the pixels in csrf as a Pygame image
Note that Pygame 1.7.1 on (Gentoo Linux) AMD64 is incorrectly
calculating the required size ARGB images, so this code will *not* work
on that platform with that version of the library. Pygame-ctypes
does work correctly there.
Note also that Pygame 1.7.1 is showing a strange colour rotation
bug on 32-bit platforms, such that ARGB mode cannot be used for
images there. Instead we have to do an expensive bit-shift operation
to produce an RGBA image from the ARGB native Cairo format.
Will raise a ValueError if passed a Null image (i.e. dimension of 0)
returns Pygame.Surface (image) with convert_alpha() called for it.
"""
# Create and return a new Pygame Image derived from the Cairo Surface
format = 'ARGB'
if hasattr(csrf,'get_data'):
# more recent API, native-format, but have to (potentially) convert the format...
log.debug( 'Native-mode api (get_data)' )
data = csrf.get_data()
if not big_endian:
# we use array here because it's considerably lighter-weight
# to import than the numpy module
log.debug( 'Not big-endian, byte-swapping array' )
if USE_BASE_ARRAY:
import array
a = array.array( 'I' )
a.fromstring( data )
a.byteswap()
data = a.tostring()
else:
import numpy
n = numpy.fromstring( data, dtype='I' )
n = ((n & 0xff000000) >> 24 ) | ((n & 0x00ffffff) << 8 )
n = n.byteswap()
data = n.tostring()
format = 'RGBA'
else:
log.debug( 'Big-endian, array unchanged' )
data = str(data) # there's one copy
else:
# older api, not native, but we know what it is...
log.debug( 'Non-native mode api, explicitly RGBA' )
data = csrf.get_data_as_rgba()
data = str(data) # there's one copy
format = 'RGBA'
width, height = csrf.get_width(),csrf.get_height()
try:
log.info( 'Format = %s', format )
return pygame.image.fromstring(
data,
(width,height),
format
) # there's the next
except ValueError, err:
err.args += (len(data), (width,height), width*height*4,format )
raise
if __name__ == "__main__":
import unittest
logging.basicConfig()
class Tests( unittest.TestCase ):
def test_colours( self ):
"""Test that colours are correctly translated
If we draw a given colour in cairo, we want the same
colour to show up in Pygame, let's test that...
"""
for sourceColour in [
(255,0,0, 255),
(0,255,0, 255),
(0,0,255, 255),
(255,255,0, 255),
(0,255,255,255),
(255,0,255,255),
]:
csrf,cctx = newContext( 1,1 )
background = mangle_color( sourceColour )
cctx.set_source_rgba(*background)
cctx.paint()
img = asImage( csrf )
colour = img.get_at( (0,0))
assert colour == sourceColour, (sourceColour,mangle_color(sourceColour),colour)
unittest.main()
|