File: ch2_graphics.py

package info (click to toggle)
python-reportlab 3.1.8-3%2Bdeb8u1
  • links: PTS
  • area: main
  • in suites: jessie
  • size: 6,996 kB
  • ctags: 9,483
  • sloc: python: 69,727; ansic: 19,108; xml: 1,494; makefile: 416; java: 193; sh: 100
file content (1259 lines) | stat: -rw-r--r-- 45,193 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
#Copyright ReportLab Europe Ltd. 2000-2012
#see license.txt for license details
#history http://www.reportlab.co.uk/cgi-bin/viewcvs.cgi/public/reportlab/trunk/reportlab/docs/userguide/ch2_graphics.py
from tools.docco.rl_doc_utils import *
from reportlab.lib.codecharts import SingleByteEncodingChart

heading1("Graphics and Text with $pdfgen$")

heading2("Basic Concepts")
disc("""
The $pdfgen$ package is the lowest level interface for
generating PDF documents.  A $pdfgen$ program is essentially
a sequence of instructions for "painting" a document onto
a sequence of pages.  The interface object which provides the
painting operations is the $pdfgen canvas$.
""")

disc("""
The canvas should be thought of as a sheet of white paper
with points on the sheet identified using Cartesian ^(X,Y)^ coordinates
which by default have the ^(0,0)^ origin point at the lower
left corner of the page.  Furthermore the first coordinate ^x^
goes to the right and the second coordinate ^y^ goes up, by
default.""")

disc("""
A simple example
program that uses a canvas follows.
""")

eg("""
    from reportlab.pdfgen import canvas
    def hello(c):
        c.drawString(100,100,"Hello World")
    c = canvas.Canvas("hello.pdf")
    hello(c)
    c.showPage()
    c.save()
""")

disc("""
The above code creates a $canvas$ object which will generate
a PDF file named $hello.pdf$ in the current working directory.
It then calls the $hello$ function passing the $canvas$ as an argument.
Finally the $showPage$ method saves the current page of the canvas
and the $save$ method stores the file and closes the canvas.""")

disc("""
The $showPage$ method causes the $canvas$ to stop drawing on the
current page and any further operations will draw on a subsequent
page (if there are any further operations -- if not no
new page is created).  The $save$ method must be called after the
construction of the document is complete -- it generates the PDF
document, which is the whole purpose of the $canvas$ object.
""")

heading2("More about the Canvas")
disc("""
Before describing the drawing operations, we will digress to cover
some of the things which can be done to configure a canvas.  There
are many different settings available.  If you are new to Python
or can't wait to produce some output, you can skip ahead, but
come back later and read this!""")

disc("""First of all, we will look at the constructor
arguments for the canvas:""")

eg("""    def __init__(self,filename,
                 pagesize=(595.27,841.89),
                 bottomup = 1,
                 pageCompression=0,
                 encoding=rl_config.defaultEncoding,
                 verbosity=0
                 encrypt=None):
                 """)

disc("""The $filename$ argument controls the
name of the final PDF file.  You
may also pass in any open file object (such as $sys.stdout$, the python process standard output)
and the PDF document will be written to that.  Since PDF
is a binary format, you should take care when writing other
stuff before or after it; you can't deliver PDF documents
inline in the middle of an HTML page!""")

disc("""The $pagesize$ argument is a tuple of two numbers
in points (1/72 of an inch). The canvas defaults to $A4$ (an international standard
page size which differs from the American standard page size of $letter$),
but it is better to explicitly specify it.  Most common page
sizes are found in the library module $reportlab.lib.pagesizes$,
so you can use expressions like""")

eg("""from reportlab.lib.pagesizes import letter, A4
myCanvas = Canvas('myfile.pdf', pagesize=letter)
width, height = letter  #keep for later
""")

pencilnote()

disc("""If you have problems printing your document make sure you
are using the right page size (usually either $A4$ or $letter$).
Some printers do not work well with pages that are too large or too small.""")

disc("""Very often, you will want to calculate things based on
the page size.  In the example above we extracted the width and
height.  Later in the program we may use the $width$ variable to
define a right margin as $width - inch$ rather than using
a constant.  By using variables the margin will still make sense even
if the page size changes.""")

disc("""The $bottomup$ argument
switches coordinate systems.  Some graphics systems (like PDF
and PostScript) place (0,0) at the bottom left of the page
others (like many graphical user interfaces [GUI's]) place the origen at the top left.  The
$bottomup$ argument is deprecated and may be dropped in future""")

todo("""Need to see if it really works for all tasks, and if not
     then get rid of it""")

disc("""The $pageCompression$ option determines whether the stream
of PDF operations for each page is compressed.  By default
page streams are not compressed, because the compression slows the file generation process.
If output size is important set $pageCompression=1$, but remember that, compressed documents will
be smaller, but slower to generate.  Note that images are <i>always</i> compressed, and this option
will only save space if you have a very large amount of text and vector graphics
on each page.""")

