Esempio n. 1
0
def make_pdf_to_png_converter():
    """Return a function that converts a pdf file to a png file."""
    try:
        mpl._get_executable_info("pdftocairo")
    except mpl.ExecutableNotFoundError:
        pass
    else:
        return lambda pdffile, pngfile, dpi: subprocess.check_output(
            [
                "pdftocairo", "-singlefile", "-transp", "-png", "-r",
                "%d" % dpi, pdffile,
                os.path.splitext(pngfile)[0]
            ],
            stderr=subprocess.STDOUT)
    try:
        gs_info = mpl._get_executable_info("gs")
    except mpl.ExecutableNotFoundError:
        pass
    else:
        return lambda pdffile, pngfile, dpi: subprocess.check_output([
            gs_info.executable, '-dQUIET', '-dSAFER', '-dBATCH', '-dNOPAUSE',
            '-dNOPROMPT', '-dUseCIEColor', '-dTextAlphaBits=4',
            '-dGraphicsAlphaBits=4', '-dDOINTERPOLATE', '-sDEVICE=pngalpha',
            '-sOutputFile=%s' % pngfile,
            '-r%d' % dpi, pdffile
        ],
                                                                     stderr=
                                                                     subprocess
                                                                     .STDOUT)
    raise RuntimeError("No suitable pdf to png renderer found.")
Esempio n. 2
0
def xpdf_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False):
    """
    Use ghostscript's ps2pdf and xpdf's/poppler's pdftops to distill a file.
    This yields smaller files without illegal encapsulated postscript
    operators. This distiller is preferred, generating high-level postscript
    output that treats text as text.
    """
    mpl._get_executable_info("gs")  # Effectively checks for ps2pdf.
    mpl._get_executable_info("pdftops")

    pdffile = tmpfile + '.pdf'
    psfile = tmpfile + '.ps'

    # Pass options as `-foo#bar` instead of `-foo=bar` to keep Windows happy
    # (https://www.ghostscript.com/doc/9.22/Use.htm#MS_Windows).
    cbook._check_and_log_subprocess(
        ["ps2pdf",
         "-dAutoFilterColorImages#false",
         "-dAutoFilterGrayImages#false",
         "-sAutoRotatePages#None",
         "-sGrayImageFilter#FlateEncode",
         "-sColorImageFilter#FlateEncode",
         "-dEPSCrop" if eps else "-sPAPERSIZE#%s" % ptype,
         tmpfile, pdffile], _log)
    cbook._check_and_log_subprocess(
        ["pdftops", "-paper", "match", "-level2", pdffile, psfile], _log)

    os.remove(tmpfile)
    shutil.move(psfile, tmpfile)

    if eps:
        pstoeps(tmpfile)

    for fname in glob.glob(tmpfile+'.*'):
        os.remove(fname)
Esempio n. 3
0
def _update_converter():
    try:
        mpl._get_executable_info("gs")
    except FileNotFoundError:
        pass
    else:
        converter['pdf'] = converter['eps'] = _GSConverter()
    try:
        mpl._get_executable_info("inkscape")
    except FileNotFoundError:
        pass
    else:
        converter['svg'] = _SVGConverter()
Esempio n. 4
0
def _update_converter():
    try:
        mpl._get_executable_info("gs")
    except FileNotFoundError:
        pass
    else:
        converter['pdf'] = converter['eps'] = _GSConverter()
    try:
        mpl._get_executable_info("inkscape")
    except FileNotFoundError:
        pass
    else:
        converter['svg'] = _SVGConverter()
Esempio n. 5
0
def gs_distill(tmpfile, eps=False, ptype='letter', bbox=None, rotated=False):
    """
    Use ghostscript's pswrite or epswrite device to distill a file.
    This yields smaller files without illegal encapsulated postscript
    operators. The output is low-level, converting text to outlines.
    """

    if eps:
        paper_option = "-dEPSCrop"
    else:
        paper_option = "-sPAPERSIZE=%s" % ptype

    psfile = tmpfile + '.ps'
    dpi = mpl.rcParams['ps.distiller.res']

    cbook._check_and_log_subprocess(
        [mpl._get_executable_info("gs").executable,
         "-dBATCH", "-dNOPAUSE", "-r%d" % dpi, "-sDEVICE=ps2write",
         paper_option, "-sOutputFile=%s" % psfile, tmpfile],
        _log)

    os.remove(tmpfile)
    shutil.move(psfile, tmpfile)

    # While it is best if above steps preserve the original bounding
    # box, there seem to be cases when it is not. For those cases,
    # the original bbox can be restored during the pstoeps step.

    if eps:
        # For some versions of gs, above steps result in an ps file where the
        # original bbox is no more correct. Do not adjust bbox for now.
        pstoeps(tmpfile, bbox, rotated=rotated)
