Как определить высоту строки в PostScript? - PullRequest
12 голосов
/ 01 сентября 2010

Мне нужно определить высоту строки (в заданном масштабе и шрифте) в постскриптуме.

/Helvetic-Oblique findfont
10 scalefont
setfont
10 10 1 0 360 arc fill
10 10 moveto (test) dup stringwidth pop 2 div neg 0 rmoveto show

напечатает тест по центру по горизонтали (но еще не по вертикали) в точке (10,10). (чтобы увидеть это, я также показываю маленький кружок на 10,10). Мне также нужно определить высоту строки, чтобы центрировать текст по вертикали, но я не могу найти для нее функцию.

Ответы [ 4 ]

9 голосов
/ 07 сентября 2010

Вы знакомы с кодом PostScript, который вы используете? Или это просто слепо скопировано и вставлено откуда-то? Если вы хотите понять это, вам следует поискать в «Справочнике по языку PostScript», «Красной книге» или «PLRM». Эти ресурсы доступны в формате PDF от Adobe.

Ваш фрагмент PostScript использует следующие шаги:

  1. (test) помещает строку «test» на вершину стека.
  2. dup дублирует самый верхний элемент в стеке. (Теперь у вас будет строка в стеке дважды.)
  3. stringwidth. После выполнения этого оператора будет использована самая верхняя «тестовая» строка, и вместо этого в стек будут добавлены два значения: высота строки (самая верхняя) и ширина строки (вторая сверху). [ Обновление: На самом деле, "высота строки" не совсем корректна - это скорее вертикальное смещение текущей точки после окончания рисования строки ... ]
  4. Далее вы используете pop. Это просто удаляет самое верхнее значение в стеке. Теперь только ширина строки остается на вершине стека.
  5. 2 div делит это значение на 2 и оставляет результат (половину ширины строки).
  6. neg отменяет самое верхнее значение в стеке. Теперь это отрицательное значение является самым верхним в стеке.
  7. 0 помещает значение «0» поверх стека.
  8. rmoveto затем использует два самых верхних значения в стеке и перемещает текущую точку на это расстояние (половину ширины строки) влево.
  9. show использует первую «тестовую» строку, которая все время оставалась на дне стека, и «показывает» ее.

Так что бы сработать, чтобы учесть высоту строки? Попробуйте в качестве последней строки:

200 700 moveto (test) dup true charpath pathbbox 3 -1 roll sub 2 div neg 3 1 roll sub 2 div exch 200 700 moveto rmoveto show"

Чтобы понять мои изменения, посмотрите значение операторов charpath, div, exch, pathbbox, roll и sub в Красной книге.

Эта команда использует Ghostscript для создания PDF-файла в Windows из кода (проще просматривать и проверять результаты):

 gswin32c.exe ^
      -o my.pdf ^
      -sDEVICE=pdfwrite ^
      -c "/Helvetic-Oblique findfont 10 scalefont setfont 200 700 1 0 360 arc fill 0 0 moveto (test test) dup true charpath pathbbox 3 -1 roll sub 2 div neg 3 1 roll sub 2 div exch 200 700 moveto rmoveto show"

В Linux использовать:

 gs \
      -o my.pdf \
      -sDEVICE=pdfwrite \
      -c "/Helvetic-Oblique findfont 10 scalefont setfont 200 700 1 0 360 arc fill 0 0 moveto (test test) dup true charpath pathbbox 3 -1 roll sub 2 div neg 3 1 roll sub 2 div exch 200 700 moveto rmoveto show"

Лучше читаемые формы:

  gswin32c ^
     -o my.pdf ^
     -sDEVICE=pdfwrite ^
     -c "/Helvetic-Oblique findfont 10 scalefont setfont" ^
     -c "200 700 1 0 360 arc fill 0 0 moveto (test test) dup" ^
     -c "true charpath pathbbox 3 -1 roll sub 2 div neg 3 1 roll" ^
     -c "sub 2 div exch 200 700 moveto rmoveto show"

и

  gs \
     -o my.pdf \
     -sDEVICE=pdfwrite \
     -c "/Helvetic-Oblique findfont 10 scalefont setfont" \
     -c "200 700 1 0 360 arc fill 0 0 moveto (test test) dup" \
     -c "true charpath pathbbox 3 -1 roll sub 2 div neg 3 1 roll" \
     -c "sub 2 div exch 200 700 moveto rmoveto show"
7 голосов
/ 19 августа 2011

Просто добавив к pipitas ответ:

/textheight { 
    gsave                                  % save graphic context
    {                            
        100 100 moveto                     % move to some point 
        (HÍpg) true charpath pathbbox      % gets text path bounding box (LLx LLy URx URy)
        exch pop 3 -1 roll pop             % keeps LLy and URy
        exch sub                           % URy - LLy
    }
    stopped                                % did the last block fail?
    {
        pop pop                            % get rid of "stopped" junk
        currentfont /FontMatrix get 3 get  % gets alternative text height
    }
    if
    grestore                               % restore graphic context
} bind def

/jumpTextLine { 
    textheight 1.25 mul                    % gets textheight and adds 1/4
    0 exch neg rmoveto                     % move down only in Y axis
} bind def

Метод ожидает, что какой-то шрифт уже установлен. Работает над выбранным шрифтом (setfont) и его размером (scalefont).

Я использую (HÍpg), чтобы получить максимально возможную ограничивающую рамку, используя выделенные заглавные буквы и символы «под строкой». Результат достаточно хороший.

Альтернативный подход основан на ответе dreamlax - некоторые шрифты не поддерживают оператор charpath. (См. Как получить метрику высоты строки в PostScript? )

Сохранение и восстановление графического контекста сохраняет текущую точку на месте, поэтому она не влияет на «поток» вашего документа.

Надеюсь, я помог.

4 голосов
/ 15 сентября 2011

Вот краткий ответ, дополняющий подробное объяснение Пипитаса.

Эта процедура позиционирует и показывает строку с центром в указанной точке.

/ceshow { % (string) fontsize fontname x y
    gsave
        moveto findfont exch scalefont setfont % s
        gsave
            dup false charpath flattenpath pathbbox % s x0 y0 x1 y1
        grestore
        3 -1 roll sub % s x0 x1 dy
        3 1 roll sub % s dy -dx
        2 div exch % s -dx/2 dy
        -2 div % s -dx/2 -dy/2
        rmoveto show
    grestore
} bind def
1 голос
/ 30 мая 2016

У меня были ужасные результаты при использовании описанных выше процедур со шрифтом дингбата, потом я понял, что они предполагают, что текст действительно начинается в текущей точке, что в некоторых случаях является крайне неточным.

Мое решение также опирается на pathbbox для вычисления ширины и высоты, но затем оно также использует X0 и Y0, чтобы в первую очередь добраться до начала координат.

%-- to make things nicer
/hmoveto { 0 rmoveto } def
/vmoveto { 0 exch rmoveto } def
%-- cshow means something else...
/ccshow {
    dup %-- charpath consumes the string
    gsave
    newpath %-- else there's a strange line somewhere
    0 0 moveto
    true charpath flattenpath pathbbox
    grestore
    2 index sub -2 div vmoveto
    2 index sub -2 div hmoveto
    neg vmoveto
    neg hmoveto
    show
} def
...