Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.postscript > #3250 > unrolled thread

Interrogating a font

Started byluser droog <luser.droog@gmail.com>
First post2018-03-27 15:57 -0700
Last post2018-06-18 23:13 -0700
Articles 4 — 3 participants

Back to article view | Back to comp.lang.postscript


Contents

  Interrogating a font luser droog <luser.droog@gmail.com> - 2018-03-27 15:57 -0700
    Re: Interrogating a font Mark Carroll <mtbc@bcs.org> - 2018-03-28 07:32 +0100
    Re: Interrogating a font deedubman@gmail.com - 2018-06-18 14:22 -0700
      Re: Interrogating a font luser droog <luser.droog@gmail.com> - 2018-06-18 23:13 -0700

#3250 — Interrogating a font

Fromluser droog <luser.droog@gmail.com>
Date2018-03-27 15:57 -0700
SubjectInterrogating a font
Message-ID<c66ccb1f-ee64-48c2-9d80-0c018c89b137@googlegroups.com>
Since I cannot predict what pieces may be inaccessible
in any given font dictionary I have tried to achieve
my needs with ... programming. tada! So, the following
incomplete program analyzes the paths produced in
a few key glyphs (CHj) for ascender, descender, cap-height,
italic-angle, and stem-v.

The implementation for stem-v seems to function correctly,
but I have not implemented the distance-between-segments
function, so the result is always 42. I'll fix that later.


I wonder if anyone has any advice on where to find the
information I need for the PDF font descriptor's /Flags
member? How do I determine if a font "is italic", reliably?
Scan the characters of 'FontName tempstring cvs'?

Anyway, here's my workaround for access restrictions 
in the font dictionaries preventing a more direct approach.


$ cat fontdata.ps

% main is called at eof
/main {
    test-palatino
} def


/test-palatino {
    /Palatino-Roman findfont
    %dup length dict copy dup /FontMatrix matrix put readonly
    1000 scalefont
    setfont
%    generate-font-extras pstack()=
    generate-font-descriptor ===
} def


/generate-font-extras {
    /FirstChar 32
    /LastChar 127
    /Widths [
        32 1 127 {
            1 string dup 0 4 -1 roll put stringwidth pop
        } for
    ]
} def



/generate-font-descriptor {
    <<
        /Type     /FontDescriptor
        /FontName currentfont /FontName get
        /FontBBox currentfont /FontBBox get dup length array copy

      predicates begin
        /Flags  is-fixed-pitch 0 bitshift
                is-serif       1 bitshift and
                is-symbolic    2 bitshift and
                is-script      3 bitshift and
                is-nonsymbolic 5 bitshift and
                is-italic      6 bitshift and
                is-allcap     16 bitshift and
                is-smallcap   17 bitshift and
                is-forcebold  18 bitshift and
      end

      font-analysis begin

      % Private:BlueValues?
        /Ascent ascender
        /CapHeight cap-height
        /Descent descender
             %/XHeight (optional)

      %  /StemV currentfont /Private get /StdVW get   dup type ==   cvx exec
        /StemV stem-v

        /ItalicAngle italic-angle
             %/MissingWidth  (optional)
             %/CharSet (/string/of/glyph/names)  (optional)
      end
    >>
} def


/font-analysis <<

    /ascender {
        gsave
            0 0 moveto
            (C) false charpath flattenpath pathbbox 4 array astore
            3 get
        grestore
    }

    /cap-height {
        gsave
            0 0 moveto
            (H) false charpath flattenpath pathbbox 4 array astore
            3 get
        grestore
    }

    /descender {
        gsave
            0 0 moveto
            (j) false charpath flattenpath pathbbox 4 array astore
            1 get
        grestore
    }

    /italic-angle {
        gsave
            0 0 moveto
            (H) false charpath flattenpath
            get-line-segments
            discard-horizontal-segments
            longest-segment
            angle-of-segment
        grestore
    }

    /stem-v {
        gsave
            0 0 moveto
            (H) false charpath flattenpath
            get-line-segments
            discard-horizontal-segments
            dup longest-segment  dup 3 1 roll
            closest-parallel-segment
            distance-between-segments
        grestore
    }

    /get-line-segments{
        /ca 2 array def
        /cp ca cvx def
        /sa 2 array def
        /sp sa cvx def
        [
            {2 copy sa astore pop ca astore pop
             [ cp}
            {2 copy ca astore pop
             ] [ cp}
            {}
            {sp ]}
            pathforall
            ] pop
        ]  % yield array of [x0 y0 x1 y1] arrays
    }

    /discard-horizontal-segments {
        {
            dup angle-of-segment  dup 45 gt  exch 135 lt  and  not {
                pop
            } if
        } map
    }

    /longest-segment {
        dup { length-of-segment } map
        dup { max } reduce
        find-index pop get
    }

    /closest-parallel-segment {
        exch discard-single-from-list
        discard-non-parallel-segments
        dup { counttomark 2 add index distance-between-segments } map
        dup { min } reduce
        find-index pop get exch pop
    }

    /discard-single-from-list {
        { dup counttomark 1 add index eq { pop } if } map
    }

    /distance-between-segments {
        pop pop 42
    }

    /discard-non-parallel-segments {
        1 index angle-of-segment exch
        { dup angle-of-segment counttomark 1 add index angles-are-close not {
              pop
          } if } map
        exch pop
    }

    /angles-are-close {
        sq exch sq sub  5  lt
    }

    /angle-of-segment {
        dup dy exch dx
        atan
    }
    
    /length-of-segment {
        dup dx sq  exch dy sq  add  sqrt
    }
    
    /dx {
        dup 2 get exch 0 get sub
    }
    
    /dy {
        dup 3 get exch 1 get sub
    }
    
    /sq {
        dup mul
    }
    