Esempio n. 6
0
def get_file_hash(path, block_size=2**20):
    md5 = hashlib.md5()
    with open(path, 'rb') as fd:
        while True:
            data = fd.read(block_size)
            if not data:
                break
            md5.update(data)

    if path.endswith('.pdf'):
        md5.update(str(mpl._get_executable_info("gs").version).encode('utf-8'))
    elif path.endswith('.svg'):
        md5.update(
            str(mpl._get_executable_info("inkscape").version).encode('utf-8'))

    return md5.hexdigest()
Esempio n. 7
0
    def __call__(self, orig, dest):
        if not self._proc:
            self._stdout = TemporaryFile()
            self._proc = subprocess.Popen(
                [
                    mpl._get_executable_info("gs").executable, "-dNOPAUSE",
                    "-sDEVICE=png16m"
                ],
                # As far as I can see, ghostscript never outputs to stderr.
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE)
            try:
                self._read_until(b"\nGS")
            except _ConverterError:
                raise OSError("Failed to start Ghostscript")

        def encode_and_escape(name):
            return (os.fsencode(name).replace(b"\\", b"\\\\").replace(
                b"(", br"\(").replace(b")", br"\)"))

        self._proc.stdin.write(b"<< /OutputFile (" + encode_and_escape(dest) +
                               b") >> setpagedevice (" +
                               encode_and_escape(orig) + b") run flush\n")
        self._proc.stdin.flush()
        # GS> if nothing left on the stack; GS<n> if n items left on the stack.
        err = self._read_until(b"GS")
        stack = self._read_until(b">")
        if stack or not os.path.exists(dest):
            stack_size = int(stack[1:]) if stack else 0
            self._proc.stdin.write(b"pop\n" * stack_size)
            # Using the systemencoding should at least get the filenames right.
            raise ImageComparisonFailure((err + b"GS" + stack + b">").decode(
                sys.getfilesystemencoding(), "replace"))
Esempio n. 8
0
def make_pdf_to_png_converter():
    """Returns a function that converts a pdf file to a png file."""
    if shutil.which("pdftocairo"):

        def cairo_convert(pdffile, pngfile, dpi):
            cmd = [
                "pdftocairo", "-singlefile", "-png", "-r",
                "%d" % dpi, pdffile,
                os.path.splitext(pngfile)[0]
            ]
            subprocess.check_output(cmd, stderr=subprocess.STDOUT)

        return cairo_convert
    try:
        gs_info = mpl._get_executable_info("gs")
    except FileNotFoundError:
        pass
    else:

        def gs_convert(pdffile, pngfile, dpi):
            cmd = [
                gs_info.executable, '-dQUIET', '-dSAFER', '-dBATCH',
                '-dNOPAUSE', '-dNOPROMPT', '-dUseCIEColor',
                '-dTextAlphaBits=4', '-dGraphicsAlphaBits=4',
                '-dDOINTERPOLATE', '-sDEVICE=png16m',
                '-sOutputFile=%s' % pngfile,
                '-r%d' % dpi, pdffile
            ]
            subprocess.check_output(cmd, stderr=subprocess.STDOUT)

        return gs_convert
    raise RuntimeError("No suitable pdf to png renderer found.")
Esempio n. 9
0
    def make_png(self, tex, fontsize, dpi):
        """
        Generate a png file containing latex's rendering of tex string.

        Return the file name.
        """
        basefile = self.get_basefile(tex, fontsize, dpi)
        pngfile = '%s.png' % basefile
        # see get_rgba for a discussion of the background
        if not os.path.exists(pngfile):
            dvifile = self.make_dvi(tex, fontsize)
            cmd = [
                "dvipng", "-bg", "Transparent", "-D",
                str(dpi), "-T", "tight", "-o", pngfile, dvifile
            ]
            # When testing, disable FreeType rendering for reproducibility; but
            # dvipng 1.16 has a bug (fixed in f3ff241) that breaks --freetype0
            # mode, so for it we keep FreeType enabled; the image will be
            # slightly off.
            bad_ver = parse_version("1.16")
            if (getattr(mpl, "_called_from_pytest", False)
                    and mpl._get_executable_info("dvipng").version != bad_ver):
                cmd.insert(1, "--freetype0")
            self._run_checked_subprocess(cmd, tex)
        return pngfile
