[reportlab-users] Achieving uniform spacing in a text object

Jeff Kowalczyk reportlab-users@reportlab.com
Fri, 23 Aug 2002 12:20:09 -0400


Is there a way to achieve uniform spacing of characters, without relying on
the monospaced-ness of fonts like courier.

The attached example is helvetica (proportional), but if you change it to
courier, it is still very sensitive to spacing drift. I was fiddling with
7.78 and 7.79 in courier, and still not getting the later chars to align.

I guess what I'm looking for is a sane way to grid the characters out,
regardless of the font. It would be a nice API addition to textobject, if
possible: something like setCharSpaceGrid().


# CharSpacingTest.py - Test monospacing chars with proportional fonts
from reportlab.pdfgen.canvas import Canvas

Courier = 'Courier'
Helvetica = 'Helvetica'

class Form:
    def __init__(self, **kw):
        self.pdfpath = kw.get('pdfpath', 'CharSpacingTest.pdf')
        self.verbose = kw.get('verbose', 0)
        self.text_font = kw.get('typeface', Courier)
        self.text_size = kw.get('fontsize', 10)
        self.canvas = Canvas(self.pdfpath)
        self.__draw_grid()
        self.__draw_filled_boxes()


    FilledBoxes = [ \
        ( 100, 700, 20, '01234567890!,ABCDEFG', ),
        ]

    def __draw_filled_boxes(self):
        c = self.canvas
        boxwidth = 15
        boxheight = 15
        for x1, y1, chars, filler in self.FilledBoxes:
            xlist = range(x1, x1+(chars*boxwidth)+1, boxwidth)
            ylist = [y1, y1+boxheight]
            c.setLineWidth(0.25)
            c.setStrokeGray(0.25)
            c.grid(xlist,ylist)
            c.setStrokeGray(0)
            t = c.beginText(x1,y1+3)
            t.setFont(Helvetica,12)
            t.setCharSpace(7.5)
            t.textOut(filler)
            c.drawText(t)
            t = None

    def __draw_grid(self):
        c = self.canvas
        xlist = range(0, 620, 20)
        ylist = range(0, 900, 20)
        c.setLineWidth(0.05)
        c.setStrokeGray(0.25)
        c.grid(xlist,ylist)
        for x in xlist:
            t = c.beginText(x,ylist[36])
            t.setFont(Helvetica,6)
            t.textOut(str(x))
            c.drawText(t)
        for y in ylist:
            t = c.beginText(xlist[10],y)
            t.setFont(Helvetica,6)
            t.textOut(str(y))
            c.drawText(t)
        c.setStrokeGray(1.0)

    def save(self):
        self.canvas.save()

if __name__ == '__main__':
    from Fields import test_pattern
    form = Form()
    #form.populate(test_pattern())
    form.save()



