L il3vdZddlZejdZejdZejdZejdZejdZgdZGd d e Z Gd d e Z d Z ddZedk(rddlZej"Zere eZdZej+er eeedZej1er eeeeej2eej4eej7eeej9edzyyy)a Module for reading and writing AFM (Adobe Font Metrics) files. Note that this has been designed to read in AFM files generated by Fontographer and has not been tested on many other files. In particular, it does not implement the whole Adobe AFM specification [#f1]_ but, it should read most "common" AFM files. Here is an example of using `afmLib` to read, modify and write an AFM file: >>> from fontTools.afmLib import AFM >>> f = AFM("Tests/afmLib/data/TestAFM.afm") >>> >>> # Accessing a pair gets you the kern value >>> f[("V","A")] -60 >>> >>> # Accessing a glyph name gets you metrics >>> f["A"] (65, 668, (8, -25, 660, 666)) >>> # (charnum, width, bounding box) >>> >>> # Accessing an attribute gets you metadata >>> f.FontName 'TestFont-Regular' >>> f.FamilyName 'TestFont' >>> f.Weight 'Regular' >>> f.XHeight 500 >>> f.Ascender 750 >>> >>> # Attributes and items can also be set >>> f[("A","V")] = -150 # Tighten kerning >>> f.FontName = "TestFont Squished" >>> >>> # And the font written out again (remove the # in front) >>> #f.write("testfont-squished.afm") .. rubric:: Footnotes .. [#f1] `Adobe Technote 5004 `_, Adobe Font Metrics File Format Specification. Nz^([A-Za-z]+).*zl(-?\d+)\s*;\s*WX\s+(-?\d+)\s*;\s*N\s+([.A-Za-z0-9_]+)\s*;\s*B\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s+(-?\d+)\s*;\s*z0([.A-Za-z0-9_]+)\s+([.A-Za-z0-9_]+)\s+(-?\d+)\s*z([.A-Za-z0-9_]+)\s+(\d+)\s*;\s*z1PCC\s+([.A-Za-z0-9_]+)\s+(-?\d+)\s+(-?\d+)\s*;\s*)FontNameFullName FamilyNameWeight ItalicAngle IsFixedPitchFontBBoxUnderlinePositionUnderlineThicknessVersionNoticeEncodingScheme CapHeightXHeightAscender Descenderc eZdZy)errorN)__name__ __module__ __qualname__V/mnt/ssd/data/python-lab/Trading/venv/lib/python3.12/site-packages/fontTools/afmLib.pyrrwsrrceZdZdZgdZddZdZdZdZdZ dZ dd Z d Z d Z d Zd ZdZdZdZdZdZdZdZdZdZdZy)AFMN) StartFontMetricsEndFontMetricsStartCharMetricsEndCharMetrics StartKernDataStartKernPairs EndKernPairs EndKernDataStartComposites EndCompositesci|_i|_i|_i|_g|_i|_||j |yy)zAFM file reader. Instantiating an object with a path name will cause the file to be opened, read, and parsed. Alternatively the path can be left unspecified, and a file can be parsed later with the :meth:`read` method.N)_attrs_chars_kerning_index _comments _compositesread)selfpaths r__init__z AFM.__init__sE        IIdO rct|}|D]}|jstj|}|t dt |z|j dd}|d|}||dj}||jvr{|dk(r|j||dk(r|j||dk(r|j||j||y)zOpens, reads and parses a file.Nsyntax error in AFM file: CKPXCC) readlinesstrip identifierREmatchrreprregs _keywords parsechar parsekernpairparsecomposite parseattr)r/r0lineslinemposwordrests rr.zAFM.reads$ +D::<""4(Ay84:EFF&&)A,C:D:##%Dt~~%s{t$""4(##D)tT*' +rctj|}|tdt|zg}|jddD]\}}|j ||||d}|d=d|D\}}} } } } ||| | | | ff|j |<y)Nr3r4c32K|]}t|ywN)int).0things r z AFM.parsechar..s%EUc%j%Es)charREr;rr<r=appendr)) r/rHrEthingsfrtocharnamecharnumwidthlbrts rr?z AFM.parsechars LL  94tDzAB BffQRj 'FB MM$r"+ & '!9 1I%Ef%E"1a 'Aq! < Hrctj|}|tdt|zg}|jddD]\}}|j ||||\}}}t |}||j||f<y)Nr3r4)kernREr;rr<r=rRrMr*) r/rHrErSrTrUleftchar rightcharvalues rr@zAFM.parsekernpairs LL  94tDzAB BffQRj 'FB MM$r"+ & '%+")UE /4 x+,rcX|dk(r@|jDcgc] }t|c}\}}}}||||f|j|<y|dk(r|jj |y t|}||j|<ycc}w#t t f$r||j|<YywxYw)Nr Comment)splitrMr(r,rR ValueError OverflowError) r/rGrHrOrYrZr[r\ras rrBz AFM.parseattrs : 26**,?#e*?JAq!Q !1a DKK  Y  NN ! !$ ' *D %* D!@ . )$( D! )sB( BB)(B)cdtj|}|tdt|z|j d}t |j d}||j ddd}g} tj|}|tdt|z|j d}t |j d}t |j d}|j|||f||j ddd}|snt||k(sJ||j|<y)Nr3r4rJr) compositeREr;rr<grouprMr= componentRErRlenr-) r/rHrErV ncomponents componentsbasecharxoffsetyoffsets rrAzAFM.parsecomposites   d # 94tDzAB B771:!''!*o AFF1IaLN# !!$'Ay84:EFFwwqzH!''!*oG!''!*oG   x': ;q ! 'D:+---%/"rc bddl}dd|jd|j|jzg}|jD]}|j d|z|j }t D]6}||vs||}|dk(rd|z}|j |d zt|z8t|j} | D].\}}|t vr|j |d zt|z0|j d tt|jz|jjD cgc]\} \} } } | | | | ff} } } } } d }| j| | D])\} \} } \}}}}|j d | | | ||||fz+|j d|j d|j dtt|jzt|jj} | D]\\}}}|j d|||fz!|j d|j d|jrt|jj}|j dt|jz|D]B\} }d| d t|d}|D]\}}}|d|d |d |dz}|j |D|j d|j dt!|||ycc} } } } w)z)Writes out an AFM font to the given path.rNzStartFontMetrics 2.0z"Comment Generated by afmLib; at %sz%m/%d/%Y %H:%M:%SzComment r z %s %s %s %s zStartCharMetrics c&|ddk(rd|ddz}|S)znCustom key function to make sure unencoded chars (-1) end up at the end of the list after sorting.r)ir4Nr)as rmyKeyzAFM.write..myKeys$trz!"%Hr)keyz%C %d ; WX %d ; N %s ; B %d %d %d %d ;r r!zStartKernPairs z KPX %s %s %dr#r$zStartComposites %szCC z ;z PCC r&r)timestrftime localtimer,rRr(preferredAttributeOrderstrsorteditemsr<rlr)sortr*r- writelines)r/r0sepryrCcommentattrsattrrarrVrWrXboxrwrYrZr[r\r_r` compositesrnrDrorprqs rwritez AFM.writes' # 0}}0$..2MN P ~~ /G LLg- . /  + 6Du}d :%)E1E TCZ#e*45  6u{{}%  2KD%.. LLc%j0 1 2  (4DKK0@+AAB48;;3D3D3F  //7E3x, -     u 8=  4G4h|1a LL7E8Q1a89    %&  _% &c$--.@)AABt}}**,-,1 H ( !Xy5 LL8Y*FF G H ^$ ]#    0 0 6 6 89J LL-D4D4D0EE F(2 #$*'/ZA2<S.Hgwx'"RRDS T"  # LL ) %&4$U sL) c||jvS)zgReturns `True` if the given glyph pair (specified as a tuple) exists in the kerning dictionary.)r*)r/pairs r has_kernpairzAFM.has_kernpair;st}}$$rcHt|jjS)z;Returns a list of all kern pairs in the kerning dictionary.)listr*keysr/s r kernpairsz AFM.kernpairs@sDMM&&())rc||jvS)z5Returns `True` if the given glyph exists in the font.)r))r/chars rhas_charz AFM.has_charDst{{""rcHt|jjS)z.Returns a list of all glyph names in the font.)rr)rrs rcharsz AFM.charsHsDKK$$&''rc|jS)z#Returns all comments from the file.)r,rs rcommentsz AFM.commentsLs ~~rc:|jj|y)zAdds a new comment to the file.N)r,rR)r/rs r addCommentzAFM.addCommentPs g&rc"||j|<y)aSpecifies that the glyph `glyphName` is made up of the given components. The components list should be of the following form:: [ (glyphname, xOffset, yOffset), ... ] N)r-)r/ glyphNamerns r addCompositezAFM.addCompositeTs'1#rcR||jvr|j|St|rL)r(AttributeErrorr/rs r __getattr__zAFM.__getattr__`s( 4;; ;;t$ $ & &rcR|dddk(r||j|<y||j|<yNr4_)__dict__r()r/rras r __setattr__zAFM.__setattr__fs+ 8s?"'DMM$  %DKK rc|dddk(r |j|=y |j|=y#t$r t|wxYw#t$r t|wxYwr)rKeyErrorrr(rs r __delattr__zAFM.__delattr__msh 8s? +MM$' +KK%  +$T** +  +$T** +s ' ?<Ac^t|tr|j|S|j|SrL isinstancetupler*r)r/rxs r __getitem__zAFM.__getitem__zs, c5 !==% %;;s# #rcbt|tr||j|<y||j|<yrLr)r/rxras r __setitem__zAFM.__setitem__s* c5 !!&DMM#  %DKK rcZt|tr|j|=y|j|=yrLrrs r __delitem__zAFM.__delitem__s& c5 ! c" C rcTt|drd|jzSdt|zS)Nrzz)hasattrridrs r__repr__z AFM.__repr__s* 4 $(4==8 8'"T(2 2rrL )rrrr(r>r1r.r?r@rBrArrrrrrrrrrrrrrrrrrrr{sy F I +0 = 5 *0,L%\% *#(' 1' & +$%!3rrct|dd5}|j}ddd|jS#1swYjSxYw)Nr[ascii)encoding)openr. splitlines)r0fdatas rr8r8sE dC' *avvx ??  ?? s 8Act|dd|5}|jdj|dzdddy#1swYyxYw)Nwr)rnewline )rrjoin)r0rCrrs rrrsA dC'3 7)1  % 4'()))s $=A__main__A)rVz.muckr)__doc__recompiler:rQr^rirkr| Exceptionrobjectrr8rr EasyDialogsAskFileForOpenr0afmrrprintrrr rrrrrrrsZ-^ rzz+,    $   bjj bjj ( I [3&[3| )  z %; % % 'D $i <<  #d)    D ! #d)  ckk cjj clln c  $.! r