disc("""The $encoding$ argument is largely obsolete in version 2.0 and can
probably be omitted by 99% of users.  Its default value is fine unless you
very specifically need to use one of the 25 or so characters which are present
in MacRoman and not in Winansi.  A useful reference to these is here:
<font color="blue"><u><a href="http://www.alanwood.net/demos/charsetdiffs.html">http://www.alanwood.net/demos/charsetdiffs.html</a></u></font>.

The parameter determines which font encoding is used for the
standard Type 1 fonts; this should correspond to the encoding on your system.
Note that this is the encoding used <i>internally by the font</i>; text you
pass to the ReportLab toolkit for rendering should always either be a Python
unicode string object or a UTF-8 encoded byte string (see the next chapter)!
The font encoding has two values at present: $'WinAnsiEncoding'$ or
$'MacRomanEncoding'$.  The variable $rl_config.defaultEncoding$ above points
to the former, which is standard on Windows, Mac OS X and many Unices
(including Linux). If you are Mac user and don't have OS X, you may want to
make a global change: modify the line at the top of
<i>reportlab/pdfbase/pdfdoc.py</i> to switch it over.  Otherwise, you can
probably just ignore this argument completely and never pass it.  For all TTF
and the commonly-used CID fonts, the encoding you pass in here is ignored,
since the reportlab library itself knows the right encodings in those
cases.""")

disc("""The demo script $reportlab/demos/stdfonts.py$
will print out two test documents showing all code points
in all fonts, so you can look up characters.  Special
characters can be inserted into string commands with
the usual Python escape sequences; for example \\101 = 'A'.""")

disc("""The $verbosity$ argument determines how much log
information is printed.  By default, it is zero to assist
applications which want to capture PDF from standard output.
With a value of 1, you will get a confirmation message
each time a document is generated.  Higher numbers may
give more output in future.""")

disc("""The $encrypt$ argument determines if and how the document is encrypted.
By default, the document is not encrypted.
If $encrypt$ is a string object, it is used as the user password for the pdf.
If $encrypt$ is an instance of $reportlab.lib.pdfencrypt.StandardEncryption$, this object is
used to encrypt the pdf. This allows more finegrained control over the encryption settings.
Encryption is covered in more detail in Chapter 4.""")

todo("to do - all the info functions and other non-drawing stuff")
todo("""Cover all constructor arguments, and setAuthor etc.""")

heading2("Drawing Operations")
disc("""
Suppose the $hello$ function referenced above is implemented as
follows (we will not explain each of the operations in detail
yet).
""")

eg(examples.testhello)

disc("""
Examining this code notice that there are essentially two types
of operations performed using a canvas.  The first type draws something
on the page such as a text string or a rectangle or a line.  The second
type changes the state of the canvas such as
changing the current fill or stroke color or changing the current font
type and size.
""")

disc("""
If we imagine the program as a painter working on
the canvas the "draw" operations apply paint to the canvas using
the current set of tools (colors, line styles, fonts, etcetera)
and the "state change" operations change one of the current tools
(changing the fill color from whatever it was to blue, or changing
the current font to $Times-Roman$ in 15 points, for example).
""")

disc("""
The document generated by the "hello world" program listed above would contain
the following graphics.
""")

illust(examples.hello, '"Hello World" in pdfgen')

heading3("About the demos in this document")

disc("""
This document contains demonstrations of the code discussed like the one shown
in the rectangle above.  These demos are drawn on a "tiny page" embedded
within the real pages of the guide.  The tiny pages are %s inches wide
and %s inches tall. The demo displays show the actual output of the demo code.
For convenience the size of the output has been reduced slightly.
""" % (examplefunctionxinches, examplefunctionyinches))

heading2('The tools: the "draw" operations')

disc("""
This section briefly lists the tools available to the program
for painting information onto a page using the canvas interface.
These will be discussed in detail in later sections.  They are listed
here for easy reference and for summary purposes.
""")

heading3("Line methods")

eg("""canvas.line(x1,y1,x2,y2)""")
eg("""canvas.lines(linelist)""")

disc("""
The line methods draw straight line segments on the canvas.
""")

heading3("Shape methods")

eg("""canvas.grid(xlist, ylist) """)
eg("""canvas.bezier(x1, y1, x2, y2, x3, y3, x4, y4)""")
eg("""canvas.arc(x1,y1,x2,y2) """)
eg("""canvas.rect(x, y, width, height, stroke=1, fill=0) """)
eg("""canvas.ellipse(x1,y1, x2,y2, stroke=1, fill=0)""")
eg("""canvas.wedge(x1,y1, x2,y2, startAng, extent, stroke=1, fill=0) """)
eg("""canvas.circle(x_cen, y_cen, r, stroke=1, fill=0)""")
eg("""canvas.roundRect(x, y, width, height, radius, stroke=1, fill=0) """)

disc("""
The shape methods draw common complex shapes on the canvas.
""")

heading3("String drawing methods")

eg("""canvas.drawString(x, y, text):""")
eg("""canvas.drawRightString(x, y, text) """)
eg("""canvas.drawCentredString(x, y, text)""")

disc("""
The draw string methods draw single lines of text on the canvas.
""")

heading3("The text object methods")
eg("""textobject = canvas.beginText(x, y) """)
eg("""canvas.drawText(textobject) """)

disc("""
Text objects are used to format text in ways that
are not supported directly by the $canvas$ interface.
A program creates a text object from the $canvas$ using $beginText$
and then formats text by invoking $textobject$ methods.
Finally the $textobject$ is drawn onto the canvas using
$drawText$.
""")

heading3("The path object methods")