Esempio n. 10
0
    def __call__(self, orig, dest):
        if not self._proc:
            self._proc = subprocess.Popen(
                [mpl._get_executable_info("gs").executable,
                 "-dNOPAUSE", "-sDEVICE=png16m"],
                # As far as I can see, ghostscript never outputs to stderr.
                stdin=subprocess.PIPE, stdout=subprocess.PIPE)
            try:
                self._read_until(b"\nGS")
            except _ConverterError:
                raise OSError("Failed to start Ghostscript")

        def encode_and_escape(name):
            return (os.fsencode(name)
                    .replace(b"\\", b"\\\\")
                    .replace(b"(", br"\(")
                    .replace(b")", br"\)"))

        self._proc.stdin.write(
            b"<< /OutputFile ("
            + encode_and_escape(dest)
            + b") >> setpagedevice ("
            + encode_and_escape(orig)
            + b") run flush\n")
        self._proc.stdin.flush()
        # GS> if nothing left on the stack; GS<n> if n items left on the stack.
        err = self._read_until(b"GS")
        stack = self._read_until(b">")
        if stack or not os.path.exists(dest):
            stack_size = int(stack[1:]) if stack else 0
            self._proc.stdin.write(b"pop\n" * stack_size)
            # Using the systemencoding should at least get the filenames right.
            raise ImageComparisonFailure(
                (err + b"GS" + stack + b">")
                .decode(sys.getfilesystemencoding(), "replace"))
Esempio n. 11
0
def get_file_hash(path, block_size=2 ** 20):
    md5 = hashlib.md5()
    with open(path, 'rb') as fd:
        while True:
            data = fd.read(block_size)
            if not data:
                break
            md5.update(data)

    if path.endswith('.pdf'):
        md5.update(str(mpl._get_executable_info("gs").version)
                   .encode('utf-8'))
    elif path.endswith('.svg'):
        md5.update(str(mpl._get_executable_info("inkscape").version)
                   .encode('utf-8'))

    return md5.hexdigest()
Esempio n. 12
0
def make_pdf_to_png_converter():
    """Returns a function that converts a pdf file to a png file."""
    if shutil.which("pdftocairo"):
        def cairo_convert(pdffile, pngfile, dpi):
            cmd = ["pdftocairo", "-singlefile", "-png", "-r", "%d" % dpi,
                   pdffile, os.path.splitext(pngfile)[0]]
            subprocess.check_output(cmd, stderr=subprocess.STDOUT)
        return cairo_convert
    try:
        gs_info = mpl._get_executable_info("gs")
    except FileNotFoundError:
        pass
    else:
        def gs_convert(pdffile, pngfile, dpi):
            cmd = [gs_info.executable,
                   '-dQUIET', '-dSAFER', '-dBATCH', '-dNOPAUSE', '-dNOPROMPT',
                   '-dUseCIEColor', '-dTextAlphaBits=4',
                   '-dGraphicsAlphaBits=4', '-dDOINTERPOLATE',
                   '-sDEVICE=png16m', '-sOutputFile=%s' % pngfile,
                   '-r%d' % dpi, pdffile]
            subprocess.check_output(cmd, stderr=subprocess.STDOUT)
        return gs_convert
    raise RuntimeError("No suitable pdf to png renderer found.")
Esempio n. 13
0
    assert common_texification(plain_text) == escaped_text


# test compiling a figure to pdf with xelatex
@needs_xelatex
@pytest.mark.backend('pgf')
@image_comparison(['pgf_xelatex.pdf'], style='default')
def test_xelatex():
    rc_xelatex = {'font.family': 'serif', 'pgf.rcfonts': False}
    mpl.rcParams.update(rc_xelatex)
    create_figure()


try:
    _old_gs_version = \
        mpl._get_executable_info('gs').version < parse_version('9.50')
except mpl.ExecutableNotFoundError:
    _old_gs_version = True


# test compiling a figure to pdf with pdflatex
@needs_pdflatex
@pytest.mark.skipif(not _has_tex_package('ucs'), reason='needs ucs.sty')
@pytest.mark.backend('pgf')
@image_comparison(['pgf_pdflatex.pdf'],
                  style='default',
                  tol=11.7 if _old_gs_version else 0)