begin 666 CharSpacingTest.pdf
M)5!$1BTQ+C,-"B63C(N>(%)E<&]R=$QA8B!'96YE<F%T960@4$1&(&1O8W5M
M96YT(&AT=' Z+R]W=W<N<F5P;W)T;&%B+F-O;0T*)2 G0F%S:6-&;VYT<R<@
M)SQR97!O<G1L86(N<&1F8F%S92YP9&9D;V,N4$1&1&EC=&EO;F%R>2!I;G-T
M86YC92!A)R -"C$@,"!O8FH-"B4@5&AE('-T86YD87)D(&9O;G1S(&1I8W1I
M;VYA<GD-"CP\("]&,2 R(# @4B ^/@T*96YD;V)J#0HE("=&,2<@)SQR97!O
M<G1L86(N<&1F8F%S92YP9&9D;V,N4$1&5'EP93%&;VYT(&EN<W1A;F-E(&%T
M)R -"C(@,"!O8FH-"B4@1F]N="!(96QV971I8V$-"CP\("]"87-E1F]N=" O
M2&5L=F5T:6-A#0H@+T5N8V]D:6YG("]7:6Y!;G-I16YC;V1I;F<-"B O3F%M
M92 O1C$-"B O4W5B='EP92 O5'EP93$-"B O5'EP92 O1F]N=" ^/@T*96YD
M;V)J#0HE("=086=E,2<@)SQR97!O<G1L86(N<&1F8F%S92YP9&9D;V,N4$1&
M4&%G92!I;G-T86YC92!A=" P># P)R -"C,@,"!O8FH-"B4@4&%G92!D:6-T
M:6]N87)Y#0H\/" O0V]N=&5N=',@-R P(%(-"B O365D:6%";W@@6R P#0H@
M(# -"B @-3DU+C(W#0H@(#@T,2XX.2!=#0H@+U!A<F5N=" V(# @4@T*("]2
M97-O=7)C97,@/#P@+T9O;G0@,2 P(%(-"B @+U!R;V-3970@6R O4$1&#0H@
M(" O5&5X= T*(" @+TEM86=E0@T*(" @+TEM86=E0PT*(" @+TEM86=E22!=
M(#X^#0H@+U1R86YS(#P\(" ^/@T*("]4>7!E("]086=E(#X^#0IE;F1O8FH-
M"B4@)U(T)R G/')E<&]R=&QA8BYP9&9B87-E+G!D9F1O8RY01$9#871A;&]G
M(&EN<W1A;F-E(&%T(# G( T*-" P(&]B:@T*)2!$;V-U;65N="!2;V]T#0H\
M/" O3W5T;&EN97,@." P(%(-"B O4&%G94UO9&4@+U5S94YO;F4-"B O4&%G
M97,@-B P(%(-"B O5'EP92 O0V%T86QO9R ^/@T*96YD;V)J#0HE("=2-2<@
M)SQR97!O<G1L86(N<&1F8F%S92YP9&9D;V,N4$1&26YF;R!I;G-T86YC92!A
M=" P># P)R -"C4@,"!O8FH-"CP\("]!=71H;W(@*&%N;VYY;6]U<RD-"B O
M0W)E871I;VY$871E("@R,# R,#@R,S$R,3 U,2D-"B O4')O9'5C97(@*%)E
M<&]R=$QA8B!H='1P.B\O=W=W+G)E<&]R=&QA8BYC;VTI#0H@+U-U8FIE8W0@
M*'5N<W!E8VEF:65D*0T*("]4:71L92 H=6YT:71L960I(#X^#0IE;F1O8FH-
M"B4@)U(V)R G/')E<&]R=&QA8BYP9&9B87-E+G!D9F1O8RY01$9086=E<R!I
M;G-T86YC92!A=" P># G( T*-B P(&]B:@T*)2!P86=E('1R964-"CP\("]#
M;W5N=" Q#0H@+TMI9',@6R S(# @4B!=#0H@+U1Y<&4@+U!A9V5S(#X^#0IE
M;F1O8FH-"B4@)U(W)R G/')E<&]R=&QA8BYP9&9B87-E+G!D9F1O8RY01$93
M=')E86T@:6YS=&%N8V4@870@,'@G( T*-R P(&]B:@T*)2!P86=E('-T<F5A
M;0T*/#P@+T9I;'1E<B!;("]!4T-)23@U1&5C;V1E#0H@("]&;&%T941E8V]D
M92!=#0H@+TQE;F=T:" Q,C@Q(#X^#0IS=')E86T-"D=A="5D8D1T/3(D<3EM
M:VYD:R]K(F-".4Y-02$X7F]**6HG4E%I-$DW1D-!+EY99%TK+$0Q;&HC7U!E
M:@T*:S-"8C9')R,Q3%I*4%)G<SA6+"E(*UEA3UX[.7)=/EYN028J;2]/)5M8
M/E=7.D-E<R])<D(X2&),/SI:#0IK0G1T9C10<TAH;&=J<2-?5RI&=51C061'
M2VU&2#4H6ELA(RA,5$)59U5I8#@D3E5'6#9?2&!U)CDH2"P-"F%003PA,T-?
M*V,T-TLQ;B1P-B%<(BTX/EM>;2%B+&X^*#HY-#U1:B<Z4'4G8U!.(S$E62P^
M4E M;C)M8PT*/R0S9$=*33)M-DI-,FTV2E,R<D-I*B-2:4=:2' S4V5=4R9"
M/G$T-&@P8VHS/T%A/F W+TUP2"UR<6$B#0I7*69J(R8X+&!D2%I9.FI')R9T
M/21/+65?2SLD+3<_=54G1TQN02Y(55%S:4<E/TA./E]K6C@^;D4^*E(-"C0_
M.'5!.E$_9S]03C!D4VI%3D9",TTK,&U",UPW8#-04#AG3S,[1SEI<5(A6&EQ
M474M1R$D7S@J4D))40T*83!885AN4T5';C1()BMP7$=+/$E(;S8Z;TDN84)A
M*EI.(75A)F<O.V$C0VUP82-#;7!A(T-M<&$C0VUP#0IA(T-N;VHR3$Y)1U91
M:6H_-#A+22A/=& Q67,W83AC7V]/.24V9R5Q5F=%:DM"0V!7+FI1=7572#)2
M*"L-"D12;V,C5G0R=3%K)TA!*"XO041!*D1L/BY;-B1912%27W1G0TAG8D\_
M)$9"*C)T5RI)7F-$)6A?;EQ!*PT*8RPW/5MO7C%<4S4U*T,H:V1,-E%J,6UK
M4&U':W5'<#]G;E4U-2M";5YC<4=9925E,#]M1B]J-W D3#5$#0HU-2(\;%YC
M<4=945PC*V!;<$M -3E#9BPJ<E1S1E1B2CA3:V=&:5LK5B]-=#)P.C4K-B-0
M4%U(5"I0*2,-"D1K0#HN7%-N*49P.C4K5B5D7V<N7"5H6D(G*C5!24$_44Q,
M-$)F,D8C-EHI(F@\4"Y%3RU=."TA2B]R.@T*.B<Z73=A(T990E<C871F-6).
M.FHG*C-;/$]<42E@+4U&8W)D(TXX<BM,3#$B(VUF<%-"*BA#76LI(E52#0IM
M04U"-B%K)2=;(U)*<3](;3!<,#0X*TU=-6ID8E\A5V]D:50J4%]0)W4\.B=4
M5U0K62%7;4PU,&)&='$-"BYU;TDZ-5M"3$<B.64B24%+:39N/2,Z46M*7"=J
M+R-22F]P9#9P-FU9*EY//%4Q5&=69U112C0S9V942 T*0F<Y*#8G1&QQ(2E>
M:SY@1$5J)R]12C8^-W)+8S)633Y@87!$:2M&66=2(VIM:E)S;2A)8UXX3%EQ
M3EDY#0HX84]60V]S/#MC6D]B92MJ9THK8$!@)F=:/DY'-D-?(R0E2VTW:4UN
M3U9:)R@G6R-&6"<D0DQ>*51Q,V(-"B@\5D]C,#Q7-T10;"12660_3TYJ*#Q-
M9U4X<#)-.5I&6SYR.TAT6D5=6%M/;#AC:'):-W X.UIM4DQ',PT*6'0V.%<]
M*6]>62YP1D9 42]=<T=P4V-M)U52+W--<%!12$L_4E=;+5TM0RQ/;6=1.BYC
M8VI2;&U);FX[#0I<8S L,UUM<RAL,E,C;RUH3$)Q3F]?2%Q>+5PE65!O0D _
M1%L^7V!^/F5N9'-T<F5A;0T*#0IE;F1O8FH-"B4@)U(X)R G/')E<&]R=&QA
M8BYP9&9B87-E+G!D9F1O8RY01$9/=71L:6YE<R!I;G-T86YC92!A=" G( T*
M." P(&]B:@T*/#P@+T-O=6YT(# -"B O5'EP92 O3W5T;&EN97,@/CX-"F5N
M9&]B:@T*>')E9@T*," Y#0HP,# P,# P,# P(#8U-3,U(&8-"C P,# P,# Q
M-#4@,# P,# @;@T*,# P,# P,#(W-" P,# P,"!N#0HP,# P,# P-#<U(# P
M,# P(&X-"C P,# P,# W.#,@,# P,# @;@T*,# P,# P,#DU-2 P,# P,"!N
M#0HP,# P,# Q,3@X(# P,# P(&X-"C P,# P,#$S,CD@,# P,# @;@T*,# P
M,# P,C<Y," P,# P,"!N#0IT<F%I;&5R#0H\/" O240@#0H@("4@4F5P;W)T
M3&%B(&=E;F5R871E9"!01$8@9&]C=6UE;G0@+2T@9&EG97-T("AH='1P.B\O
M=W=W+G)E<&]R=&QA8BYC;VTI( T*("!;*%PS-S9<,C<R;EPS-#8^9UPR-#9<
M,#,Q;5PR,39<,C8S7#,S,DY<,C8T7# P,UPS-S<I("A<,S<V7#(W,FY<,S0V
M/F=<,C0V7# S,6U<,C$V7#(V,UPS,S).7#(V-%PP,#-<,S<W*5T@#0H@#0H@
M+TEN9F\@-2 P(%(-"B O4F]O=" T(# @4@T*("]3:7IE(#D@/CX-"G-T87)T
3>')E9@T*,C@T,0T*)25%3T8-"@``
`
end