)Ej#5dZddlZejdZejdZejdZejdZejdZgdZGd d e Z Gd d e Z d Z ddZedkrddlZejZere eZdZeereeedZeereeeeejeejeeeeeedzdSdSdS)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 DescenderceZdZdS)errorN)__name__ __module__ __qualname__BC:\PYTHON\MyICR_Suite\python\Lib\site-packages\fontTools/afmLib.pyrrwsDrrceZdZdZgdZddZdZdZdZdZ dZ dd Z d Z d Z d ZdZdZdZdZdZdZdZdZdZdZdZdS)AFMN) StartFontMetricsEndFontMetricsStartCharMetricsEndCharMetrics StartKernDataStartKernPairs EndKernPairs EndKernDataStartComposites EndCompositesci|_i|_i|_i|_g|_i|_|||dSdS)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__sP        IIdOOOOO  rc,t|}|D]}|st|}|t dt |z|jdd}|d|}||d}||jvr|dkr|||dkr| ||dkr| || ||dS)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::EFFF&)A,C:D:##%%Dt~%%s{{t$$$$""4((((##D))))tT****' + +rcBt|}|tdt|zg}|jddD]"\}}||||#|d}|d=d|D\}}} } } } ||| | | | ff|j|<dS)Nr3r4c34K|]}t|VdSNint.0things r z AFM.parsechar..s(%E%EUc%jj%E%E%E%E%E%Er)charREr;rr<r=appendr)) r/rHrEthingsfrtocharnamecharnumwidthlbrts rr?z AFM.parsechars LL   94tDzzABB BfQRRj ' 'FB MM$r"u+ & & & &!9 1I%E%Ef%E%E%E"1a 'Aq! < Hrc&t|}|tdt|zg}|jddD]"\}}||||#|\}}}t |}||j||f<dS)Nr3r4)kernREr;rr<r=rTrNr*) r/rHrErUrVrWleftchar rightcharvalues rr@zAFM.parsekernpairs LL   94tDzzABB BfQRRj ' 'FB MM$r"u+ & & & &%+")UE /4 x+,,,rc4|dkr3d|D\}}}}||||f|j|<dS|dkr|j|dS t |}||j|<dS#t t f$r||j|<YdSwxYw)Nr c,g|]}t|SrrMrOs r z!AFM.parseattr..s???#e**???rComment)splitr(r,rTrN ValueError OverflowError)r/rGrHr[r\r]r^rcs rrBz AFM.parseattrs :  ??$**,,???JAq!Q !1a DK    Y   N ! !$ ' ' ' ' ' *D %* D!!! . ) ) )$( D!!!! )sA88BBct|}|tdt|z|d}t |d}||jddd}g} t|}|tdt|z|d}t |d}t |d}||||f||jddd}|snt||ksJ||j |<dS)Nr3r4rJrT) compositeREr;rr<grouprNr= componentRErTlenr-) r/rHrErX ncomponents componentsbasecharxoffsetyoffsets rrAzAFM.parsecompositesT   d # # 94tDzzABB B771::!''!**oo AF1IaLNN#  !!$''Ay84::EFFFwwqzzH!''!**ooG!''!**ooG   x': ; ; ;q ! 'D  :+----%/"""r c ddl}dd|d||zg}|jD]}|d|z|j}t D]A}||vr;||}|dkrd|z}||d zt|zBt| } | D]7\}}|t vr||d zt|z8|d tt|j zd |j D} d } | | | D]-\} \} } \}}}}|d| | | ||||fz.|d|d|dtt|jzt|j } | D]#\\}}}|d|||fz$|d|d|jrt|j }|dt|jz|D]H\} }d| d t|d}|D]\}}}|d|d |d |dz}||I|d|dt!|||dS)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*g|]\}\}}}||||ffSrr)rPrXrYrZboxs rrfzAFM.write..s?   //7E3x, -   rc8|ddkr d|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(trzz!""%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,rTr(preferredAttributeOrderstrsorteditemsr<rpr)sortr*r- writelines)r/r0seprrCcommentattrsattrrcrr~rYrXrZr[r\r]r^rarb compositesrrrDrsrtrus rwritez AFM.writes  # 0}}0$..2M2MNN P ~ / /G LLg- . . . . + 6 6Du}}d :%%)E1E TCZ#e**4555u{{}}%%  2 2KD%... LLc%jj0 1 1 1 1  (4DK0@0@+A+AABBB  37;3D3D3F3F         u 8=   4G4h|1a LL7E8Q1a89      %&&&  _%%% &c$-.@.@)A)AABBBt}**,,--,1 H H ( !Xy5 LL8Y*FF G G G G ^$$$ ]###   * 0 6 6 8 899J LL-D4D0E0EE F F F(2 # #$**'/xxZA2<SS.Hgw4xxx'''"RRDD T"""" LL ) ) ) %&&&4$$$$$rc||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}$$rcNt|jS)z;Returns a list of all kern pairs in the kerning dictionary.)listr*keysr/s r kernpairsz AFM.kernpairs@sDM&&(()))rc||jvS)z5Returns `True` if the given glyph exists in the font.)r))r/chars rhas_charz AFM.has_charDst{""rcNt|jS)z.Returns a list of all glyph names in the font.)rr)rrs rcharsz AFM.charsHsDK$$&&'''rc|jS)z#Returns all comments from the file.)r,rs rcommentsz AFM.commentsLs ~rc:|j|dS)zAdds a new comment to the file.N)r,rT)r/rs r addCommentzAFM.addCommentPs g&&&&&rc||j|<dS)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/ glyphNamerrs r addCompositezAFM.addCompositeTs'1###rcL||jvr |j|St|rL)r(AttributeErrorr/rs r __getattr__zAFM.__getattr__`s* 4;  ;t$ $ && &rcN|dddkr ||j|<dS||j|<dSNr4_)__dict__r()r/rrcs r __setattr__zAFM.__setattr__fs7 8s??"'DM$    %DK   rc|dddkr( |j|=dS#t$rt|wxYw |j|=dS#t$rt|wxYwr)rKeyErrorrr(rs r __delattr__zAFM.__delattr__ms 8s?? +M$''' + + +$T*** + +K%%% + + +$T*** +s4AAc`t|tr |j|S|j|SrL isinstancetupler*r)r/rs r __getitem__zAFM.__getitem__zs0 c5 ! ! $=% %;s# #rc\t|tr ||j|<dS||j|<dSrLr)r/rrcs r __setitem__zAFM.__setitem__s: c5 ! ! %!&DM#    %DK   rcTt|tr |j|=dS|j|=dSrLrrs r __delitem__zAFM.__delitem__s6 c5 ! ! ! c""" C   rcZt|dr d|jzSdt|zS)Nrzz)hasattrridrs r__repr__z AFM.__repr__s2 4 $ $ 3(4=8 8'"T((2 2rrLrv)rrrr(r>r1r.r?r@rBrArrrrrrrrrrrrrrrrrrrr{st F   I    +++0 = = = 5 5 5 * * *000,L%L%L%L%\%%% ***###(((''' 1 1 1''' &&& + + +$$$%%%!!!33333rrct|dd5}|}dddn #1swxYwY|S)Nr]ascii)encoding)openr. splitlines)r0fdatas rr8r8s dC' * * *avvxx ??  s 488rvct|dd|5}|d|dzddddS#1swxYwYdS)Nwr)rnewline )rrjoin)r0rCrrs rrrs dC'3 7 7 7)1  %  4'((())))))))))))))))))s,A  AA__main__A)rVz.muckr)__doc__recompiler:rSr`rmror Exceptionrobjectrr8rr EasyDialogsAskFileForOpenr0afmrrprintrrr rrrrrrrs<--^ rz+,,     $    bj bj (     I   [3[3[3[3[3&[3[3[3| ))))  z %; % ' 'D "c$ii <<    E#d)      D ! !  E#d)    ck cj cllnn c  $.!!!!!'""r