Почему ghostscript заменяет имена шрифтов на CairoFont?

Я использую ghostscript для оптимизации pdf-файлов (в основном по размеру), для чего он отлично справляется. Команда, которую я использую:

gs -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress \
   -dCompatibilityLevel=1.4 -sOutputFile=out.pdf in.pdf

Однако кажется, что это заменяет шрифты (или их подмножества) и не сохраняет их имена. Он заменяет его на CairoFont. Как я могу заставить ghostscript сохранить имена шрифтов?

Пример. Простой файл PDF (созданный с помощью Inkscape) с одним текстовым элементом (Nimbus Roman) в качестве входных данных (in.pdf):

введите здесь описание изображения

для которых pdffonts сообщает:

name                                 type              emb sub uni object ID
------------------------------------ ----------------- --- --- --- ---------
PMLNBT+NimbusRomanNo9L               Type 1            yes yes yes      5  0

Однако после запуска ghostscript над файлом pdffonts сообщает:

name                                 type              emb sub uni object ID
------------------------------------ ----------------- --- --- --- ---------
OEPSCM+CairoFont-0-0                 Type 1C           yes yes no       8  0

Итак, есть ли способ заставить ghostscript (или libcairo?) сохранить имя шрифта?

Входной файл загружен здесь.


person hitzg    schedule 16.03.2016    source источник


Ответы (1)


Ghostscript не меняет имя шрифта, но на самом деле в файле PDF есть несколько разных «имен» шрифтов.

В случае вашего файла объект PDF FontDescriptor имеет имя

<<
  /Type /FontDescriptor
  /FontName /PMLNBT+NimbusRomanNo9L
  /Flags 4
  /FontBBox [ -168 -281 1031 924 ]
  /ItalicAngle 0
  /Ascent 924
  /Descent -281
  /CapHeight 924
  /StemV 80
  /StemH 80
  /FontFile 7 0 R
>>

который ссылается на поток FontFile

  /FontFile 7 0 R

Этот поток содержит следующее:

%!PS-AdobeFont-1.0: NimbusRomNo9L-Regu 1.06
%%Title: NimbusRomNo9L-Regu
%Version: 1.06
%%CreationDate: Thu Aug  2 13:14:49 2007
%%Creator: frob
%Copyright: Copyright (URW)++,Copyright 1999 by (URW)++ Design &
%Copyright:  Development; Cyrillic glyphs added by Valek Filippov (C)
%Copyright:  2001-2005
% Generated by FontForge 20070723 (http://fontforge.sf.net/)
%%EndComments

FontDirectory/NimbusRomNo9L-Regu known{/NimbusRomNo9L-Regu findfont dup/UniqueID known pop false {dup
/UniqueID get 5020931 eq exch/FontType get 1 eq and}{pop false}ifelse
{save true}{false}ifelse}{false}ifelse
11 dict begin
/FontType 1 def
/FontMatrix [0.001 0 0 0.001 0 0 ]readonly def
/FontName /CairoFont-0-0 def

Видите ли вы FontName в фактическом шрифте? Называется CairoFont-0-0

Это возвращает меня к вопросу, который я часто повторяю здесь и в других местах; когда вы обрабатываете PDF-файл с помощью Ghostscript и создаете новый PDF-файл с помощью устройства pdfwrite, вы не «оптимизируете», «преобразовываете», «подмножаете» или в общем смысле манипулируете содержимым исходного PDF-файла.

Что делает Ghostscript, так это интерпретирует файл PDF, создавая набор операций маркировки opf (таких как «штрих», «заливка», «изображение» и т. д.), которые он отправляет на выбранное устройство Ghostscript. Большинство устройств Ghostscript затем будут использовать графическую библиотеку для рендеринга операций в растровое изображение, и когда страница будет завершена, растровое изображение будет записано в файл. Устройства «высокого уровня» или «векторные» вместо этого переупаковывают операции в другой язык описания страниц. В случае pdfwrite это PDF-файл.

На практике это означает, что созданный файл PDF не имеет ничего общего (кроме внешнего вида) с исходным файлом PDF. В частности описание объектов может отличаться.

Итак, в вашем случае устройство pdfwrite не знает, как назывался шрифт в исходном объекте PDF. Он действительно знает, что определенный шрифт назывался Cairo-0-0, поэтому именно так он называет шрифт при его генерировании.

Откровенно говоря, это еще один убогий пример из Каира, чтобы согласиться с определением каждой страницы как содержащей прозрачность, независимо от того, имеет она или нет, FontName в объекте Font предполагается совпадать с именем в поток шрифтов.

Совершенно очевидно, что FontName был изменен, учитывая остальную часть шаблона.

person KenS    schedule 16.03.2016
comment
Потрясающее объяснение. Спасибо за это! У меня было ощущение, что к проблеме причастен libcairo, но я просто не мог понять, что inkscape на самом деле использует его при создании PDF-файла. Видели бы вы простой способ исправить имя шрифта в потоке FontFile? Какие инструменты вы использовали для чтения паров из pdf-файла? - person hitzg; 16.03.2016
comment
Я использовал MuPDF (еще один продукт Artifex) для распаковки исходного PDF-файла, а Ghostscript записал свой собственный PDF-файл, используя -dCompressPages=false и -dCompressFonts=false. После этого это был просто редактор для чтения контента. Ваша единственная надежда на «исправление» - это поместить /FontName в поток шрифтов обратно в Nimbus.... но это не простая задача. Сначала вам нужно будет распаковать файл, затем отредактировать поток шрифтов, а затем (поскольку PDF — это двоичный формат с внешней ссылкой) использовать MuPDF для исправления отредактированного файла (очистка mutool). GS ничего не может сделать с файлом PDF в его нынешнем виде. - person KenS; 16.03.2016
comment
Хорошо, я вижу. Спасибо за ваши объяснения. Они были самыми полезными! - person hitzg; 16.03.2016