>> def

/find-index {
    exch
    {
        0 1 2 index length 1 sub {
            2 copy get
            3 index eq {
                stop
            }{
                pop
            } ifelse
        } for
    } stopped {
        exch pop exch pop  true
    }{
        pop pop  false
    } ifelse
} def

/map {
    [ 3 1 roll forall ]
} def

/reduce {
    1 index 0 get 3 1 roll
    exch 1 1 index length 1 sub getinterval exch
    forall
} def

/max {
    2 copy lt { exch } if pop
} def

/min {
    2 copy gt { exch } if pop
} def

/predicates <<
    /is-fixed-pitch { 0
    }
    /is-serif { 0
    }
    /is-symbolic { 0
    }
    /is-script { 0
    }
    /is-nonsymbolic { 0
    }
    /is-italic { 0
    }
    /is-allcap { 0
    }
    /is-smallcap { 0
    }
    /is-forcebold { 0
    }
>> def


main

[toc] | [next] | [standalone]


#3251

FromMark Carroll <mtbc@bcs.org>
Date2018-03-28 07:32 +0100
Message-ID<87a7us6783.fsf@ixod.org>
In reply to#3250
On 27 Mar 2018, luser droog wrote:

> Since I cannot predict what pieces may be inaccessible
> in any given font dictionary I have tried to achieve
> my needs with ... programming. tada! So, the following
> incomplete program analyzes the paths produced in
> a few key glyphs (CHj) for ascender, descender, cap-height,
> italic-angle, and stem-v.

I had to do a similar kind of thing when I wanted to nestle letters
right up against each other. Glad to see it's working for you too.

-- Mark

[toc] | [prev] | [next] | [standalone]


#3271

Fromdeedubman@gmail.com
Date2018-06-18 14:22 -0700
Message-ID<80d271e1-9d5c-489d-853b-11225edbbf74@googlegroups.com>
In reply to#3250
Doesn't ascender refer to lower-case letters that project above the x-height like b, d, f, h, k, l, and t? I would take the max of this set. Also take the min of g, j, p, q, and y for descender. 

For stem-v I remember doing a small survey of fonts for which I had AFM files (which have stem-v) and then trying to tune an algorithm such as you described to match the known data, maybe make a wide but thin clip rectangle that crosses the stem of "I" in the middle, which is also 'true charpath clip', then 'clippath pathbbox' that result, get the width. If it could reasonably guess at known stem-v values then I could trust it in the unknown case. But then I noticed (if we are talking about PDF) that a lot of PDF software seems to not care about the stem-v value in font desccriptors, it was often zero.

David

[toc] | [prev] | [next] | [standalone]


#3272

Fromluser droog <luser.droog@gmail.com>
Date2018-06-18 23:13 -0700
Message-ID<68dd4c54-1ae2-4b76-8568-1ceebe713126@googlegroups.com>
In reply to#3271
On Monday, June 18, 2018 at 4:22:14 PM UTC-5, deed...@gmail.com wrote:
> Doesn't ascender refer to lower-case letters that project above the x-height like b, d, f, h, k, l, and t? I would take the max of this set. Also take the min of g, j, p, q, and y for descender. 
> 

That's a good thought. It wouldn't be a lot of work to make that change, 
too. Just adding those other characters to the string. It already takes
the bounding box to get lowest of (currently) one glyph.


> For stem-v I remember doing a small survey of fonts for which I had AFM files (which have stem-v) and then trying to tune an algorithm such as you described to match the known data, maybe make a wide but thin clip rectangle that crosses the stem of "I" in the middle, which is also 'true charpath clip', then 'clippath pathbbox' that result, get the width. If it could reasonably guess at known stem-v values then I could trust it in the unknown case. But then I noticed (if we are talking about PDF) that a lot of PDF software seems to not care about the stem-v value in font desccriptors, it was often zero.
> 
> David

That does seem like a good strategy. A further complication has arisen in
the actual project which changes things somewhat. The fonts I need to deal
with are not in the Standard set of 14 fonts. So I need to embed the fonts
so Acrobat Reader won't cough at my PDFs.

So, I think the simplest thing to do is to write a font sampler program in
ps, hoof it over to Kinko's and do the conversion with Acrobat Distiller
on a machine that has the required fonts. Then I can reverse engineer what
I need from the resulting PDF.

Come to think of it, my mom probably has the fonts and distiller, too. 
And better rates than Kinko's. :)

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.postscript


csiph-web