From c6509936d0f9a9f72d9c8b1dc64aaef745ecd6e9 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 23 Nov 2018 13:52:08 +0100 Subject: [PATCH] Restore special casing of grayscale images in PostScript backend. This divides the filesize by ~3 by not storing three identical channels (e.g. compare the size of ``` imshow(np.random.rand(255, 255), cmap="gray") gca().set_axis_off() savefig("test.ps") ``` before and after the patch). --- lib/matplotlib/backends/backend_ps.py | 43 ++++++++++----------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/lib/matplotlib/backends/backend_ps.py b/lib/matplotlib/backends/backend_ps.py index c58ff927a604..14f4c0676c1d 100644 --- a/lib/matplotlib/backends/backend_ps.py +++ b/lib/matplotlib/backends/backend_ps.py @@ -2,7 +2,6 @@ A PostScript backend, which can produce both PostScript .ps and .eps. """ -import binascii import datetime import glob from io import StringIO, TextIOWrapper @@ -13,6 +12,7 @@ import shutil import subprocess from tempfile import TemporaryDirectory +import textwrap import time import numpy as np @@ -392,26 +392,8 @@ def _get_font_ttf(self, prop): font.set_size(size, 72.0) return font - def _rgb(self, rgba): - h, w = rgba.shape[:2] - rgb = rgba[::-1, :, :3] - return h, w, rgb.tostring() - - def _hex_lines(self, s, chars_per_line=128): - s = binascii.b2a_hex(s) - nhex = len(s) - lines = [] - for i in range(0, nhex, chars_per_line): - limit = min(i+chars_per_line, nhex) - lines.append(s[i:limit]) - return lines - def get_image_magnification(self): - """ - Get the factor by which to magnify images passed to draw_image. - Allows a backend to have images at a different resolution to other - artists. - """ + # docstring inherited return self.image_magnification def option_scale_image(self): @@ -422,17 +404,22 @@ def option_image_nocomposite(self): # docstring inherited return not rcParams['image.composite_image'] - def _get_image_h_w_bits_command(self, im): - h, w, bits = self._rgb(im) - imagecmd = "false 3 colorimage" - - return h, w, bits, imagecmd - def draw_image(self, gc, x, y, im, transform=None): # docstring inherited - h, w, bits, imagecmd = self._get_image_h_w_bits_command(im) - hexlines = b'\n'.join(self._hex_lines(bits)).decode('ascii') + h, w = im.shape[:2] + if ((im[..., 3] == 255).all() + and (im[..., 0] == im[..., 1]).all() + and (im[..., 0] == im[..., 2]).all()): + data = im[::-1, ..., 0] + imagecmd = "image" + else: + data = im[::-1, :, :3] + imagecmd = "false 3 colorimage" + + # data.tobytes().hex() has no spaces, so can be linewrapped by relying + # on textwrap.fill breaking long words. + hexlines = textwrap.fill(data.tobytes().hex(), 128) if transform is None: matrix = "1 0 0 1 0 0"