eg("""path = canvas.beginPath() """)
eg("""canvas.drawPath(path, stroke=1, fill=0) """)
eg("""canvas.clipPath(path, stroke=1, fill=0) """)

disc("""
Path objects are similar to text objects: they provide dedicated control
for performing complex graphical drawing not directly provided by the
canvas interface.  A program creates a path object using $beginPath$
populates the path with graphics using the methods of the path object
and then draws the path on the canvas using $drawPath$.""")

disc("""It is also possible
to use a path as a "clipping region" using the $clipPath$ method -- for example a circular path
can be used to clip away the outer parts of a rectangular image leaving
only a circular part of the image visible on the page.
""")

heading3("Image methods")
pencilnote()
disc("""
You need the Python Imaging Library (PIL) to use images with the ReportLab package.
Examnples of the techniques below can be found by running the script $test_pdfgen_general.py$
in our $tests$ subdirectory and looking at page 7 of the output.
""")

disc("""
There are two similar-sounding ways to draw images.  The preferred one is
the $drawImage$ method.  This implements a caching system so you can
define an image once and draw it many times; it will only be
stored once in the PDF file.  $drawImage$ also exposes one advanced parameter,
a transparency mask, and will expose more in future.  The older technique,
$drawInlineImage$, stores bitmaps within the page stream and is thus very
inefficient if you use the same image more than once in a document; but can result
in PDFs which render faster if the images are very small and not repeated. We'll
discuss the oldest one first:
""")

eg("""canvas.drawInlineImage(self, image, x,y, width=None,height=None) """)

disc("""
The $drawInlineImage$ method places an image on the canvas.  The $image$
parameter may be either a PIL Image object or an image filename.  Many common
file formats are accepted including GIF and JPEG.  It returns the size of the actual
image in pixels as a (width, height) tuple.
""")

eg("""canvas.drawImage(self, image, x,y, width=None,height=None,mask=None) """)
disc("""
The arguments and return value work as for $drawInlineImage$.  However, we use a caching
system; a given image will only be stored the first time it is used, and just referenced
on subsequent use.  If you supply a filename, it assumes that the same filename
means the same image.  If you supply a PIL image, it tests if the content
has actually changed before re-embedding.""")

disc("""
The $mask$ parameter lets you create transparent images.  It takes 6 numbers
and defines the range of RGB values which will be masked out or treated as
transparent. For example with [0,2,40,42,136,139], it will mask out any pixels
with a Red value from 0 or 1, Green from 40 or 41 and Blue of  136, 137 or 138
(on a scale of 0-255). It's currently your job to know which color is the
'transparent' or background one.""")

disc("""PDF allows for many image features and we will expose more of the over
time, probably with extra keyword arguments to $drawImage$.""")

heading3("Ending a page")

eg("""canvas.showPage()""")

disc("""The $showPage$ method finishes the current page.  All additional drawing will
be done on another page.""")

pencilnote()

disc("""Warning!  All state changes (font changes, color settings, geometry transforms, etcetera)
are FORGOTTEN when you advance to a new page in $pdfgen$.  Any state settings you wish to preserve
must be set up again before the program proceeds with drawing!""")

heading2('The toolbox: the "state change" operations')

disc("""
This section briefly lists the ways to switch the tools used by the
program
for painting information onto a page using the $canvas$ interface.
These too will be discussed in detail in later sections.
""")

heading3("Changing Colors")
eg("""canvas.setFillColorCMYK(c, m, y, k) """)
eg("""canvas.setStrikeColorCMYK(c, m, y, k) """)
eg("""canvas.setFillColorRGB(r, g, b) """)
eg("""canvas.setStrokeColorRGB(r, g, b) """)
eg("""canvas.setFillColor(acolor) """)
eg("""canvas.setStrokeColor(acolor) """)
eg("""canvas.setFillGray(gray) """)
eg("""canvas.setStrokeGray(gray) """)

disc("""
PDF supports three different color models: gray level, additive (red/green/blue or RGB), and
subtractive with darkness parameter (cyan/magenta/yellow/darkness or CMYK).
The ReportLab packages also provide named colors such as $lawngreen$.  There are two
basic color parameters in the graphics state: the $Fill$ color for the interior of graphic
figures and the $Stroke$ color for the boundary of graphic figures.  The above methods
support setting the fill or stroke color using any of the four color specifications.
""")

heading3("Changing Fonts")
eg("""canvas.setFont(psfontname, size, leading = None) """)

disc("""
The $setFont$ method changes the current text font to a given type and size.
The $leading$ parameter specifies the distance down to move when advancing from
one text line to the next.
""")

heading3("Changing Graphical Line Styles")

eg("""canvas.setLineWidth(width) """)
eg("""canvas.setLineCap(mode) """)
eg("""canvas.setLineJoin(mode) """)
eg("""canvas.setMiterLimit(limit) """)
eg("""canvas.setDash(self, array=[], phase=0) """)

disc("""
Lines drawn in PDF can be presented in a number of graphical styles.
Lines can have different widths, they can end in differing cap styles,
they can meet in different join styles, and they can be continuous or
they can be dotted or dashed.  The above methods adjust these various parameters.""")

heading3("Changing Geometry")

