Уменьшение размера файлов PDF, созданных с помощью matplotlib, путем изменения встраивания шрифта.

Я использую matplotlib для создания PDF-файлов. Тем не менее, даже самые простые цифры дают относительно большие файлы, MWE ниже создает файл размером почти 1 МБ. Мне стало известно, что большой размер файла связан с тем, что matplotlib полностью встраивает все используемые шрифты. Поскольку я собираюсь создать довольно много графиков и хотел бы уменьшить размеры файлов, мне интересно:

Основной вопрос:

Есть ли способ заставить matplotlib встраивать шрифт подмножества вместо полных шрифтов? Я также был бы в порядке, если бы вообще не включал шрифты.

Вещи, рассмотренные на данный момент:

  • Редактор векторной графики можно легко использовать для экспорта PDF-файла, включая подмножества шрифтов (а также вообще не включая шрифты), но необходимость выполнять этот шаг для каждого файла (редакции) кажется излишне утомительной.
  • Точно так же я читал о постобработке PDF-файлов (например, с использованием Ghostscript), хотя усилия кажутся сопоставимыми.
  • Я попытался установить «pdf.fonttype» = 3, что действительно создает файлы значительно меньшего размера. Тем не менее, я хотел бы, чтобы текст можно было изменять в редакторах векторной графики, что, похоже, не работает в этом случае (например, знаки минус не будут сохранены как текст).

Поскольку легко, хотя и трудоемко, создавать файлы со встроенными подмножествами с помощью внешнего программного обеспечения, можно ли как-то добиться этого непосредственно в matplotlib? Любая помощь будет принята с благодарностью.

MWE

import matplotlib.pyplot as plt #Setup
import matplotlib as mpl
mpl.rcParams['pdf.fonttype'] = 42
mpl.rcParams['mathtext.fontset'] = 'dejavuserif'
mpl.rc('font',family='Arial',size=12)

fig,ax=plt.subplots(figsize=(2,2)) #Create a figure containing some text
ax.semilogy(1,1,'s',label='Text\n$M_\mathrm{ath}$')
ax.legend()
fig.tight_layout()
fig.savefig('test.pdf')

Среда: matplotlib 3.1.1


person Xenon    schedule 05.02.2020    source источник


Ответы (2)


бэкэнд PGF помогает значительно уменьшить размер файла PDF. Просто добавьте mpl.use('pgf') в свой код. В моей среде эта поправка приводит к следующему:

  • Размер файла уменьшается с 817К до 21К (в 40 раз меньше!).
  • Время выполнения увеличивается с 1 с до 3 с.

Однако для реальных цифр время выполнения часто уменьшается вместе с размером файла.

Уменьшение размера PDF объясняется внедрением подмножеств шрифтов.

$ pdffonts pdf_backend.pdf
name                         type              emb sub uni prob object ID
---------------------------- ----------------- --- --- --- ---- ---------
ArialMT                      CID TrueType      yes no  yes          14  0
DejaVuSerif-Italic           CID TrueType      yes no  yes          23  0
DejaVuSerif                  CID TrueType      yes no  yes          32  0
$ pdffonts pgf_backend.pdf
name                         type              emb sub uni prob object ID
---------------------------- ----------------- --- --- --- ---- ---------
KECVVY+ArialMT               CID TrueType      yes yes yes           7  0
EFAAMX+CMR12                 Type 1C           yes yes yes           8  0
EHYQVR+CMSY8                 Type 1C           yes yes yes           9  0
UVNOSL+CMR8                  Type 1C           yes yes yes          10  0
FDPQQI+CMMI12                Type 1C           yes yes yes          11  0
DGIYWD+DejaVuSerif           CID TrueType      yes yes yes          13  0

Другой вариант — создать файл EPS (используя серверную часть PostScript) и преобразовать его в формат PDF, например, с помощью epstopdf< /a> (используя интерпретатор GhostScript). Таким образом, файл PDF уменьшается до 9K. Однако стоит отметить, что бэкэнд PS не поддерживает прозрачность.

person olegrog    schedule 18.12.2020
comment
Это действительно адаптирует встраивание шрифта, как я и просил. Однако математические строки (метки экспоненциальной галочки и математическая метка в приведенном выше MWE), похоже, сохранены другим шрифтом. Есть идеи по этому поводу? (Наличие разных шрифтов для меток делений линейной и экспоненциальной осей на одном и том же рисунке неудовлетворительно.) - person Xenon; 14.01.2021
comment
Я предлагаю использовать LaTeX для всех математических строк. Это можно сделать, добавив mpl.rc('text',usetex=True) в код. - person olegrog; 17.01.2021

Оставлю это здесь на случай, если кто-то еще ищет что-то подобное: в конце концов, я решил выбрать Ghostscript. Из-за дополнительного шага это не совсем то, что я искал, но, по крайней мере, его можно автоматизировать:

import subprocess
def gs_opt(filename):
    filenameTmp = filename.split('.')[-2]+'_tmp.pdf'
    gs = ['gswin64',
          '-sDEVICE=pdfwrite',
          '-dEmbedAllFonts=false',
          '-dSubsetFonts=true',             # Create font subsets (default)
          '-dPDFSETTINGS=/prepress',        # Image resolution
          '-dDetectDuplicateImages=true',   # Embeds images used multiple times only once
          '-dCompressFonts=true',           # Compress fonts in the output (default)
          '-dNOPAUSE',                      # No pause after each image
          '-dQUIET',                        # Suppress output
          '-dBATCH',                        # Automatically exit
          '-sOutputFile='+filenameTmp,      # Save to temporary output
          filename]                         # Input file

    subprocess.run(gs)                                      # Create temporary file
    subprocess.run(['del', filename],shell=True)            # Delete input file
    subprocess.run(['ren',filenameTmp,filename],shell=True) # Rename temporary to input file

А потом звоню

filename = 'test.pdf'
plt.savefig(filename)
gs_opt(filename)

Это сохранит фигуру как test.pdf, используйте Ghostscript для создания временного оптимизированного файла test_tmp.pdf, удалите исходный файл и переименуйте оптимизированный файл в test.pdf.

По сравнению с экспортом файла с помощью векторного графического редактора итоговый PDF-файл, созданный Ghostscript, все еще в несколько раз больше (обычно в 4-5 раз). Однако он уменьшает размер файла до значения от 1/5 до 1/10 исходного файла. Это что-то.

person Xenon    schedule 10.02.2020