Skip to content

Commit 1759556

Browse files
committed
Move flatten_rgba to image.py and implment flatten_rgba for jpeg files.
1 parent 60d85f3 commit 1759556

File tree

2 files changed

+62
-46
lines changed

2 files changed

+62
-46
lines changed

lib/matplotlib/backends/backend_agg.py

Lines changed: 20 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from matplotlib.path import Path
4040
from matplotlib.transforms import Bbox, BboxBase
4141
from matplotlib import colors as mcolors
42+
from matplotlib import image as mimage
4243

4344
from matplotlib.backends._backend_agg import RendererAgg as _RendererAgg
4445
from matplotlib import _png
@@ -514,7 +515,7 @@ def print_raw(self, filename_or_obj, *args, **kwargs):
514515
if kwargs.get('flatten', False):
515516
w, h = int(renderer.width), int(renderer.height)
516517
img = np.array(memoryview(img)).reshape((w, h, 4))
517-
img = self.flatten_rgba(img)
518+
img = mimage.flatten_rgba(img)
518519

519520
try:
520521
fileobj.write(img)
@@ -524,34 +525,6 @@ def print_raw(self, filename_or_obj, *args, **kwargs):
524525
renderer.dpi = original_dpi
525526
print_rgba = print_raw
526527

527-
def flatten_rgba(self, src, bg=None):
528-
"""
529-
Flatten an RGBA image `src` with a background color `bg`.
530-
The resulting image will have an alpha channel, but no
531-
transparency. This is useful when interfacing with
532-
file formats that don't support transparency or only support
533-
boolean transparency.
534-
"""
535-
if bg is None:
536-
bg = mcolors.colorConverter.to_rgb(
537-
rcParams.get('savefig.facecolor', 'white'))
538-
bg = tuple([int(x * 255.0) for x in bg])
539-
540-
# Numpy images have dtype=uint8 which will overflow
541-
src = src.astype(dtype = np.uint16)
542-
543-
alpha = src[:,:,3]
544-
src_rgb = src[:,:,:3]
545-
w, h, _ = src.shape
546-
547-
result = np.empty((w, h, 4))
548-
result[:,:,0] = (255 - alpha)*bg[0] + alpha*src_rgb[:,:,0]
549-
result[:,:,1] = (255 - alpha)*bg[1] + alpha*src_rgb[:,:,1]
550-
result[:,:,2] = (255 - alpha)*bg[2] + alpha*src_rgb[:,:,2]
551-
result = (result/255).astype(np.uint8)
552-
result[:,:,3] = 255
553-
return result
554-
555528
def print_png(self, filename_or_obj, *args, **kwargs):
556529
FigureCanvasAgg.draw(self)
557530
renderer = self.get_renderer()
@@ -562,15 +535,18 @@ def print_png(self, filename_or_obj, *args, **kwargs):
562535
close = True
563536
else:
564537
close = False
538+
539+
# Flatten RGBA if used as intermediate fileformat for something
540+
# that doesn't support transparency (ie: Animations)
541+
img = renderer._renderer
542+
if kwargs.get('flatten', False):
543+
img = img.buffer_rgba()
544+
w, h = int(renderer.width), int(renderer.height)
545+
img = renderer._renderer.buffer_rgba()
546+
img = np.array(memoryview(img)).reshape((h, w, 4))
547+
img = mimage.flatten_rgba(img)
565548
try:
566-
if kwargs.get('flatten', False):
567-
w, h = int(renderer.width), int(renderer.height)
568-
img = renderer._renderer.buffer_rgba()
569-
img = np.array(memoryview(img)).reshape((h,w,4))
570-
img = self.flatten_rgba(img)
571-
_png.write_png(img, filename_or_obj, self.figure.dpi)
572-
else:
573-
_png.write_png(renderer._renderer, filename_or_obj, self.figure.dpi)
549+
_png.write_png(img, filename_or_obj, self.figure.dpi)
574550
finally:
575551
if close:
576552
filename_or_obj.close()
@@ -605,24 +581,22 @@ def print_jpg(self, filename_or_obj, *args, **kwargs):
605581
*progressive*: If present, indicates that this image
606582
should be stored as a progressive JPEG file.
607583
"""
608-
buf, size = self.print_to_buffer()
584+
buf, (w, h) = self.print_to_buffer()
585+
buf = np.array(memoryview(buf)).reshape((w, h, 4))
586+
609587
if kwargs.pop("dryrun", False):
610588
return
611589
# The image is "pasted" onto a white background image to safely
612590
# handle any transparency
613-
image = Image.frombuffer('RGBA', size, buf, 'raw', 'RGBA', 0, 1)
614-
color = mcolors.colorConverter.to_rgb(
615-
rcParams.get('savefig.facecolor', 'white'))
616-
color = tuple([int(x * 255.0) for x in color])
617-
background = Image.new('RGB', size, color)
618-
background.paste(image, image)
591+
buf = mimage.flatten_rgba(buf)
592+
img = Image.frombuffer('RGBA', (w, h), buf, 'raw', 'RGBA', 0, 1)
593+
619594
options = restrict_dict(kwargs, ['quality', 'optimize',
620595
'progressive'])
621-
622596
if 'quality' not in options:
623597
options['quality'] = rcParams['savefig.jpeg_quality']
624598

625-
return background.save(filename_or_obj, format='jpeg', **options)
599+
return img.save(filename_or_obj, format='jpeg', **options)
626600
print_jpeg = print_jpg
627601

628602
# add TIFF support

lib/matplotlib/image.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,3 +1502,45 @@ def thumbnail(infile, thumbfile, scale=0.1, interpolation='bilinear',
15021502
ax.imshow(im, aspect='auto', resample=True, interpolation=interpolation)
15031503
fig.savefig(thumbfile, dpi=dpi)
15041504
return fig
1505+
1506+
def flatten_rgba(src, bg=None):
1507+
"""
1508+
Flatten an RGBA image *src* with a background color *bg*.
1509+
The resulting image will have an alpha channel, but no transparency.
1510+
This can be useful when interfacing with file formats that don't support
1511+
transparency or only support boolean transparency.
1512+
1513+
Parameters
1514+
----------
1515+
src : MxNx4 Numpy array, dtype=uint8
1516+
Image source in RGBA to be flattened.
1517+
1518+
bg : Tuple(int,int,int), optional
1519+
Background color to merge *src* with. If no bg color is provided
1520+
the color from the rcParam 'savefig.facecolor' will be use.
1521+
1522+
Returns
1523+
-------
1524+
dest : MxNx4 Numpy array, dtype=uint8
1525+
"""
1526+
1527+
if bg is None:
1528+
bg = mcolors.colorConverter.to_rgb(
1529+
rcParams.get('savefig.facecolor', 'white'))
1530+
bg = tuple([int(x * 255.0) for x in bg])
1531+
1532+
# Numpy images have dtype=uint8 which will overflow
1533+
src = src.astype(np.uint16)
1534+
1535+
alpha = src[:,:,3]
1536+
src_rgb = src[:,:,:3]
1537+
w, h, _ = src.shape
1538+
1539+
dest = np.empty((w, h, 4))
1540+
dest[:,:,0] = (255 - alpha)*bg[0] + alpha*src_rgb[:,:,0]
1541+
dest[:,:,1] = (255 - alpha)*bg[1] + alpha*src_rgb[:,:,1]
1542+
dest[:,:,2] = (255 - alpha)*bg[2] + alpha*src_rgb[:,:,2]
1543+
dest = (dest/255).astype(np.uint8)
1544+
dest[:,:,3] = 255
1545+
1546+
return dest

0 commit comments

Comments
 (0)