eg("""canvas.setPageSize(pair) """)
eg("""canvas.transform(a,b,c,d,e,f): """)
eg("""canvas.translate(dx, dy) """)
eg("""canvas.scale(x, y) """)
eg("""canvas.rotate(theta) """)
eg("""canvas.skew(alpha, beta) """)

disc("""
All PDF drawings fit into a specified page size.  Elements drawn outside of the specified
page size are not visible.  Furthermore all drawn elements are passed through an affine
transformation which may adjust their location and/or distort their appearence.  The
$setPageSize$ method adjusts the current page size.  The $transform$, $translate$, $scale$,
$rotate$, and $skew$ methods add additional transformations to the current transformation.
It is important to remember that these transformations are <i>incremental</i> -- a new
transform modifies the current transform (but does not replace it).
""")

heading3("State control")

eg("""canvas.saveState() """)
eg("""canvas.restoreState() """)

disc("""
Very often it is important to save the current font, graphics transform, line styles and
other graphics state in order to restore them later. The $saveState$ method marks the
current graphics state for later restoration by a matching $restoreState$.  Note that
the save and restore method invokation must match -- a restore call restores the state to
the most recently saved state which hasn't been restored yet.
You cannot save the state on one page and restore
it on the next, however -- no state is preserved between pages.""")

heading2("Other $canvas$ methods.")

disc("""
Not all methods of the $canvas$ object fit into the "tool" or "toolbox"
categories.  Below are some of the misfits, included here for completeness.
""")

eg("""
 canvas.setAuthor()
 canvas.addOutlineEntry(title, key, level=0, closed=None)
 canvas.setTitle(title)
 canvas.setSubject(subj)
 canvas.pageHasData()
 canvas.showOutline()
 canvas.bookmarkPage(name)
 canvas.bookmarkHorizontalAbsolute(name, yhorizontal)
 canvas.doForm()
 canvas.beginForm(name, lowerx=0, lowery=0, upperx=None, uppery=None)
 canvas.endForm()
 canvas.linkAbsolute(contents, destinationname, Rect=None, addtopage=1, name=None, **kw)
 canvas.linkRect(contents, destinationname, Rect=None, addtopage=1, relative=1, name=None, **kw)
 canvas.getPageNumber()
 canvas.addLiteral()
 canvas.getAvailableFonts()
 canvas.stringWidth(self, text, fontName, fontSize, encoding=None)
 canvas.setPageCompression(onoff=1)
 canvas.setPageTransition(self, effectname=None, duration=1,
                        direction=0,dimension='H',motion='I')
""")


heading2('Coordinates (default user space)')

disc("""
By default locations on a page are identified by a pair of numbers.
For example the pair $(4.5*inch, 1*inch)$ identifies the location
found on the page by starting at the lower left corner and moving to
the right 4.5 inches and up one inch.
""")

disc("""For example, the following function draws
a number of elements on a $canvas$.""")

eg(examples.testcoords)

disc("""In the default user space the "origin" ^(0,0)^ point is at the lower
left corner.  Executing the $coords$ function in the default user space
(for the "demo minipage") we obtain the following.""")

illust(examples.coords, 'The Coordinate System')

heading3("Moving the origin: the $translate$ method")

disc("""Often it is useful to "move the origin" to a new point off
the lower left corner.  The $canvas.translate(^x,y^)$ method moves the origin
for the current page to the point currently identified by ^(x,y)^.""")

disc("""For example the following translate function first moves
the origin before drawing the same objects as shown above.""")

eg(examples.testtranslate)

disc("""This produces the following.""")

illust(examples.translate, "Moving the origin: the $translate$ method")


#illust(NOP) # execute some code

pencilnote()


disc("""
<i>Note:</i> As illustrated in the example it is perfectly possible to draw objects
or parts of objects "off the page".
In particular a common confusing bug is a translation operation that translates the
entire drawing off the visible area of the page.  If a program produces a blank page
it is possible that all the drawn objects are off the page.
""")

heading3("Shrinking and growing: the scale operation")

disc("""Another important operation is scaling.  The scaling operation $canvas.scale(^dx,dy^)$
stretches or shrinks the ^x^ and ^y^ dimensions by the ^dx^, ^dy^ factors respectively.  Often
^dx^ and ^dy^ are the same -- for example to reduce a drawing by half in all dimensions use
$dx = dy = 0.5$.  However for the purposes of illustration we show an example where
$dx$ and $dy$ are different.
""")

eg(examples.testscale)

disc("""This produces a "short and fat" reduced version of the previously displayed operations.""")

illust(examples.scale, "Scaling the coordinate system")


#illust(NOP) # execute some code

pencilnote()


disc("""<i>Note:</i> scaling may also move objects or parts of objects off the page,
or may cause objects to "shrink to nothing." """)

disc("""Scaling and translation can be combined, but the order of the
operations are important.""")

eg(examples.testscaletranslate)

disc("""This example function first saves the current $canvas$ state
and then does a $scale$ followed by a $translate$.  Afterward the function
restores the state (effectively removing the effects of the scaling and
translation) and then does the <i>same</i> operations in a different order.
Observe the effect below.""")

illust(examples.scaletranslate, "Scaling and Translating")


#illust(NOP) # execute some code

pencilnote()