def test_pdflatex():
    if os.environ.get('APPVEYOR'):
        pytest.xfail("pdflatex test does not work on appveyor due to missing "
                     "LaTeX fonts")
Esempio n. 14
0
    def __call__(self, orig, dest):
        old_inkscape = mpl._get_executable_info("inkscape").version < "1"
        terminator = b"\n>" if old_inkscape else b"> "
        if not hasattr(self, "_tmpdir"):
            self._tmpdir = TemporaryDirectory()
        if (not self._proc  # First run.
                or self._proc.poll() is not None):  # Inkscape terminated.
            env = {
                **os.environ,
                # If one passes e.g. a png file to Inkscape, it will try to
                # query the user for conversion options via a GUI (even with
                # `--without-gui`).  Unsetting `DISPLAY` prevents this (and
                # causes GTK to crash and Inkscape to terminate, but that'll
                # just be reported as a regular exception below).
                "DISPLAY":
                "",
                # Do not load any user options.
                "INKSCAPE_PROFILE_DIR":
                os.devnull,
            }
            # Old versions of Inkscape (e.g. 0.48.3.1) seem to sometimes
            # deadlock when stderr is redirected to a pipe, so we redirect it
            # to a temporary file instead.  This is not necessary anymore as of
            # Inkscape 0.92.1.
            stderr = TemporaryFile()
            self._proc = subprocess.Popen(
                ["inkscape", "--without-gui", "--shell"]
                if old_inkscape else ["inkscape", "--shell"],
                stdin=subprocess.PIPE,
                stdout=subprocess.PIPE,
                stderr=stderr,
                env=env,
                cwd=self._tmpdir.name)
            # Slight abuse, but makes shutdown handling easier.
            self._proc.stderr = stderr
            try:
                self._read_until(terminator)
            except _ConverterError as err:
                raise OSError("Failed to start Inkscape in interactive "
                              "mode") from err

        # Inkscape's shell mode does not support escaping metacharacters in the
        # filename ("\n", and ":;" for inkscape>=1).  Avoid any problems by
        # running from a temporary directory and using fixed filenames.
        inkscape_orig = Path(self._tmpdir.name, os.fsdecode(b"f.svg"))
        inkscape_dest = Path(self._tmpdir.name, os.fsdecode(b"f.png"))
        try:
            inkscape_orig.symlink_to(Path(orig).resolve())
        except OSError:
            shutil.copyfile(orig, inkscape_orig)
        self._proc.stdin.write(
            b"f.svg --export-png=f.png\n" if old_inkscape else
            b"file-open:f.svg;export-filename:f.png;export-do;file-close\n")
        self._proc.stdin.flush()
        try:
            self._read_until(terminator)
        except _ConverterError as err:
            # Inkscape's output is not localized but gtk's is, so the output
            # stream probably has a mixed encoding.  Using the filesystem
            # encoding should at least get the filenames right...
            self._proc.stderr.seek(0)
            raise ImageComparisonFailure(self._proc.stderr.read().decode(
                sys.getfilesystemencoding(), "replace")) from err
        os.remove(inkscape_orig)
        shutil.move(inkscape_dest, dest)
Esempio n. 15
0
    assert common_texification(plain_text) == escaped_text


# test compiling a figure to pdf with xelatex
@needs_xelatex
@pytest.mark.backend('pgf')
@image_comparison(['pgf_xelatex.pdf'], style='default')
def test_xelatex():
    rc_xelatex = {'font.family': 'serif',
                  'pgf.rcfonts': False}
    mpl.rcParams.update(rc_xelatex)
    create_figure()


try:
    _old_gs_version = mpl._get_executable_info('gs').version < '9.50'
except mpl.ExecutableNotFoundError:
    _old_gs_version = True


# test compiling a figure to pdf with pdflatex
@needs_pdflatex
@pytest.mark.skipif(not _has_tex_package('ucs'), reason='needs ucs.sty')
@pytest.mark.backend('pgf')
@image_comparison(['pgf_pdflatex.pdf'], style='default',
                  tol=11.7 if _old_gs_version else 0)
def test_pdflatex():
    if os.environ.get('APPVEYOR'):
        pytest.xfail("pdflatex test does not work on appveyor due to missing "
                     "LaTeX fonts")