8000 Fix alpha channels in PDF images · matplotlib/matplotlib@f2d59a4 · GitHub
[go: up one dir, main page]

Skip to content

Commit f2d59a4

Browse files
committed
Fix alpha channels in PDF images
The code was conflating the presence of an alpha channel with whether the image is grayscale or RGB. Fixes #4331
1 parent d58a2a5 commit f2d59a4

File tree

1 file changed

+34
-29
lines changed

1 file changed

+34
-29
lines changed

lib/matplotlib/backends/backend_pdf.py

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
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

Comments
 (0)
0