disc("""<em>Note:</em> scaling shrinks or grows everything including line widths
so using the canvas.scale method to render a microscopic drawing in
scaled microscopic units
may produce a blob (because all line widths will get expanded a huge amount).
Also rendering an aircraft wing in meters scaled to centimeters may cause the lines
to shrink to the point where they disappear.  For engineering or scientific purposes
such as these scale and translate
the units externally before rendering them using the canvas.""")

heading3("Saving and restoring the $canvas$ state: $saveState$ and $restoreState$")

disc("""
The $scaletranslate$ function used an important feature of the $canvas$ object:
the ability to save and restore the current parameters of the $canvas$.
By enclosing a sequence of operations in a matching pair of $canvas.saveState()$
an $canvas.restoreState()$ operations all changes of font, color, line style,
scaling, translation, or other aspects of the $canvas$ graphics state can be
restored to the state at the point of the $saveState()$.  Remember that the save/restore
calls must match: a stray save or restore operation may cause unexpected
and undesirable behavior.  Also, remember that <i>no</i> $canvas$ state is
preserved across page breaks, and the save/restore mechanism does not work
across page breaks.
""")

heading3("Mirror image")

disc("""
It is interesting although perhaps not terribly useful to note that
scale factors can be negative.  For example the following function
""")

eg(examples.testmirror)

disc("""
creates a mirror image of the elements drawn by the $coord$ function.
""")

illust(examples.mirror, "Mirror Images")

disc("""
Notice that the text strings are painted backwards.
""")

heading2("Colors")
disc("""
There are generally two types of colors used in PDF depending on the media where
the PDF will be used. The most commonly known screen colors model RGB can be used
in PDF, however in professional printing another color model CMYK is mainly used 
which gives more control over how inks are applied to paper. More on these color
models below.
""")

heading3("RGB Colors")
disc("""
The $RGB$ or additive color representation follows the way a computer
screen adds different levels of the red, green, and blue light to make
any color in between, where white is formed by turning all three lights on full
($1,1,1$).
""")

disc("""
There are three ways to specify RGB colors in $pdfgen$: by name (using the $color$
module, by red/green/blue (additive, $RGB$) value, or by gray level.
The $colors$ function below exercises each of the four methods.
""")

eg(examples.testRGBcolors)
illust(examples.colorsRGB, "RGB Color Models")

heading4("RGB Color Transparency")

disc("""
Objects may be painted over other objects to good effect in $pdfgen$.  Generally
There are two modes of handling objects that overlap in space, the default objects 
in the top layer will hide any part of other objects that falls underneath it. If you
need transparency you got two choices:
""")

disc("""
1. If your document is intended to be printed in a professional way and you are 
working in CMYK color space then you can use overPrint. In overPrinting the colors
physically mix in the printer and thus a new color is obtained. By default a 
knockout will be applied and only top object appears. Read the CMYK section
if this is what you intend to use.
""")

disc("""
2. If your document is intended for screen output and you are using RGB colors 
then you can set an alpha value, where alpha is the opacity value of the color.
The default alpha value is $1$ (fully opaque) and you can use any real number
value in the range 0-1.
""")

disc("""
Alpha transparency ($alpha$) is similar to overprint but works in RGB color space
this example below demonstrates the alpha funtionality. Refer to our website
http://www.reportlab.com/snippets/ and look for snippets of overPrint and alpha
to see the code that generates the graph below.
""")

eg(examples.testalpha)
illust(examples.alpha, "Alpha example")

heading3("CMYK Colors")
disc("""
The $CMYK$ or subtractive method follows the way a printer
mixes three pigments (cyan, magenta, and yellow) to form colors.
Because mixing chemicals is more difficult than combining light there
is a fourth parameter for darkness.  For example a chemical
combination of the $CMY$ pigments generally never makes a perfect
black -- instead producing a muddy color -- so, to get black printers
don not use the $CMY$ pigments but use a direct black ink.  Because
$CMYK$ maps more directly to the way printer hardware works it may
be the case that colors specified in $CMYK$ will provide better fidelity
and better control when printed.
""")

disc("""
There are two ways of representing CMYK Color: each color can be represented either
by a real value between 0 and 1, or integer value between 0 and 100. Depending
on your preference you can either use CMYKColor (for real values) or PCMYKColor ( for 
integer values). 0 means 'no ink', so printing on white papers gives you white. 1 (or 100
if you use PCMYKColor) means 'the maximum amount of ink'. e.g. CMYKColor(0,0,0,1) is black,
CMYKColor(0,0,0,0) means 'no ink', and CMYKColor(0.5,0,0,0) means 50 percent cyan color.
""")
eg(examples.testCMYKcolors)
illust(examples.colorsCMYK, "CMYK Color Models")

heading2("Color space checking")
disc("""The $enforceColorSpace$ argument of the canvas is used to enforce the consistency
of the colour model used in a document. It accepts these values: CMYK, RGB, SEP, SEP_BLACK,
SEP_CMYK. 'SEP' refers to named color separations such as Pantone spot colors - these can
be mixed with CMYK or RGB according to the parameter used.  The default is 'MIXED' which
allows you to use colors from any color space.  An exception is raised if any colors used
are not convertible to the specified model, e.g. rgb and cmyk (more information in
test_pdfgen_general). This approach doesn't check external images included in document.
""")

heading2("Color Overprinting")

