9292
9393# TODOs:
9494#
95- # * the alpha channel of images
9695# * image compression could be improved (PDF supports png-like compression)
9796# * encoding of fonts, including mathtext fonts and unicode support
9897# * TTF support has lots of small TODOs, e.g., how do you know if a font
@@ -1262,18 +1261,19 @@ def imageObject(self, image):
12621261 self .images [image ] = (name , ob )
12631262 return name
12641263
1265- # These two from backend_ps.py
1266- # TODO: alpha (SMask, p. 518 of pdf spec)
1267-
12681264 def _rgb (self , im ):
12691265 h , w , s = im .as_rgba_str ()
12701266
12711267 rgba = np .fromstring (s , np .uint8 )
12721268 rgba .shape = (h , w , 4 )
12731269 rgba = rgba [::- 1 ]
1274- rgb = rgba [:, :, :3 ]
1275- a = rgba [:, :, 3 :]
1276- return h , w , rgb .tostring (), a .tostring ()
1270+ rgb = rgba [:, :, :3 ].tostring ()
1271+ a = rgba [:, :, 3 ]
1272+ if np .all (a == 255 ):
1273+ alpha = None
1274+ else :
1275+ alpha = a .tostring ()
1276+ return h , w , rgb , alpha
12771277
12781278 def _gray (self , im , rc = 0.3 , gc = 0.59 , bc = 0.11 ):
12791279 rgbat = im .as_rgba_str ()
@@ -1284,24 +1284,30 @@ def _gray(self, im, rc=0.3, gc=0.59, bc=0.11):
12841284 r = rgba_f [:, :, 0 ]
12851285 g = rgba_f [:, :, 1 ]
12861286 b = rgba_f [:, :, 2 ]
1287- gray = (r * rc + g * gc + b * bc ).astype (np .uint8 )
1288- return rgbat [0 ], rgbat [1 ], gray .tostring ()
1287+ a = rgba [:, :, 3 ]
1288+ if np .all (a == 255 ):
1289+ alpha = None
1290+ else :
1291+ alpha = a .tostring ()
1292+ gray = (r * rc + g * gc + b * bc ).astype (np .uint8 ).tostring ()
1293+ return rgbat [0 ], rgbat [1 ], gray , alpha
12891294
12901295 def writeImages (self ):
12911296 for img , pair in six .iteritems (self .images ):
12921297 if img .is_grayscale :
1293- height , width , data = self ._gray (img )
1294- self .beginStream (
1295- pair [1 ].id ,
1296- self .reserveObject ('length of image stream' ),
1297- {'Type' : Name ('XObject' ), 'Subtype' : Name ('Image' ),
1298- 'Width' : width , 'Height' : height ,
1299- 'ColorSpace' : Name ('DeviceGray' ), 'BitsPerComponent' : 8 })
1300- # TODO: predictors (i.e., output png)
1301- self .currentstream .write (data )
1302- self .endStream ()
1298+ height , width , data , adata = self ._gray (img )
13031299 else :
13041300 height , width , data , adata = self ._rgb (img )
1301+
1302+ colorspace = 'DeviceGray' if img .is_grayscale else 'DeviceRGB'
1303+ obj = {'Type' : Name ('XObject' ),
1304+ 'Subtype' : Name ('Image' ),
1305+ 'Width' : width ,
1306+ 'Height' : height ,
1307+ 'ColorSpace' : Name (colorspace ),
1308+ 'BitsPerComponent' : 8 }
1309+
1310+ if adata is not None :
13051311 smaskObject = self .reserveObject ("smask" )
13061312 self .beginStream (
13071313 smaskObject .id ,
@@ -1312,17 +1318,16 @@ def writeImages(self):
13121318 # TODO: predictors (i.e., output png)
13131319 self .currentstream .write (adata )
13141320 self .endStream ()
1321+ obj ['SMask' ] = smaskObject
13151322
1316- self .beginStream (
1317- pair [1 ].id ,
1318- self .reserveObject ('length of image stream' ),
1319- {'Type' : Name ('XObject' ), 'Subtype' : Name ('Image' ),
1320- 'Width' : width , 'Height' : height ,
1321- 'ColorSpace' : Name ('DeviceRGB' ), 'BitsPerComponent' : 8 ,
1322- 'SMask' : smaskObject })
1323- # TODO: predictors (i.e., output png)
1324- self .currentstream .write (data )
1325- self .endStream ()
1323+ self .beginStream (
1324+ pair [1 ].id ,
1325+ self .reserveObject ('length of image stream' ),
1326+ obj
1327+ )
1328+ # TODO: predictors (i.e., output png)
1329+ self .currentstream .write (data )
1330+ self .endStream ()
13261331
13271332 def markerObject (self , path , trans , fillp , strokep , lw , joinstyle ,
13281333 capstyle ):
0 commit comments