disc("""
When two CMYK colored objects overlap in printing, then either the object 'on top'
will knock out the color of the the one underneath it, or the colors of the two
objects will mix in the overlapped area.
This behaviour can be set using the property $overPrint$.
""")

disc("""
The $overPrint$ function will cause ovelapping areas of color to mix. In the example
below, the colors of the rectangles on the left should appear mixed where they overlap
- If you can't see this effect then you may need to enable the 'overprint preview'
option in your PDF viewing software.  Some PDF viewers such as $evince$ do not
support overPrint; however Adobe Acrobat Reader does support it.
""")
illust(examples.overPrint, "overPrint example")

heading3("Other Object Order of Printing Examples")

disc("""
The word "SPUMONI" is painted in white over the colored rectangles,
with the apparent effect of "removing" the color inside the body of
the word.
""")

eg(examples.testspumoni)
illust(examples.spumoni, "Painting over colors")

disc("""
The last letters of the word are not visible because the default $canvas$
background is white and painting white letters over a white background
leaves no visible effect.
""")

disc("""
This method of building up complex paintings in layers can be done
in very many layers in $pdfgen$ -- there are fewer physical limitations
than there are when dealing with physical paints.
""")

eg(examples.testspumoni2)

disc("""
The $spumoni2$ function layers an ice cream cone over the
$spumoni$ drawing.  Note that different parts of the cone
and scoops layer over eachother as well.
""")
illust(examples.spumoni2, "building up a drawing in layers")

heading2('Standard fonts and text objects')

disc("""
Text may be drawn in many different colors, fonts, and sizes in $pdfgen$.
The $textsize$ function demonstrates how to change the color and font and
size of text and how to place text on the page.
""")

eg(examples.testtextsize)

disc("""
The $textsize$ function generates the following page.
""")

illust(examples.textsize, "text in different fonts and sizes")

disc("""
A number of different fonts are always available in $pdfgen$.
""")

eg(examples.testfonts)

disc("""
The $fonts$ function lists the fonts that are always available.
These don't need to be stored in a PDF document, since they
are guaranteed to be present in Acrobat Reader.
""")

illust(examples.fonts, "the 14 standard fonts")

disc("""The Symbol and ZapfDingbats fonts cannot display properly because the required glyphs are not present in those fonts.""")

disc("""
For information on how to use arbitrary fonts, see the next chapter.
""")


heading2("Text object methods")

disc("""
For the dedicated presentation of text in a PDF document, use a text object.
The text object interface provides detailed control of text layout parameters
not available directly at the $canvas$ level.  In addition, it results in smaller
PDF that will render faster than many separate calls to the $drawString$ methods.
""")

eg("""textobject.setTextOrigin(x,y)""")
eg("""textobject.setTextTransform(a,b,c,d,e,f)""")
eg("""textobject.moveCursor(dx, dy) # from start of current LINE""")
eg("""(x,y) = textobject.getCursor()""")
eg("""x = textobject.getX(); y = textobject.getY()""")
eg("""textobject.setFont(psfontname, size, leading = None)""")
eg("""textobject.textOut(text)""")
eg("""textobject.textLine(text='')""")
eg("""textobject.textLines(stuff, trim=1)""")

disc("""
The text object methods shown above relate to basic text geometry.
""")

disc("""
A text object maintains a text cursor which moves about the page when
text is drawn.  For example the $setTextOrigin$ places the cursor
in a known position and the $textLine$ and $textLines$ methods move
the text cursor down past the lines that have been missing.
""")

eg(examples.testcursormoves1)

disc("""
The $cursormoves$ function relies on the automatic
movement of the text cursor for placing text after the origin
has been set.
""")

illust(examples.cursormoves1, "How the text cursor moves")

disc("""
It is also possible to control the movement of the cursor
more explicitly by using the $moveCursor$ method (which moves
the cursor as an offset from the start of the current <i>line</i>
NOT the current cursor, and which also has positive ^y^ offsets
move <i>down</i> (in contrast to the normal geometry where
positive ^y^ usually moves up.
""")

eg(examples.testcursormoves2)

disc("""
Here the $textOut$ does not move the down a line in contrast
to the $textLine$ function which does move down.
""")

illust(examples.cursormoves2, "How the text cursor moves again")

heading3("Character Spacing")

eg("""textobject.setCharSpace(charSpace)""")

disc("""The $setCharSpace$ method adjusts one of the parameters of text -- the inter-character
spacing.""")

eg(examples.testcharspace)

disc("""The
$charspace$ function exercises various spacing settings.
It produces the following page.""")

illust(examples.charspace, "Adjusting inter-character spacing")

heading3("Word Spacing")

eg("""textobject.setWordSpace(wordSpace)""")

disc("The $setWordSpace$ method adjusts the space between words.")

eg(examples.testwordspace)

disc("""The $wordspace$ function shows what various word space settings
look like below.""")

illust(examples.wordspace, "Adjusting word spacing")

heading3("Horizontal Scaling")

eg("""textobject.setHorizScale(horizScale)""")

disc("""Lines of text can be stretched or shrunken horizontally by the
$setHorizScale$ method.""")

eg(examples.testhorizontalscale)

disc("""The horizontal scaling parameter ^horizScale^
is given in percentages (with 100 as the default), so the 80 setting
shown below looks skinny.
""")
illust(examples.horizontalscale, "adjusting horizontal text scaling")

heading3("Interline spacing (Leading)")

eg("""textobject.setLeading(leading)""")

disc("""The vertical offset between the point at which one
line starts and where the next starts is called the leading
offset.  The $setLeading$ method adjusts the leading offset.
""")

eg(examples.testleading)

disc("""As shown below if the leading offset is set too small
characters of one line my write over the bottom parts of characters
in the previous line.""")

illust(examples.leading, "adjusting the leading")

heading3("Other text object methods")

eg("""textobject.setTextRenderMode(mode)""")

disc("""The $setTextRenderMode$ method allows text to be used
as a forground for clipping background drawings, for example.""")

eg("""textobject.setRise(rise)""")

disc("""
The $setRise$ method <super>raises</super> or <sub>lowers</sub> text on the line
(for creating superscripts or subscripts, for example).
""")

eg("""textobject.setFillColor(aColor);
textobject.setStrokeColor(self, aColor)
# and similar""")

disc("""
These color change operations change the <font color=darkviolet>color</font> of the text and are otherwise
similar to the color methods for the $canvas$ object.""")

heading2('Paths and Lines')

disc("""Just as textobjects are designed for the dedicated presentation
of text, path objects are designed for the dedicated construction of
graphical figures.  When path objects are drawn onto a $canvas$ they
are drawn as one figure (like a rectangle) and the mode of drawing
for the entire figure can be adjusted: the lines of the figure can
be drawn (stroked) or not; the interior of the figure can be filled or
not; and so forth.""")

disc("""
For example the $star$ function uses a path object
to draw a star
""")

eg(examples.teststar)

disc("""
The $star$ function has been designed to be useful in illustrating
various line style parameters supported by $pdfgen$.
""")

illust(examples.star, "line style parameters")

heading3("Line join settings")

disc("""
The $setLineJoin$ method can adjust whether line segments meet in a point
a square or a rounded vertex.
""")

eg(examples.testjoins)

disc("""
The line join setting is only really of interest for thick lines because
it cannot be seen clearly for thin lines.
""")

illust(examples.joins, "different line join styles")

heading3("Line cap settings")

disc("""The line cap setting, adjusted using the $setLineCap$ method,
determines whether a terminating line
ends in a square exactly at the vertex, a square over the vertex
or a half circle over the vertex.
""")

eg(examples.testcaps)

disc("""The line cap setting, like the line join setting, is only clearly
visible when the lines are thick.""")

illust(examples.caps, "line cap settings")

heading3("Dashes and broken lines")

disc("""
The $setDash$ method allows lines to be broken into dots or dashes.
""")

eg(examples.testdashes)

disc("""
The patterns for the dashes or dots can be in a simple on/off repeating pattern
or they can be specified in a complex repeating pattern.
""")

illust(examples.dashes, "some dash patterns")

heading3("Creating complex figures with path objects")

disc("""
Combinations of lines, curves, arcs and other figures
can be combined into a single figure using path objects.
For example the function shown below constructs two path
objects using lines and curves.
This function will be used later on as part of a
pencil icon construction.
""")

eg(examples.testpenciltip)

disc("""
Note that the interior of the pencil tip is filled
as one object even though it is constructed from
several lines and curves.  The pencil lead is then
drawn over it using a new path object.
""")

illust(examples.penciltip, "a pencil tip")

heading2('Rectangles, circles, ellipses')

disc("""
The $pdfgen$ module supports a number of generally useful shapes
such as rectangles, rounded rectangles, ellipses, and circles.
Each of these figures can be used in path objects or can be drawn
directly on a $canvas$.  For example the $pencil$ function below
draws a pencil icon using rectangles and rounded rectangles with
various fill colors and a few other annotations.
""")

eg(examples.testpencil)

pencilnote()

disc("""
Note that this function is used to create the "margin pencil" to the left.
Also note that the order in which the elements are drawn are important
because, for example, the white rectangles "erase" parts of a black rectangle
and the "tip" paints over part of the yellow rectangle.
""")

illust(examples.pencil, "a whole pencil")

heading2('Bezier curves')

disc("""
Programs that wish to construct figures with curving borders
generally use Bezier curves to form the borders.
""")

eg(examples.testbezier)

disc("""
A Bezier curve is specified by four control points
$(x1,y1)$, $(x2,y2)$, $(x3,y3)$, $(x4,y4)$.
The curve starts at $(x1,y1)$ and ends at $(x4,y4)$
and the line segment from $(x1,y1)$ to $(x2,y2)$
and the line segment from $(x3,y3)$ to $(x4,y4)$
both form tangents to the curve.  Furthermore the
curve is entirely contained in the convex figure with vertices
at the control points.
""")

illust(examples.bezier, "basic bezier curves")

disc("""
The drawing above (the output of $testbezier$) shows
a bezier curves, the tangent lines defined by the control points
and the convex figure with vertices at the control points.
""")

heading3("Smoothly joining bezier curve sequences")

disc("""
It is often useful to join several bezier curves to form a
single smooth curve.  To construct a larger smooth curve from
several bezier curves make sure that the tangent lines to adjacent
bezier curves that join at a control point lie on the same line.
""")

eg(examples.testbezier2)

disc("""
The figure created by $testbezier2$ describes a smooth
complex curve because adjacent tangent lines "line up" as
illustrated below.
""")

illust(examples.bezier2, "bezier curves")

heading2("Path object methods")

disc("""
Path objects build complex graphical figures by setting
the "pen" or "brush" at a start point on the canvas and drawing
lines or curves to additional points on the canvas.  Most operations
apply paint on the canvas starting at the end point of the last
operation and leave the brush at a new end point.
""")

eg("""pathobject.moveTo(x,y)""")

disc("""
The $moveTo$ method lifts the brush (ending any current sequence
of lines or curves if there is one) and replaces the brush at the
new ^(x,y)^ location on the canvas to start a new path sequence.
""")

eg("""pathobject.lineTo(x,y)""")

disc("""
The $lineTo$ method paints straight line segment from the current brush
location to the new ^(x,y)^ location.
""")

eg("""pathobject.curveTo(x1, y1, x2, y2, x3, y3) """)

disc("""
The $curveTo$ method starts painting a Bezier curve beginning at
the current brush location, using ^(x1,y1)^, ^(x2,y2)^, and ^(x3,y3)^
as the other three control points, leaving the brush on ^(x3,y3)^.
""")

eg("""pathobject.arc(x1,y1, x2,y2, startAng=0, extent=90) """)

eg("""pathobject.arcTo(x1,y1, x2,y2, startAng=0, extent=90) """)

disc("""
The $arc$ and $arcTo$ methods paint partial ellipses.  The $arc$ method first "lifts the brush"
and starts a new shape sequence.  The $arcTo$ method joins the start of
the partial ellipse to the current
shape sequence by line segment before drawing the partial ellipse.  The points
^(x1,y1)^ and ^(x2,y2)^ define opposite corner points of a rectangle enclosing
the ellipse.  The $startAng$ is an angle (in degrees) specifying where to begin
the partial ellipse where the 0 angle is the midpoint of the right border of the enclosing
rectangle (when ^(x1,y1)^ is the lower left corner and ^(x2,y2)^ is the upper
right corner).  The $extent$ is the angle in degrees to traverse on the ellipse.
""")

eg(examples.testarcs)

disc("""The $arcs$ function above exercises the two partial ellipse methods.
It produces the following drawing.""")

illust(examples.arcs, "arcs in path objects")

eg("""pathobject.rect(x, y, width, height) """)

disc("""The $rect$ method draws a rectangle with lower left corner
at ^(x,y)^ of the specified ^width^ and ^height^.""")

eg("""pathobject.ellipse(x, y, width, height)""")

disc("""The $ellipse$ method
draws an ellipse enclosed in the rectange with lower left corner
at ^(x,y)^ of the specified ^width^ and ^height^.
""")

eg("""pathobject.circle(x_cen, y_cen, r) """)

disc("""The $circle$ method
draws a circle centered at ^(x_cen, y_cen)^ with radius ^r^.
""")

eg(examples.testvariousshapes)

disc("""
The $variousshapes$ function above shows a rectangle, circle and ellipse
placed in a frame of reference grid.
""")

illust(examples.variousshapes, "rectangles, circles, ellipses in path objects")

eg("""pathobject.close() """)

disc("""
The $close$ method closes the current graphical figure
by painting a line segment from the last point of the figure
to the starting point of the figure (the the most
recent point where the brush was placed on the paper by $moveTo$
or $arc$ or other placement operations).
""")

eg(examples.testclosingfigures)

disc("""
The $closingfigures$ function illustrates the
effect of closing or not closing figures including a line
segment and a partial ellipse.
""")

illust(examples.closingfigures, "closing and not closing pathobject figures")

disc("""
Closing or not closing graphical figures effects only the stroked outline
of a figure, not the filling of the figure as illustrated above.
""")


disc("""
For a more extensive example of drawing using a path object
examine the $hand$ function.
""")

eg(examples.testhand)

disc("""
In debug mode (the default) the $hand$ function shows the tangent line segments
to the bezier curves used to compose the figure.  Note that where the segments
line up the curves join smoothly, but where they do not line up the curves show
a "sharp edge".
""")

illust(examples.hand, "an outline of a hand using bezier curves")

disc("""
Used in non-debug mode the $hand$ function only shows the
Bezier curves.  With the $fill$ parameter set the figure is
filled using the current fill color.
""")

eg(examples.testhand2)

disc("""
Note that the "stroking" of the border draws over the interior fill where
they overlap.
""")

illust(examples.hand2, "the finished hand, filled")



heading2("Further Reading: The ReportLab Graphics Library")

disc("""
So far the graphics we have seen were created on a fairly low level.
It should be noted, though, that there is another way of creating
much more sophisticated graphics using the dedicated
high-level <i>ReportLab Graphics Library</i>.
""")

disc("""
It can be used to produce high-quality, platform-independant,
reusable graphics for different output formats (vector and bitmap)
like PDF, EPS, SVG, JPG and PNG.
""")

disc("""
A more thorough description of its philsophy and features is
now covered in Chapter 11 of this document, <i>Graphics</i>, which 
contains information about the existing components and
how to create customized ones.
""")

disc("""
Chapter 11 also contains details of the ReportLab 
charting package and its components (labels, axes, legends and
different types of charts like bar, line and pie charts) that
builds directly on the graphics library.
""")


##### FILL THEM IN