├── LICENSE
├── Makefile
├── README
├── doc
├── .gitignore
└── overview.edoc
├── ebin
└── .gitignore
├── erlguten
├── priv
├── font_locations
├── fonts
│ ├── README.txt
│ ├── adobe
│ │ ├── courier
│ │ │ ├── pcrb8a.afm
│ │ │ ├── pcrbo8a.afm
│ │ │ ├── pcrr8a.afm
│ │ │ └── pcrro8a.afm
│ │ ├── helvetic
│ │ │ ├── phvb8a.afm
│ │ │ ├── phvbo8a.afm
│ │ │ ├── phvr8a.afm
│ │ │ └── phvro8a.afm
│ │ ├── symbol
│ │ │ └── psyr.afm
│ │ ├── times
│ │ │ ├── ptmb8a.afm
│ │ │ ├── ptmbi8a.afm
│ │ │ ├── ptmr8a.afm
│ │ │ └── ptmri8a.afm
│ │ └── zapfding
│ │ │ └── pzdr.afm
│ ├── gocm
│ │ ├── GOCM____.TXT
│ │ ├── ase
│ │ │ ├── GOCMASE_.CFG
│ │ │ ├── GOCMASE_.INF
│ │ │ ├── GOCMASE_.afm
│ │ │ ├── GOCMASE_.pfb
│ │ │ └── GOCMASE_.pfm
│ │ └── seq
│ │ │ ├── GOCMSEQ_.CFG
│ │ │ ├── GOCMSEQ_.INF
│ │ │ ├── GOCMSEQ_.afm
│ │ │ ├── GOCMSEQ_.pfb
│ │ │ └── GOCMSEQ_.pfm
│ ├── ocr
│ │ ├── file_id.diz
│ │ ├── ocra_num.ttf
│ │ ├── ocrad___.afm
│ │ ├── ocrad___.pfb
│ │ ├── ocrad___.pfm
│ │ ├── ocrb_num.ttf
│ │ ├── ocrbd___.afm
│ │ ├── ocrbd___.pfb
│ │ ├── ocrbd___.pfm
│ │ └── readme.txt
│ └── vsecret
│ │ ├── README
│ │ ├── V-SECRET.BMA
│ │ ├── V-SECRET.afm
│ │ └── V-SECRET.pfb
├── hyphenation
│ ├── README.txt
│ ├── dk_merged.tex
│ ├── hyph_da_DK.dic
│ ├── hyph_en_GB.dic
│ ├── hyph_fi_FI.dic
│ ├── hyph_nb_NO.dic
│ ├── hyph_sv_SE.dic
│ ├── original_tex
│ │ ├── dkcommon.tex
│ │ ├── dkhyph.tex
│ │ ├── dkspecial.tex
│ │ ├── fihyph.tex
│ │ ├── nohyphbx.tex
│ │ ├── svhyph.tex
│ │ └── ukhyphen.tex
│ ├── tb87nemeth.pdf
│ └── ukhyphen.tex
└── src
│ ├── .gitignore
│ └── README.txt
├── src
├── eg.hrl
├── eg_afm.erl
├── eg_convert.erl
├── eg_embed.erl
├── eg_font_server.erl
├── eg_hyphenate.erl
├── eg_lib.erl
├── eg_line_break.erl
├── eg_mk_hyphen.erl
├── eg_pdf.erl
├── eg_pdf_analyse.erl
├── eg_pdf_annot.erl
├── eg_pdf_assemble.erl
├── eg_pdf_image.erl
├── eg_pdf_lib.erl
├── eg_pdf_obj.erl
├── eg_pdf_op.erl
├── eg_pdf_page.erl
├── eg_richText.erl
├── eg_richText2pdf.erl
├── eg_xml2richText.erl
├── eg_xml_lite.erl
├── eg_xml_tokenise.erl
├── erlguten.app.src
└── erlguten.erl
├── test
├── .gitignore
├── content1.con
├── ebutik.jpg
├── eg_test1.erl
├── eg_test2.erl
├── eg_test3.erl
├── eg_test4.erl
├── eg_test5.erl
├── eg_test6.erl
├── eg_test7.erl
├── erlguten
├── galley_001.gal
├── galley_002.gal
├── joenew.jpg
├── kd_test1.erl
├── template1.tem
├── template_001.tem
├── test1.map
├── test1.pdf
├── test1.xml
├── test2.xml
├── tmo_doc.erl
├── tmo_doc.xml
└── tmobile.jpg
└── vsn.mk
/LICENSE:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/LICENSE
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | include vsn.mk
2 | APPNAME=erlguten
3 | DOC_OPTS={def,{version,\"$(VSN)\"}}
4 | ERLGUTEN=./erlguten
5 | ERL=erl
6 | ERLC=erlc
7 | ERLC_FLAGS=+debug_info +nowarn_unused_vars
8 | PERL=perl
9 | APPSCRIPT = '$$vsn=shift; $$mods=""; while(@ARGV){ $$_=shift; s/^([A-Z].*)$$/\'\''$$1\'\''/; $$mods.=", " if $$mods; $$mods .= $$_; } while(<>) { s/%VSN%/$$vsn/; s/"%MODULES%"/$$mods/; print; }'
10 |
11 | HYPHEN_DICTS = $(wildcard priv/hyphenation/hyph_*.dic)
12 | HYPHEN_SOURCES = $(HYPHEN_DICTS:priv/hyphenation/hyph_%.dic=priv/src/eg_hyphen_rules_%.erl)
13 | .PRECIOUS: $(HYPHEN_SOURCES)
14 | HYPHEN_OBJECTS = $(HYPHEN_SOURCES:priv/src/%.erl=ebin/%.beam)
15 |
16 | ERL_SOURCES = $(wildcard src/*.erl)
17 | MODULES = $(ERL_SOURCES:src/%.erl=%)
18 | ERL_OBJECTS = $(ERL_SOURCES:src/%.erl=ebin/%.beam) \
19 | ebin/eg_font_map.beam $(HYPHEN_OBJECTS)
20 |
21 | TEST_SOURCES = $(wildcard test/*.erl)
22 | TEST_PDFS = $(TEST_SOURCES:test/%.erl=test/%.pdf)
23 | TEST_OBJECTS = $(TEST_SOURCES:test/%.erl=test/%.beam)
24 | .PRECIOUS: $(TEST_OBJECTS)
25 |
26 | .PHONY: all test doc
27 |
28 | all: $(ERL_OBJECTS) app
29 |
30 | test: all $(TEST_PDFS)
31 |
32 | docs: doc
33 | doc: doc/index.html
34 |
35 | app: ebin/$(APPNAME).app
36 |
37 | clean:
38 | -rm -f $(ERL_OBJECTS) ebin/$(APPNAME).app
39 | -cd priv/src && $(MAKE) clean
40 | -rm -f $(TEST_OBJECTS) $(TEST_PDFS)
41 | -rm -f doc/*.html doc/stylesheet.css doc/erlang.png doc/edoc-info
42 |
43 |
44 | doc/index.html: doc/overview.edoc $(ERL_SOURCES)
45 | $(ERL) -noshell -eval "edoc:application($(APPNAME), \".\", [$(DOC_OPTS)])" -s init stop
46 |
47 |
48 | ebin/%.app: src/%.app.src vsn.mk
49 | $(PERL) -e $(APPSCRIPT) "$(VSN)" $(MODULES) < $< > $@
50 |
51 | ebin/%.beam: src/%.erl
52 | $(ERLC) $(ERLC_FLAGS) -o ebin $<
53 |
54 |
55 | # eg_hyphen_rules_*.erl files are found in priv/src/, not src/
56 | ebin/eg_hyphen_rules_%.beam: priv/src/eg_hyphen_rules_%.erl
57 | $(ERLC) $(ERLC_FLAGS) -o ebin $<
58 |
59 | # generate hyphenation modules from .dic files
60 | priv/src/eg_hyphen_rules_%.erl: priv/hyphenation/hyph_%.dic \
61 | ebin/eg_mk_hyphen.beam ebin/eg_lib.beam
62 | $(ERL) -noshell -pa ebin -s eg_mk_hyphen start $* -s init stop
63 |
64 |
65 | # the font mapping is treated specially with its own Makefile, since we
66 | # can't know here how many font source files will be generated by eg_afm
67 | ebin/eg_font_map.beam: priv/src/Makefile
68 | -cd priv/src && $(MAKE)
69 |
70 | priv/src/Makefile: ebin/eg_afm.beam ebin/eg_lib.beam ebin/eg_pdf_op.beam \
71 | priv/font_locations
72 | $(ERL) -noshell -pa ebin -s eg_afm make -s init stop
73 |
74 |
75 | test1.pdf: test1.map galley_001.gal content1.con
76 | $(ERLGUTEN) test1.map
77 |
78 | test2.pdf: test2.xml galley_002.gal
79 | $(ERLGUTEN) test2.xml
80 |
81 | tmo_doc.pdf: tmo_doc.xml
82 |
83 | test/%.pdf: test/%.beam $(ERL_OBJECTS)
84 | cd test && erl -pa . -pa ../ebin -noshell -s $* test -s init stop
85 |
86 | test/%.beam: test/%.erl
87 | $(ERLC) $(ERLC_FLAGS) -o test $<
88 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | 1) Install with make
2 |
3 | 2) Try the command
4 |
5 | make test
6 |
7 | This compiles test/eg_test1.erl, ... test/eg_test7.erl and runs them to
8 | generate test/eg_test1.pdf, ... test/eg_test7.pdf. See these modules
9 | for examples of how to use erlguten from an Erlang program.
10 |
11 | Note: The main module 'erlguten.erl' was intended as a batch interface,
12 | using xml files as input (see test/test1.xml), but it never reached a stable
13 | state and is not fit for use. The shell wrapper script 'erlguten' expects to
14 | use this interface, but doesn't in fact work. Contributions are welcome.
15 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | *.html
2 | edoc-info
3 | erlang.png
4 | stylesheet.css
5 |
--------------------------------------------------------------------------------
/doc/overview.edoc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/doc/overview.edoc
--------------------------------------------------------------------------------
/ebin/.gitignore:
--------------------------------------------------------------------------------
1 | *.beam
2 | erlguten.app
3 |
--------------------------------------------------------------------------------
/erlguten:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | erl -pa ./ebin -s erlguten batch $1 -s init stop
3 |
4 |
--------------------------------------------------------------------------------
/priv/font_locations:
--------------------------------------------------------------------------------
1 | priv/fonts/adobe/courier
2 | priv/fonts/adobe/helvetic
3 | priv/fonts/adobe/symbol
4 | priv/fonts/adobe/times
5 | priv/fonts/adobe/zapfding
6 | priv/fonts/vsecret
7 | priv/fonts/ocr
8 | priv/fonts/gocm/ase
9 |
--------------------------------------------------------------------------------
/priv/fonts/README.txt:
--------------------------------------------------------------------------------
1 | The Adobe AFM files for the base PDF fonts were copied from the TeX Live
2 | distribution. They may be freely distributed.
3 |
4 | The fonts OCR-A-Digits & OCR-B-Digits and Victorias-Secret are only included
5 | here for demo purposes, and for use by Erlguten's test suite. Please refer
6 | to their individual README-files for details on conditions of use.
7 |
--------------------------------------------------------------------------------
/priv/fonts/adobe/symbol/psyr.afm:
--------------------------------------------------------------------------------
1 | StartFontMetrics 2.0
2 | Comment Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.
3 | Comment Creation Date: Wed Jan 17 21:48:26 1990
4 | Comment UniqueID 27004
5 | Comment VMusage 28489 37622
6 | FontName Symbol
7 | FullName Symbol
8 | FamilyName Symbol
9 | Weight Medium
10 | ItalicAngle 0
11 | IsFixedPitch false
12 | FontBBox -180 -293 1090 1010
13 | UnderlinePosition -98
14 | UnderlineThickness 54
15 | Version 001.007
16 | Notice Copyright (c) 1985, 1987, 1989, 1990 Adobe Systems Incorporated. All rights reserved.
17 | EncodingScheme FontSpecific
18 | StartCharMetrics 189
19 | C 32 ; WX 250 ; N space ; B 0 0 0 0 ;
20 | C 33 ; WX 333 ; N exclam ; B 128 -17 240 672 ;
21 | C 34 ; WX 713 ; N universal ; B 31 0 681 705 ;
22 | C 35 ; WX 500 ; N numbersign ; B 20 -16 481 673 ;
23 | C 36 ; WX 549 ; N existential ; B 25 0 478 707 ;
24 | C 37 ; WX 833 ; N percent ; B 63 -36 771 655 ;
25 | C 38 ; WX 778 ; N ampersand ; B 41 -18 750 661 ;
26 | C 39 ; WX 439 ; N suchthat ; B 48 -17 414 500 ;
27 | C 40 ; WX 333 ; N parenleft ; B 53 -191 300 673 ;
28 | C 41 ; WX 333 ; N parenright ; B 30 -191 277 673 ;
29 | C 42 ; WX 500 ; N asteriskmath ; B 65 134 427 551 ;
30 | C 43 ; WX 549 ; N plus ; B 10 0 539 533 ;
31 | C 44 ; WX 250 ; N comma ; B 56 -152 194 104 ;
32 | C 45 ; WX 549 ; N minus ; B 11 233 535 288 ;
33 | C 46 ; WX 250 ; N period ; B 69 -17 181 95 ;
34 | C 47 ; WX 278 ; N slash ; B 0 -18 254 646 ;
35 | C 48 ; WX 500 ; N zero ; B 23 -17 471 685 ;
36 | C 49 ; WX 500 ; N one ; B 117 0 390 673 ;
37 | C 50 ; WX 500 ; N two ; B 25 0 475 686 ;
38 | C 51 ; WX 500 ; N three ; B 39 -17 435 685 ;
39 | C 52 ; WX 500 ; N four ; B 16 0 469 685 ;
40 | C 53 ; WX 500 ; N five ; B 29 -17 443 685 ;
41 | C 54 ; WX 500 ; N six ; B 36 -17 467 685 ;
42 | C 55 ; WX 500 ; N seven ; B 24 -16 448 673 ;
43 | C 56 ; WX 500 ; N eight ; B 54 -18 440 685 ;
44 | C 57 ; WX 500 ; N nine ; B 31 -18 460 685 ;
45 | C 58 ; WX 278 ; N colon ; B 81 -17 193 460 ;
46 | C 59 ; WX 278 ; N semicolon ; B 83 -152 221 460 ;
47 | C 60 ; WX 549 ; N less ; B 26 0 523 522 ;
48 | C 61 ; WX 549 ; N equal ; B 11 141 537 390 ;
49 | C 62 ; WX 549 ; N greater ; B 26 0 523 522 ;
50 | C 63 ; WX 444 ; N question ; B 70 -17 412 686 ;
51 | C 64 ; WX 549 ; N congruent ; B 11 0 537 475 ;
52 | C 65 ; WX 722 ; N Alpha ; B 4 0 684 673 ;
53 | C 66 ; WX 667 ; N Beta ; B 29 0 592 673 ;
54 | C 67 ; WX 722 ; N Chi ; B -9 0 704 673 ;
55 | C 68 ; WX 612 ; N Delta ; B 6 0 608 688 ;
56 | C 69 ; WX 611 ; N Epsilon ; B 32 0 617 673 ;
57 | C 70 ; WX 763 ; N Phi ; B 26 0 741 673 ;
58 | C 71 ; WX 603 ; N Gamma ; B 24 0 609 673 ;
59 | C 72 ; WX 722 ; N Eta ; B 39 0 729 673 ;
60 | C 73 ; WX 333 ; N Iota ; B 32 0 316 673 ;
61 | C 74 ; WX 631 ; N theta1 ; B 18 -18 623 689 ;
62 | C 75 ; WX 722 ; N Kappa ; B 35 0 722 673 ;
63 | C 76 ; WX 686 ; N Lambda ; B 6 0 680 688 ;
64 | C 77 ; WX 889 ; N Mu ; B 28 0 887 673 ;
65 | C 78 ; WX 722 ; N Nu ; B 29 -8 720 673 ;
66 | C 79 ; WX 722 ; N Omicron ; B 41 -17 715 685 ;
67 | C 80 ; WX 768 ; N Pi ; B 25 0 745 673 ;
68 | C 81 ; WX 741 ; N Theta ; B 41 -17 715 685 ;
69 | C 82 ; WX 556 ; N Rho ; B 28 0 563 673 ;
70 | C 83 ; WX 592 ; N Sigma ; B 5 0 589 673 ;
71 | C 84 ; WX 611 ; N Tau ; B 33 0 607 673 ;
72 | C 85 ; WX 690 ; N Upsilon ; B -8 0 694 673 ;
73 | C 86 ; WX 439 ; N sigma1 ; B 40 -233 436 500 ;
74 | C 87 ; WX 768 ; N Omega ; B 34 0 736 688 ;
75 | C 88 ; WX 645 ; N Xi ; B 40 0 599 673 ;
76 | C 89 ; WX 795 ; N Psi ; B 15 0 781 684 ;
77 | C 90 ; WX 611 ; N Zeta ; B 44 0 636 673 ;
78 | C 91 ; WX 333 ; N bracketleft ; B 86 -155 299 674 ;
79 | C 92 ; WX 863 ; N therefore ; B 163 0 701 478 ;
80 | C 93 ; WX 333 ; N bracketright ; B 33 -155 246 674 ;
81 | C 94 ; WX 658 ; N perpendicular ; B 15 0 652 674 ;
82 | C 95 ; WX 500 ; N underscore ; B -2 -252 502 -206 ;
83 | C 96 ; WX 500 ; N radicalex ; B 480 881 1090 917 ;
84 | C 97 ; WX 631 ; N alpha ; B 41 -18 622 500 ;
85 | C 98 ; WX 549 ; N beta ; B 61 -223 515 741 ;
86 | C 99 ; WX 549 ; N chi ; B 12 -231 522 499 ;
87 | C 100 ; WX 494 ; N delta ; B 40 -19 481 740 ;
88 | C 101 ; WX 439 ; N epsilon ; B 22 -19 427 502 ;
89 | C 102 ; WX 521 ; N phi ; B 27 -224 490 671 ;
90 | C 103 ; WX 411 ; N gamma ; B 5 -225 484 499 ;
91 | C 104 ; WX 603 ; N eta ; B 0 -202 527 514 ;
92 | C 105 ; WX 329 ; N iota ; B 0 -17 301 503 ;
93 | C 106 ; WX 603 ; N phi1 ; B 36 -224 587 499 ;
94 | C 107 ; WX 549 ; N kappa ; B 33 0 558 501 ;
95 | C 108 ; WX 549 ; N lambda ; B 24 -17 548 739 ;
96 | C 109 ; WX 576 ; N mu ; B 33 -223 567 500 ;
97 | C 110 ; WX 521 ; N nu ; B -9 -16 475 507 ;
98 | C 111 ; WX 549 ; N omicron ; B 35 -19 501 499 ;
99 | C 112 ; WX 549 ; N pi ; B 10 -19 530 487 ;
100 | C 113 ; WX 521 ; N theta ; B 43 -17 485 690 ;
101 | C 114 ; WX 549 ; N rho ; B 50 -230 490 499 ;
102 | C 115 ; WX 603 ; N sigma ; B 30 -21 588 500 ;
103 | C 116 ; WX 439 ; N tau ; B 10 -19 418 500 ;
104 | C 117 ; WX 576 ; N upsilon ; B 7 -18 535 507 ;
105 | C 118 ; WX 713 ; N omega1 ; B 12 -18 671 583 ;
106 | C 119 ; WX 686 ; N omega ; B 42 -17 684 500 ;
107 | C 120 ; WX 493 ; N xi ; B 27 -224 469 766 ;
108 | C 121 ; WX 686 ; N psi ; B 12 -228 701 500 ;
109 | C 122 ; WX 494 ; N zeta ; B 60 -225 467 756 ;
110 | C 123 ; WX 480 ; N braceleft ; B 58 -183 397 673 ;
111 | C 124 ; WX 200 ; N bar ; B 65 -177 135 673 ;
112 | C 125 ; WX 480 ; N braceright ; B 79 -183 418 673 ;
113 | C 126 ; WX 549 ; N similar ; B 17 203 529 307 ;
114 | C 161 ; WX 620 ; N Upsilon1 ; B -2 0 610 685 ;
115 | C 162 ; WX 247 ; N minute ; B 27 459 228 735 ;
116 | C 163 ; WX 549 ; N lessequal ; B 29 0 526 639 ;
117 | C 164 ; WX 167 ; N fraction ; B -180 -12 340 677 ;
118 | C 165 ; WX 713 ; N infinity ; B 26 124 688 404 ;
119 | C 166 ; WX 500 ; N florin ; B 2 -193 494 686 ;
120 | C 167 ; WX 753 ; N club ; B 86 -26 660 533 ;
121 | C 168 ; WX 753 ; N diamond ; B 142 -36 600 550 ;
122 | C 169 ; WX 753 ; N heart ; B 117 -33 631 532 ;
123 | C 170 ; WX 753 ; N spade ; B 113 -36 629 548 ;
124 | C 171 ; WX 1042 ; N arrowboth ; B 24 -15 1024 511 ;
125 | C 172 ; WX 987 ; N arrowleft ; B 32 -15 942 511 ;
126 | C 173 ; WX 603 ; N arrowup ; B 45 0 571 910 ;
127 | C 174 ; WX 987 ; N arrowright ; B 49 -15 959 511 ;
128 | C 175 ; WX 603 ; N arrowdown ; B 45 -22 571 888 ;
129 | C 176 ; WX 400 ; N degree ; B 50 385 350 685 ;
130 | C 177 ; WX 549 ; N plusminus ; B 10 0 539 645 ;
131 | C 178 ; WX 411 ; N second ; B 20 459 413 737 ;
132 | C 179 ; WX 549 ; N greaterequal ; B 29 0 526 639 ;
133 | C 180 ; WX 549 ; N multiply ; B 17 8 533 524 ;
134 | C 181 ; WX 713 ; N proportional ; B 27 123 639 404 ;
135 | C 182 ; WX 494 ; N partialdiff ; B 26 -20 462 746 ;
136 | C 183 ; WX 460 ; N bullet ; B 50 113 410 473 ;
137 | C 184 ; WX 549 ; N divide ; B 10 71 536 456 ;
138 | C 185 ; WX 549 ; N notequal ; B 15 -25 540 549 ;
139 | C 186 ; WX 549 ; N equivalence ; B 14 82 538 443 ;
140 | C 187 ; WX 549 ; N approxequal ; B 14 135 527 394 ;
141 | C 188 ; WX 1000 ; N ellipsis ; B 111 -17 889 95 ;
142 | C 189 ; WX 603 ; N arrowvertex ; B 280 -120 336 1010 ;
143 | C 190 ; WX 1000 ; N arrowhorizex ; B -60 220 1050 276 ;
144 | C 191 ; WX 658 ; N carriagereturn ; B 15 -16 602 629 ;
145 | C 192 ; WX 823 ; N aleph ; B 175 -18 661 658 ;
146 | C 193 ; WX 686 ; N Ifraktur ; B 10 -53 578 740 ;
147 | C 194 ; WX 795 ; N Rfraktur ; B 26 -15 759 734 ;
148 | C 195 ; WX 987 ; N weierstrass ; B 159 -211 870 573 ;
149 | C 196 ; WX 768 ; N circlemultiply ; B 43 -17 733 673 ;
150 | C 197 ; WX 768 ; N circleplus ; B 43 -15 733 675 ;
151 | C 198 ; WX 823 ; N emptyset ; B 39 -24 781 719 ;
152 | C 199 ; WX 768 ; N intersection ; B 40 0 732 509 ;
153 | C 200 ; WX 768 ; N union ; B 40 -17 732 492 ;
154 | C 201 ; WX 713 ; N propersuperset ; B 20 0 673 470 ;
155 | C 202 ; WX 713 ; N reflexsuperset ; B 20 -125 673 470 ;
156 | C 203 ; WX 713 ; N notsubset ; B 36 -70 690 540 ;
157 | C 204 ; WX 713 ; N propersubset ; B 37 0 690 470 ;
158 | C 205 ; WX 713 ; N reflexsubset ; B 37 -125 690 470 ;
159 | C 206 ; WX 713 ; N element ; B 45 0 505 468 ;
160 | C 207 ; WX 713 ; N notelement ; B 45 -58 505 555 ;
161 | C 208 ; WX 768 ; N angle ; B 26 0 738 673 ;
162 | C 209 ; WX 713 ; N gradient ; B 36 -19 681 718 ;
163 | C 210 ; WX 790 ; N registerserif ; B 50 -17 740 673 ;
164 | C 211 ; WX 790 ; N copyrightserif ; B 51 -15 741 675 ;
165 | C 212 ; WX 890 ; N trademarkserif ; B 18 293 855 673 ;
166 | C 213 ; WX 823 ; N product ; B 25 -101 803 751 ;
167 | C 214 ; WX 549 ; N radical ; B 10 -38 515 917 ;
168 | C 215 ; WX 250 ; N dotmath ; B 69 210 169 310 ;
169 | C 216 ; WX 713 ; N logicalnot ; B 15 0 680 288 ;
170 | C 217 ; WX 603 ; N logicaland ; B 23 0 583 454 ;
171 | C 218 ; WX 603 ; N logicalor ; B 30 0 578 477 ;
172 | C 219 ; WX 1042 ; N arrowdblboth ; B 27 -20 1023 510 ;
173 | C 220 ; WX 987 ; N arrowdblleft ; B 30 -15 939 513 ;
174 | C 221 ; WX 603 ; N arrowdblup ; B 39 2 567 911 ;
175 | C 222 ; WX 987 ; N arrowdblright ; B 45 -20 954 508 ;
176 | C 223 ; WX 603 ; N arrowdbldown ; B 44 -19 572 890 ;
177 | C 224 ; WX 494 ; N lozenge ; B 18 0 466 745 ;
178 | C 225 ; WX 329 ; N angleleft ; B 25 -198 306 746 ;
179 | C 226 ; WX 790 ; N registersans ; B 50 -20 740 670 ;
180 | C 227 ; WX 790 ; N copyrightsans ; B 49 -15 739 675 ;
181 | C 228 ; WX 786 ; N trademarksans ; B 5 293 725 673 ;
182 | C 229 ; WX 713 ; N summation ; B 14 -108 695 752 ;
183 | C 230 ; WX 384 ; N parenlefttp ; B 40 -293 436 926 ;
184 | C 231 ; WX 384 ; N parenleftex ; B 40 -85 92 925 ;
185 | C 232 ; WX 384 ; N parenleftbt ; B 40 -293 436 926 ;
186 | C 233 ; WX 384 ; N bracketlefttp ; B 0 -80 341 926 ;
187 | C 234 ; WX 384 ; N bracketleftex ; B 0 -79 55 925 ;
188 | C 235 ; WX 384 ; N bracketleftbt ; B 0 -80 340 926 ;
189 | C 236 ; WX 494 ; N bracelefttp ; B 201 -75 439 926 ;
190 | C 237 ; WX 494 ; N braceleftmid ; B 14 -85 255 935 ;
191 | C 238 ; WX 494 ; N braceleftbt ; B 201 -70 439 926 ;
192 | C 239 ; WX 494 ; N braceex ; B 201 -80 255 935 ;
193 | C 241 ; WX 329 ; N angleright ; B 21 -198 302 746 ;
194 | C 242 ; WX 274 ; N integral ; B 2 -107 291 916 ;
195 | C 243 ; WX 686 ; N integraltp ; B 332 -83 715 921 ;
196 | C 244 ; WX 686 ; N integralex ; B 332 -88 415 975 ;
197 | C 245 ; WX 686 ; N integralbt ; B 39 -81 415 921 ;
198 | C 246 ; WX 384 ; N parenrighttp ; B 54 -293 450 926 ;
199 | C 247 ; WX 384 ; N parenrightex ; B 398 -85 450 925 ;
200 | C 248 ; WX 384 ; N parenrightbt ; B 54 -293 450 926 ;
201 | C 249 ; WX 384 ; N bracketrighttp ; B 22 -80 360 926 ;
202 | C 250 ; WX 384 ; N bracketrightex ; B 305 -79 360 925 ;
203 | C 251 ; WX 384 ; N bracketrightbt ; B 20 -80 360 926 ;
204 | C 252 ; WX 494 ; N bracerighttp ; B 17 -75 255 926 ;
205 | C 253 ; WX 494 ; N bracerightmid ; B 201 -85 442 935 ;
206 | C 254 ; WX 494 ; N bracerightbt ; B 17 -70 255 926 ;
207 | C -1 ; WX 790 ; N apple ; B 56 -3 733 808 ;
208 | EndCharMetrics
209 | EndFontMetrics
210 |
--------------------------------------------------------------------------------
/priv/fonts/adobe/zapfding/pzdr.afm:
--------------------------------------------------------------------------------
1 | StartFontMetrics 2.0
2 | Comment Copyright (c) 1985, 1987, 1988, 1989 Adobe Systems Incorporated. All rights reserved.
3 | Comment Creation Date: Fri Dec 1 12:57:42 1989
4 | Comment UniqueID 26200
5 | Comment VMusage 39281 49041
6 | FontName ZapfDingbats
7 | FullName ITC Zapf Dingbats
8 | FamilyName ITC Zapf Dingbats
9 | Weight Medium
10 | ItalicAngle 0
11 | IsFixedPitch false
12 | FontBBox -1 -143 981 820
13 | UnderlinePosition -98
14 | UnderlineThickness 54
15 | Version 001.004
16 | Notice Copyright (c) 1985, 1987, 1988, 1989 Adobe Systems Incorporated. All rights reserved.ITC Zapf Dingbats is a registered trademark of International Typeface Corporation.
17 | EncodingScheme FontSpecific
18 | StartCharMetrics 202
19 | C 32 ; WX 278 ; N space ; B 0 0 0 0 ;
20 | C 33 ; WX 974 ; N a1 ; B 35 72 939 621 ;
21 | C 34 ; WX 961 ; N a2 ; B 35 81 927 611 ;
22 | C 35 ; WX 974 ; N a202 ; B 35 72 939 621 ;
23 | C 36 ; WX 980 ; N a3 ; B 35 0 945 692 ;
24 | C 37 ; WX 719 ; N a4 ; B 34 139 685 566 ;
25 | C 38 ; WX 789 ; N a5 ; B 35 -14 755 705 ;
26 | C 39 ; WX 790 ; N a119 ; B 35 -14 755 705 ;
27 | C 40 ; WX 791 ; N a118 ; B 35 -13 761 705 ;
28 | C 41 ; WX 690 ; N a117 ; B 35 138 655 553 ;
29 | C 42 ; WX 960 ; N a11 ; B 35 123 925 568 ;
30 | C 43 ; WX 939 ; N a12 ; B 35 134 904 559 ;
31 | C 44 ; WX 549 ; N a13 ; B 29 -11 516 705 ;
32 | C 45 ; WX 855 ; N a14 ; B 34 59 820 632 ;
33 | C 46 ; WX 911 ; N a15 ; B 35 50 876 642 ;
34 | C 47 ; WX 933 ; N a16 ; B 35 139 899 550 ;
35 | C 48 ; WX 911 ; N a105 ; B 35 50 876 642 ;
36 | C 49 ; WX 945 ; N a17 ; B 35 139 909 553 ;
37 | C 50 ; WX 974 ; N a18 ; B 35 104 938 587 ;
38 | C 51 ; WX 755 ; N a19 ; B 34 -13 721 705 ;
39 | C 52 ; WX 846 ; N a20 ; B 36 -14 811 705 ;
40 | C 53 ; WX 762 ; N a21 ; B 35 0 727 692 ;
41 | C 54 ; WX 761 ; N a22 ; B 35 0 727 692 ;
42 | C 55 ; WX 571 ; N a23 ; B -1 -68 571 661 ;
43 | C 56 ; WX 677 ; N a24 ; B 36 -13 642 705 ;
44 | C 57 ; WX 763 ; N a25 ; B 35 0 728 692 ;
45 | C 58 ; WX 760 ; N a26 ; B 35 0 726 692 ;
46 | C 59 ; WX 759 ; N a27 ; B 35 0 725 692 ;
47 | C 60 ; WX 754 ; N a28 ; B 35 0 720 692 ;
48 | C 61 ; WX 494 ; N a6 ; B 35 0 460 692 ;
49 | C 62 ; WX 552 ; N a7 ; B 35 0 517 692 ;
50 | C 63 ; WX 537 ; N a8 ; B 35 0 503 692 ;
51 | C 64 ; WX 577 ; N a9 ; B 35 96 542 596 ;
52 | C 65 ; WX 692 ; N a10 ; B 35 -14 657 705 ;
53 | C 66 ; WX 786 ; N a29 ; B 35 -14 751 705 ;
54 | C 67 ; WX 788 ; N a30 ; B 35 -14 752 705 ;
55 | C 68 ; WX 788 ; N a31 ; B 35 -14 753 705 ;
56 | C 69 ; WX 790 ; N a32 ; B 35 -14 756 705 ;
57 | C 70 ; WX 793 ; N a33 ; B 35 -13 759 705 ;
58 | C 71 ; WX 794 ; N a34 ; B 35 -13 759 705 ;
59 | C 72 ; WX 816 ; N a35 ; B 35 -14 782 705 ;
60 | C 73 ; WX 823 ; N a36 ; B 35 -14 787 705 ;
61 | C 74 ; WX 789 ; N a37 ; B 35 -14 754 705 ;
62 | C 75 ; WX 841 ; N a38 ; B 35 -14 807 705 ;
63 | C 76 ; WX 823 ; N a39 ; B 35 -14 789 705 ;
64 | C 77 ; WX 833 ; N a40 ; B 35 -14 798 705 ;
65 | C 78 ; WX 816 ; N a41 ; B 35 -13 782 705 ;
66 | C 79 ; WX 831 ; N a42 ; B 35 -14 796 705 ;
67 | C 80 ; WX 923 ; N a43 ; B 35 -14 888 705 ;
68 | C 81 ; WX 744 ; N a44 ; B 35 0 710 692 ;
69 | C 82 ; WX 723 ; N a45 ; B 35 0 688 692 ;
70 | C 83 ; WX 749 ; N a46 ; B 35 0 714 692 ;
71 | C 84 ; WX 790 ; N a47 ; B 34 -14 756 705 ;
72 | C 85 ; WX 792 ; N a48 ; B 35 -14 758 705 ;
73 | C 86 ; WX 695 ; N a49 ; B 35 -14 661 706 ;
74 | C 87 ; WX 776 ; N a50 ; B 35 -6 741 699 ;
75 | C 88 ; WX 768 ; N a51 ; B 35 -7 734 699 ;
76 | C 89 ; WX 792 ; N a52 ; B 35 -14 757 705 ;
77 | C 90 ; WX 759 ; N a53 ; B 35 0 725 692 ;
78 | C 91 ; WX 707 ; N a54 ; B 35 -13 672 704 ;
79 | C 92 ; WX 708 ; N a55 ; B 35 -14 672 705 ;
80 | C 93 ; WX 682 ; N a56 ; B 35 -14 647 705 ;
81 | C 94 ; WX 701 ; N a57 ; B 35 -14 666 705 ;
82 | C 95 ; WX 826 ; N a58 ; B 35 -14 791 705 ;
83 | C 96 ; WX 815 ; N a59 ; B 35 -14 780 705 ;
84 | C 97 ; WX 789 ; N a60 ; B 35 -14 754 705 ;
85 | C 98 ; WX 789 ; N a61 ; B 35 -14 754 705 ;
86 | C 99 ; WX 707 ; N a62 ; B 34 -14 673 705 ;
87 | C 100 ; WX 687 ; N a63 ; B 36 0 651 692 ;
88 | C 101 ; WX 696 ; N a64 ; B 35 0 661 691 ;
89 | C 102 ; WX 689 ; N a65 ; B 35 0 655 692 ;
90 | C 103 ; WX 786 ; N a66 ; B 34 -14 751 705 ;
91 | C 104 ; WX 787 ; N a67 ; B 35 -14 752 705 ;
92 | C 105 ; WX 713 ; N a68 ; B 35 -14 678 705 ;
93 | C 106 ; WX 791 ; N a69 ; B 35 -14 756 705 ;
94 | C 107 ; WX 785 ; N a70 ; B 36 -14 751 705 ;
95 | C 108 ; WX 791 ; N a71 ; B 35 -14 757 705 ;
96 | C 109 ; WX 873 ; N a72 ; B 35 -14 838 705 ;
97 | C 110 ; WX 761 ; N a73 ; B 35 0 726 692 ;
98 | C 111 ; WX 762 ; N a74 ; B 35 0 727 692 ;
99 | C 112 ; WX 762 ; N a203 ; B 35 0 727 692 ;
100 | C 113 ; WX 759 ; N a75 ; B 35 0 725 692 ;
101 | C 114 ; WX 759 ; N a204 ; B 35 0 725 692 ;
102 | C 115 ; WX 892 ; N a76 ; B 35 0 858 705 ;
103 | C 116 ; WX 892 ; N a77 ; B 35 -14 858 692 ;
104 | C 117 ; WX 788 ; N a78 ; B 35 -14 754 705 ;
105 | C 118 ; WX 784 ; N a79 ; B 35 -14 749 705 ;
106 | C 119 ; WX 438 ; N a81 ; B 35 -14 403 705 ;
107 | C 120 ; WX 138 ; N a82 ; B 35 0 104 692 ;
108 | C 121 ; WX 277 ; N a83 ; B 35 0 242 692 ;
109 | C 122 ; WX 415 ; N a84 ; B 35 0 380 692 ;
110 | C 123 ; WX 392 ; N a97 ; B 35 263 357 705 ;
111 | C 124 ; WX 392 ; N a98 ; B 34 263 357 705 ;
112 | C 125 ; WX 668 ; N a99 ; B 35 263 633 705 ;
113 | C 126 ; WX 668 ; N a100 ; B 36 263 634 705 ;
114 | C 161 ; WX 732 ; N a101 ; B 35 -143 697 806 ;
115 | C 162 ; WX 544 ; N a102 ; B 56 -14 488 706 ;
116 | C 163 ; WX 544 ; N a103 ; B 34 -14 508 705 ;
117 | C 164 ; WX 910 ; N a104 ; B 35 40 875 651 ;
118 | C 165 ; WX 667 ; N a106 ; B 35 -14 633 705 ;
119 | C 166 ; WX 760 ; N a107 ; B 35 -14 726 705 ;
120 | C 167 ; WX 760 ; N a108 ; B 0 121 758 569 ;
121 | C 168 ; WX 776 ; N a112 ; B 35 0 741 705 ;
122 | C 169 ; WX 595 ; N a111 ; B 34 -14 560 705 ;
123 | C 170 ; WX 694 ; N a110 ; B 35 -14 659 705 ;
124 | C 171 ; WX 626 ; N a109 ; B 34 0 591 705 ;
125 | C 172 ; WX 788 ; N a120 ; B 35 -14 754 705 ;
126 | C 173 ; WX 788 ; N a121 ; B 35 -14 754 705 ;
127 | C 174 ; WX 788 ; N a122 ; B 35 -14 754 705 ;
128 | C 175 ; WX 788 ; N a123 ; B 35 -14 754 705 ;
129 | C 176 ; WX 788 ; N a124 ; B 35 -14 754 705 ;
130 | C 177 ; WX 788 ; N a125 ; B 35 -14 754 705 ;
131 | C 178 ; WX 788 ; N a126 ; B 35 -14 754 705 ;
132 | C 179 ; WX 788 ; N a127 ; B 35 -14 754 705 ;
133 | C 180 ; WX 788 ; N a128 ; B 35 -14 754 705 ;
134 | C 181 ; WX 788 ; N a129 ; B 35 -14 754 705 ;
135 | C 182 ; WX 788 ; N a130 ; B 35 -14 754 705 ;
136 | C 183 ; WX 788 ; N a131 ; B 35 -14 754 705 ;
137 | C 184 ; WX 788 ; N a132 ; B 35 -14 754 705 ;
138 | C 185 ; WX 788 ; N a133 ; B 35 -14 754 705 ;
139 | C 186 ; WX 788 ; N a134 ; B 35 -14 754 705 ;
140 | C 187 ; WX 788 ; N a135 ; B 35 -14 754 705 ;
141 | C 188 ; WX 788 ; N a136 ; B 35 -14 754 705 ;
142 | C 189 ; WX 788 ; N a137 ; B 35 -14 754 705 ;
143 | C 190 ; WX 788 ; N a138 ; B 35 -14 754 705 ;
144 | C 191 ; WX 788 ; N a139 ; B 35 -14 754 705 ;
145 | C 192 ; WX 788 ; N a140 ; B 35 -14 754 705 ;
146 | C 193 ; WX 788 ; N a141 ; B 35 -14 754 705 ;
147 | C 194 ; WX 788 ; N a142 ; B 35 -14 754 705 ;
148 | C 195 ; WX 788 ; N a143 ; B 35 -14 754 705 ;
149 | C 196 ; WX 788 ; N a144 ; B 35 -14 754 705 ;
150 | C 197 ; WX 788 ; N a145 ; B 35 -14 754 705 ;
151 | C 198 ; WX 788 ; N a146 ; B 35 -14 754 705 ;
152 | C 199 ; WX 788 ; N a147 ; B 35 -14 754 705 ;
153 | C 200 ; WX 788 ; N a148 ; B 35 -14 754 705 ;
154 | C 201 ; WX 788 ; N a149 ; B 35 -14 754 705 ;
155 | C 202 ; WX 788 ; N a150 ; B 35 -14 754 705 ;
156 | C 203 ; WX 788 ; N a151 ; B 35 -14 754 705 ;
157 | C 204 ; WX 788 ; N a152 ; B 35 -14 754 705 ;
158 | C 205 ; WX 788 ; N a153 ; B 35 -14 754 705 ;
159 | C 206 ; WX 788 ; N a154 ; B 35 -14 754 705 ;
160 | C 207 ; WX 788 ; N a155 ; B 35 -14 754 705 ;
161 | C 208 ; WX 788 ; N a156 ; B 35 -14 754 705 ;
162 | C 209 ; WX 788 ; N a157 ; B 35 -14 754 705 ;
163 | C 210 ; WX 788 ; N a158 ; B 35 -14 754 705 ;
164 | C 211 ; WX 788 ; N a159 ; B 35 -14 754 705 ;
165 | C 212 ; WX 894 ; N a160 ; B 35 58 860 634 ;
166 | C 213 ; WX 838 ; N a161 ; B 35 152 803 540 ;
167 | C 214 ; WX 1016 ; N a163 ; B 34 152 981 540 ;
168 | C 215 ; WX 458 ; N a164 ; B 35 -127 422 820 ;
169 | C 216 ; WX 748 ; N a196 ; B 35 94 698 597 ;
170 | C 217 ; WX 924 ; N a165 ; B 35 140 890 552 ;
171 | C 218 ; WX 748 ; N a192 ; B 35 94 698 597 ;
172 | C 219 ; WX 918 ; N a166 ; B 35 166 884 526 ;
173 | C 220 ; WX 927 ; N a167 ; B 35 32 892 660 ;
174 | C 221 ; WX 928 ; N a168 ; B 35 129 891 562 ;
175 | C 222 ; WX 928 ; N a169 ; B 35 128 893 563 ;
176 | C 223 ; WX 834 ; N a170 ; B 35 155 799 537 ;
177 | C 224 ; WX 873 ; N a171 ; B 35 93 838 599 ;
178 | C 225 ; WX 828 ; N a172 ; B 35 104 791 588 ;
179 | C 226 ; WX 924 ; N a173 ; B 35 98 889 594 ;
180 | C 227 ; WX 924 ; N a162 ; B 35 98 889 594 ;
181 | C 228 ; WX 917 ; N a174 ; B 35 0 882 692 ;
182 | C 229 ; WX 930 ; N a175 ; B 35 84 896 608 ;
183 | C 230 ; WX 931 ; N a176 ; B 35 84 896 608 ;
184 | C 231 ; WX 463 ; N a177 ; B 35 -99 429 791 ;
185 | C 232 ; WX 883 ; N a178 ; B 35 71 848 623 ;
186 | C 233 ; WX 836 ; N a179 ; B 35 44 802 648 ;
187 | C 234 ; WX 836 ; N a193 ; B 35 44 802 648 ;
188 | C 235 ; WX 867 ; N a180 ; B 35 101 832 591 ;
189 | C 236 ; WX 867 ; N a199 ; B 35 101 832 591 ;
190 | C 237 ; WX 696 ; N a181 ; B 35 44 661 648 ;
191 | C 238 ; WX 696 ; N a200 ; B 35 44 661 648 ;
192 | C 239 ; WX 874 ; N a182 ; B 35 77 840 619 ;
193 | C 241 ; WX 874 ; N a201 ; B 35 73 840 615 ;
194 | C 242 ; WX 760 ; N a183 ; B 35 0 725 692 ;
195 | C 243 ; WX 946 ; N a184 ; B 35 160 911 533 ;
196 | C 244 ; WX 771 ; N a197 ; B 34 37 736 655 ;
197 | C 245 ; WX 865 ; N a185 ; B 35 207 830 481 ;
198 | C 246 ; WX 771 ; N a194 ; B 34 37 736 655 ;
199 | C 247 ; WX 888 ; N a198 ; B 34 -19 853 712 ;
200 | C 248 ; WX 967 ; N a186 ; B 35 124 932 568 ;
201 | C 249 ; WX 888 ; N a195 ; B 34 -19 853 712 ;
202 | C 250 ; WX 831 ; N a187 ; B 35 113 796 579 ;
203 | C 251 ; WX 873 ; N a188 ; B 36 118 838 578 ;
204 | C 252 ; WX 927 ; N a189 ; B 35 150 891 542 ;
205 | C 253 ; WX 970 ; N a190 ; B 35 76 931 616 ;
206 | C 254 ; WX 918 ; N a191 ; B 34 99 884 593 ;
207 | C -1 ; WX 410 ; N a86 ; B 35 0 375 692 ;
208 | C -1 ; WX 509 ; N a85 ; B 35 0 475 692 ;
209 | C -1 ; WX 334 ; N a95 ; B 35 0 299 692 ;
210 | C -1 ; WX 509 ; N a205 ; B 35 0 475 692 ;
211 | C -1 ; WX 390 ; N a89 ; B 35 -14 356 705 ;
212 | C -1 ; WX 234 ; N a87 ; B 35 -14 199 705 ;
213 | C -1 ; WX 276 ; N a91 ; B 35 0 242 692 ;
214 | C -1 ; WX 390 ; N a90 ; B 35 -14 355 705 ;
215 | C -1 ; WX 410 ; N a206 ; B 35 0 375 692 ;
216 | C -1 ; WX 317 ; N a94 ; B 35 0 283 692 ;
217 | C -1 ; WX 317 ; N a93 ; B 35 0 283 692 ;
218 | C -1 ; WX 276 ; N a92 ; B 35 0 242 692 ;
219 | C -1 ; WX 334 ; N a96 ; B 35 0 299 692 ;
220 | C -1 ; WX 234 ; N a88 ; B 35 -14 199 705 ;
221 | EndCharMetrics
222 | EndFontMetrics
223 |
--------------------------------------------------------------------------------
/priv/fonts/gocm/GOCM____.TXT:
--------------------------------------------------------------------------------
1 | Installation notes for PC users:
2 |
3 | Don't forget to make the WIN.INI changes required to allow the font to
4 | download to your printer.
5 |
6 | Included in this archive are two versions of GoodCityModern: the first one
7 | uses Adobe Standard Encoding, meaning that many of the odd characters in the
8 | 'upper 128' of the ASCII sequence will appear in the places that PC
9 | keyboarders expect them to be. The second version uses sequential encoding (as
10 | did the original upload of the PC version of GoodCityModern). Sequential
11 | encoding means that a lot more characters will be available for typing from
12 | the PC keyboard, but they will not be in the positions that PC keyboarders
13 | expect them to be.
14 |
15 | You will need to make a choice between the GOCMASE_.* font and the GOCMSEQ_.*
16 | font. The first is Adobe Standard Encoded (characters where PC expects them
17 | but fewer characters available), the second is Sequential Encoded (all the
18 | characters available, but they're in different positions than PCs expect
19 | them). DO NOT INSTALL BOTH VERSIONS AT ONCE OR YOU WILL HAVE PROBLEMS.
20 |
21 | Also, both these versions have been run through the FOGFIX program, to make
22 | sure none of the anomalies that can be caused by having nulls or upper ASCII
23 | in the .PFB file will ever show up.
24 |
25 |
26 | Welcome to GoodCityModern,
27 |
28 | GoodCityModern 1.1 Read Me
29 |
30 | Thank all of you for downloading my font. I never in my wildest dreams would
31 | think so many people wanted this obscure, yet historical, font. To date, well
32 | over 3500 people have retrieved or received GoodCityModern. I have received
33 | letters, cards, and phone calls from all over the world. I am pleased that you
34 | are pleased.
35 |
36 | Ah, like software development, there is always the needed 1.1 after the first
37 | version ships. Quite a lot has happened to GCM (GoodCityModern): lots of
38 | tweaking of path points; corrected accented characters; improved some
39 | character widths; a few new characters added. Enough about the software.
40 |
41 | Since GCM's 1.0 release, I have been busy reading about Latin grammar. I
42 | learned several things. The original kerned pairs that Gutenberg created (po,
43 | pe, pp, etc...) are actually special abbreviations for Latin prefixes,
44 | suffixes, and phrases. He attempted to carry over the medieval scribe's style
45 | of spelling and 'shorthand' for fitting long words at the end of lines.
46 |
47 | Some have complained that the spacing for GCM is uneven or too tight. Go look
48 | at a Gutenberg Bible reproduction and see for yourself. It's far easier to
49 | unkern a few pairs to one's liking than try to know which pairs should be
50 | kerned. Until Apple releases the Line Layout Manager, there is no smart way to
51 | duplicate how Gutenberg typeset his 42 line Bible.
52 |
53 | The main new 'feature' of this version is a set of Lombardic caps to be used
54 | as initial caps with GCM. The original caps will be another font down the way.
55 |
56 | Remember: Blessed is one who teaches another to scribe the Letters. Shalom.
57 |
58 | ------------------------
59 | GoodCityModern 1.0 Read Me
60 |
61 | Naturally, you may be asking yourself, 'How did he create this font?' It
62 | started late one night, restless... Glancing through some type books, I
63 | stopped upon a reproduction of the Gutenberg typeface; thought, that would be
64 | a great typeface to do in Fontographer. Thinking further, perhaps several
65 | weeks in the library and several more at my Mac with Fontographer 3.0 and I
66 | would be done. Hmm, things do not happen quite that way. Murphy's law was
67 | determined to be bothersome. There were only fragments of pages to go by... My
68 | Mac and scanner broke, requiring costly repairs. However, while visiting my
69 | parents (near C.W. Post Campus of Long Island University in Brookville, New
70 | York), I found a full character set to copy at the college library. Work could
71 | commence.
72 |
73 | The reproduction was small and the copier worse, but I managed. Studying the
74 | page, I quickly realized several key points. One: Gutenberg designed the font
75 | with a deep understanding of Latin grammar and spelling. He had kerning pairs
76 | based on repeated letter usage throughout the Bible and kerned small words
77 | into tight units (i.e., "our," "of," and "and"). Second: That he posited key
78 | geometric guidelines to aid in creating the font. He was doing more than just
79 | capturing the scribe-like strokes of his day, but in addition had a respect
80 | for the metal and ink to be used in printing his Bible. This second point made
81 | it possible to actually create the font; because of the smallness of the
82 | reproduced letters, I had to re-create (for techies, 'reverse-engineer') them.
83 | My loupe and the page became very close friends!
84 |
85 | After some hand drawings to 'feel' the letter forms, I scanned the page at 150
86 | dpi and made a bitmap font using Fontastic Plus(tm). Sometimes, I felt another
87 | hand on my mouse while fat-bitting away late at night... Then, I typed Latin
88 | text into Fontastic Plus' sample text edit window to see the typeface in
89 | actual context. Next, using the bitmap font, a PostScript printer, and Apple's
90 | print driver, I printed a page of characters at 200% enlargement with the
91 | option 'smoothing' (to partly smooth out the jaggies) checked from Apple's
92 | print driver. Thus, one could scale and smooth out a bitmap font -- without
93 | fatbitting a lot. Finally, I cleaned up the scan in MacPaint(R).
94 |
95 | I did preliminary versions in Fontographer 3.0.5 thru 3.1. As the in-house
96 | tester for FreeHand 3.0, I was naturally thinking mostly in terms of FreeHand,
97 | constantly experimenting with new ways to use it. At one point, I wondered
98 | "how much of my font could I do in FreeHand?" So, I placed the scanned image
99 | into FreeHand 3.0 to trace and refine -- using all its new features to
100 | accomplish the task. For example, while Fontographer has layers, I preferred
101 | the naming and ordering of the layers palette that FreeHand offered. Yes, bcp
102 | by bcp, the font came alive. There were days I felt a presence in the room...
103 |
104 | Once the character paths were done, I simply option-copied them from FreeHand
105 | into Fontographer 3.2. Once paths are in Fontographer, one can create the
106 | needed ligatures. Finally, after upgrading from Fontographer 3.2 to 3.3, I
107 | created kerning pairs. Based on the same careful study Gutenberg did on Latin
108 | letters, I needed to create 800 pairs! Now as of 5:15 pm, June 18, 1991, using
109 | Fontographer 3.3, I was finished.
110 |
111 | A few historical notes. The original typeface was created for Latin, not for
112 | modern English; hence, the 'modern' in the name of my translation. I had to
113 | create a full Roman set everyone can use. However, there is an exact Latin
114 | version which is not done. The 'goodcity' part of its name comes from German:
115 | guten-good, burg-city (or fortress), (actually, Earl Allen, a fellow Altsysian
116 | coined the term: Thanks, Earl!) [Earl notes that he goofed on the translation
117 | from German, mistakenly translating 'berg' as if it were spelled 'burg.' A
118 | better translation would be GoodMountModern, since 'berg' should actually be
119 | translated 'Mountain' rather than 'City,' as anyone who knows what an iceberg
120 | is would have done. Apologies for the mistranslation, but Andrew has decided
121 | to stick with the name for now.]
122 |
123 | Enjoy and use in good health.
124 |
125 | Andrew S. Meit Altsys Tester (and Stackhead) Altsys Corporation
126 |
127 | If you have any comments you'd like to pass on to Andrew you can send them to
128 | him at CompuServe: 76004,2071; MCI Mail: ALTSYS; America Online: Altsys;
129 | AppleLink: D0590. If you'd prefer to call, the phone number is (214) 680-2060
130 | and the FAX number is (214) 680-0537. Andrew appreciates any and all feedback
131 | you can give him.
132 |
--------------------------------------------------------------------------------
/priv/fonts/gocm/ase/GOCMASE_.CFG:
--------------------------------------------------------------------------------
1 | # Installer Configuration File
2 | # Contains package specific information used by the install program.
3 | #
4 | DISKSIZE 0
5 | FILE INSTALL.CFG 1
6 | FILE README 1
7 | #
8 | # Font entry fields:
9 | # Fontname - PostScript name of the typeface
10 | # Filename - 5 character PC filename base
11 | # Number of the disk this filetype sits on or zero if not present
12 | # One entry for each filetype PFB, INF, CTF, PFM, ABF, AFM
13 | #
14 | FONT GoodCityModern GoCM____ 1 1 0 1 0 1
15 | #
16 | DISKNAME 1 'GoodCityModern'
17 | #
18 | PKGNAME GoodCityModern
19 |
--------------------------------------------------------------------------------
/priv/fonts/gocm/ase/GOCMASE_.INF:
--------------------------------------------------------------------------------
1 | FontName (GoodCityModern)
2 | FullName (GoodCityModern)
3 | FamilyName (GoodCityModern)
4 | AppleName (GoodCityModern)
5 | AppleFONDID 1759
6 | version (001.000)
7 | isFixedPitch false
8 | CharacterSet (isoAdobe)
9 | Encoding (AdobeStandardEncoding)
10 | ItalicAngle 0
11 | CapHeight 681
12 | UnderlinePosition -133
13 | UnderlineThickness 20
14 | StemWidth 30
15 | Serif true
16 | Pi false
17 | MSMenuName (GoodCityModern)
18 | VPMenuName (GoodCityModern)
19 | WORDMenuName (GoodCityModern)
20 | VPTypefaceID 4021258
21 | VPStyle (N)
22 | PCFileNamePrefix (GoCM____)
23 | PCLTypefaceID 4021258
24 | PCLStrokeWeight 0
25 | PCLStyle 0
26 |
--------------------------------------------------------------------------------
/priv/fonts/gocm/ase/GOCMASE_.pfb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/gocm/ase/GOCMASE_.pfb
--------------------------------------------------------------------------------
/priv/fonts/gocm/ase/GOCMASE_.pfm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/gocm/ase/GOCMASE_.pfm
--------------------------------------------------------------------------------
/priv/fonts/gocm/seq/GOCMSEQ_.CFG:
--------------------------------------------------------------------------------
1 | # Installer Configuration File
2 | # Contains package specific information used by the install program.
3 | #
4 | DISKSIZE 0
5 | FILE INSTALL.CFG 1
6 | FILE README 1
7 | #
8 | # Font entry fields:
9 | # Fontname - PostScript name of the typeface
10 | # Filename - 5 character PC filename base
11 | # Number of the disk this filetype sits on or zero if not present
12 | # One entry for each filetype PFB, INF, CTF, PFM, ABF, AFM
13 | #
14 | FONT GoodCityModern GoCM____ 1 1 0 1 0 1
15 | #
16 | DISKNAME 1 'GoodCityModern'
17 | #
18 | PKGNAME GoodCityModern
19 |
--------------------------------------------------------------------------------
/priv/fonts/gocm/seq/GOCMSEQ_.INF:
--------------------------------------------------------------------------------
1 | FontName (GoodCityModern)
2 | FullName (GoodCityModern)
3 | FamilyName (GoodCityModern)
4 | AppleName (GoodCityModern)
5 | AppleFONDID 1759
6 | version (001.000)
7 | isFixedPitch false
8 | CharacterSet (isoAdobe)
9 | Encoding (AppleStandard)
10 | ItalicAngle 0
11 | CapHeight 681
12 | UnderlinePosition -133
13 | UnderlineThickness 20
14 | StemWidth 30
15 | Serif true
16 | Pi false
17 | MSMenuName (GoodCityModern)
18 | VPMenuName (GoodCityModern)
19 | WORDMenuName (GoodCityModern)
20 | VPTypefaceID 4021258
21 | VPStyle (N)
22 | PCFileNamePrefix (GoCM____)
23 | PCLTypefaceID 4021258
24 | PCLStrokeWeight 0
25 | PCLStyle 0
26 |
--------------------------------------------------------------------------------
/priv/fonts/gocm/seq/GOCMSEQ_.pfb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/gocm/seq/GOCMSEQ_.pfb
--------------------------------------------------------------------------------
/priv/fonts/gocm/seq/GOCMSEQ_.pfm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/gocm/seq/GOCMSEQ_.pfm
--------------------------------------------------------------------------------
/priv/fonts/ocr/file_id.diz:
--------------------------------------------------------------------------------
1 | OCR-A-Digits and OCR-B-Digits - are two
2 | sample fonts from the author's
3 | OCR-A/OCR-B font package. They include
4 | only the digits 0-9 and the space
5 | character and are useful for inventory,
6 | ID numbers, tracking, etc.
7 |
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocra_num.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/ocr/ocra_num.ttf
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocrad___.afm:
--------------------------------------------------------------------------------
1 | StartFontMetrics 2.0
2 | Comment Generated by Fontographer 3.5 Mon Oct 04 15:20:45 1993
3 | FontName OCR-A-Digits
4 | FullName OCR-A-Digits
5 | FamilyName OCR-A-Digits
6 | Weight Normal
7 | Notice copyright 1993 Jerry Whiting
8 | ItalicAngle 0
9 | IsFixedPitch false
10 | UnderlinePosition -120
11 | UnderlineThickness 20
12 | Version 1.000
13 | EncodingScheme AdobeStandardEncoding
14 | FontBBox 0 0 523 666
15 | CapHeight 610
16 | XHeight 407
17 | Descender -186
18 | Ascender 814
19 | StartCharMetrics 12
20 | C 32 ; WX 200 ; N space ; B 0 0 0 0 ;
21 | C 48 ; WX 620 ; N zero ; B 98 0 522 666 ;
22 | C 49 ; WX 620 ; N one ; B 98 0 522 666 ;
23 | C 50 ; WX 620 ; N two ; B 97 0 522 666 ;
24 | C 51 ; WX 620 ; N three ; B 96 0 520 666 ;
25 | C 52 ; WX 620 ; N four ; B 141 0 523 666 ;
26 | C 53 ; WX 620 ; N five ; B 97 0 521 665 ;
27 | C 54 ; WX 620 ; N six ; B 97 0 521 666 ;
28 | C 55 ; WX 620 ; N seven ; B 98 0 522 666 ;
29 | C 56 ; WX 620 ; N eight ; B 98 0 522 666 ;
30 | C 57 ; WX 620 ; N nine ; B 97 0 521 666 ;
31 | C -1 ; WX 500 ; N nbspace ; B 0 0 0 0 ;
32 | EndCharMetrics
33 | EndFontMetrics
34 |
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocrad___.pfb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/ocr/ocrad___.pfb
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocrad___.pfm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/ocr/ocrad___.pfm
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocrb_num.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/ocr/ocrb_num.ttf
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocrbd___.afm:
--------------------------------------------------------------------------------
1 | StartFontMetrics 2.0
2 | Comment Generated by Fontographer 3.5 Mon Oct 04 15:25:50 1993
3 | FontName OCR-B-Digits
4 | FullName OCR-B-Digits
5 | FamilyName OCR-B-Digits
6 | Weight Normal
7 | Notice copyright 1993 Jerry Whiting
8 | ItalicAngle 0
9 | IsFixedPitch false
10 | UnderlinePosition -120
11 | UnderlineThickness 20
12 | Version 1.000
13 | EncodingScheme AdobeStandardEncoding
14 | FontBBox 0 -13 621 742
15 | CapHeight 610
16 | XHeight 407
17 | Descender -186
18 | Ascender 814
19 | StartCharMetrics 12
20 | C 32 ; WX 200 ; N space ; B 0 0 0 0 ;
21 | C 48 ; WX 763 ; N zero ; B 141 -13 620 735 ;
22 | C 49 ; WX 763 ; N one ; B 173 -10 473 734 ;
23 | C 50 ; WX 763 ; N two ; B 160 0 601 738 ;
24 | C 51 ; WX 763 ; N three ; B 143 -10 613 725 ;
25 | C 52 ; WX 763 ; N four ; B 143 -10 620 734 ;
26 | C 53 ; WX 763 ; N five ; B 166 -10 582 725 ;
27 | C 54 ; WX 763 ; N six ; B 141 -13 621 738 ;
28 | C 55 ; WX 763 ; N seven ; B 145 -10 618 725 ;
29 | C 56 ; WX 763 ; N eight ; B 142 -13 621 735 ;
30 | C 57 ; WX 763 ; N nine ; B 141 -9 621 742 ;
31 | C -1 ; WX 500 ; N nbspace ; B 0 0 0 0 ;
32 | EndCharMetrics
33 | EndFontMetrics
34 |
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocrbd___.pfb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/ocr/ocrbd___.pfb
--------------------------------------------------------------------------------
/priv/fonts/ocr/ocrbd___.pfm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/ocr/ocrbd___.pfm
--------------------------------------------------------------------------------
/priv/fonts/ocr/readme.txt:
--------------------------------------------------------------------------------
1 | OCR-A-Digits & OCR-B-Digits
2 | copyright 1993 Jerry Whiting
3 |
4 | Azalea Software, Inc.
5 | PO Box 16745
6 | Seattle WA 98116-0745
7 |
8 | 800 48-ASOFT
9 | 206 937.5919 voice/FAX
10 |
11 | These two fonts are samples from our OCR-A/OCR-B font package. OCR-A-Digits
12 | and OCR-B-Digits include only the digits 0-9 and the space character. They
13 | are ideal for inventory, ID numbers, tracking, etc., and they serve as a demo
14 | of our full OCR-A/OCR-B font set which includes the full ASCII character set.
15 | It is only $99 and available directly from us.
16 |
17 | Install the TrueType font using the Control Panel/Fonts from the Program
18 | Manager. Install the Type 1 fonts using the ATM Control Panel. They will then
19 | appear in the font menu of any Windows application.
20 |
21 | Azalea Software, Inc. specializes in quality bar code printing solutions. We
22 | sell fonts and utilities for both Windows and the Macintosh. Code 39, UPC,
23 | EAN, Bookland, Code 93, etc. We love to hack bar codes!
24 |
25 |
26 | All trademarks & registered trademarks are property of their respective owners.
27 |
--------------------------------------------------------------------------------
/priv/fonts/vsecret/README:
--------------------------------------------------------------------------------
1 | Victorias-Secret is a Type 1 PostScript font constructed from the
2 | handwriting (printing, mostly) of Victoria Salter, the Office Manager of
3 | the Columbia University Music Department. Note the extra swashes on the
4 | upper-case E. You'll find every character Victoria routinely uses,
5 | including alphabet, numbers and punctuation.
6 |
7 | Victorias-Secret is copyright (c) 1992 by David Rakowski. All Rights
8 | Reserved. It is distributed free of charge, providing the documentation
9 | accompanies any copies sold or traded. Commercial distribution is
10 | prohibited. Nonprofit companies and user groups may freely distribute this
11 | font on their nominal charge disks.
12 |
13 | Victorias-Secret comes from the zero-person type foundry fictitiously known
14 | as Insect Bytes. Although we don't understand it when other people say it,
15 | we also claim that our fonts are "hand crafted." We feel that calling a
16 | digital typeface "hand crafted" is somewhat akin to calling a television
17 | "mother."
18 |
--------------------------------------------------------------------------------
/priv/fonts/vsecret/V-SECRET.BMA:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/vsecret/V-SECRET.BMA
--------------------------------------------------------------------------------
/priv/fonts/vsecret/V-SECRET.afm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/vsecret/V-SECRET.afm
--------------------------------------------------------------------------------
/priv/fonts/vsecret/V-SECRET.pfb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/fonts/vsecret/V-SECRET.pfb
--------------------------------------------------------------------------------
/priv/hyphenation/README.txt:
--------------------------------------------------------------------------------
1 | __How to add additional Hyphenation rules for new country/language ?__
2 |
3 | * Get the appropriate .tex file/s from TeX (more info about this below).
4 |
5 | Open Office has similar (.dic) files that may or may not work (and may in
6 | turn be based on .tex files) - the main issue is that they support some
7 | additional hyphenation rules and sometimes have more than one substring rule
8 | with the same text (when the numbers are removed) - which our code doesn't
9 | handle - .tex files don't appear to have this issue.
10 |
11 | * The .dic file to create and the ones that already exist, have a format
12 | inspired by Open Office, as I started out with OO .dic files before I realised
13 | that they didn't quite work.
14 |
15 | The exact format is explained in eg_mk_hyphen:start/2.
16 |
17 | It should be fairly easy to create a erlguten .dic file by removing the .tex
18 | "%" commets, "\xxx" commands, "{", "}" markers, replace all non-ascii
19 | escape codes with proper latin-1 letters and add the encoding header and
20 | possibly a "\hyphenation" block.
21 |
22 | Note: this may later make it simpler to handle OO .dic files fully.
23 |
24 | * The new file should be placed in erlguten/priv/hyphenation.
25 |
26 | * It should be named "hyphen_languagecode_COUNTRYCODE.dic"
27 | e.g. "hyphen_sv_SE.dic" where sv = the Swedish language and
28 | SE = Sweden the country. See iso3166 and iso639 for the codes to use.
29 |
30 | * You might also want to add a entry in eg_hyphenate:test/1 to check how well
31 | the hyphenation rules work for the new language.
32 |
33 | Note: The .dic support is still somewhat hackish (2009-08-07), there are
34 | several things that can be done to improve it.
35 | - Check that erlguten can truely handle the dic files fully,
36 | hyphen_fi_FI.dic has some rules with spaces in them which will probably
37 | not be used as erlguten seams to mostly pass individual words (space
38 | separated char sequences) for hyphenation.
39 | - tb87nemeth.pdf - "Automatic Non-Standard Hyphenation in OpenOffice"
40 | explains a bit about some of the extra features supported by OO .dic
41 | files which aren't supported by erlgutens TeX based solution.
42 |
43 | ===============================================================================
44 |
45 | The .tex files used have been extracted from the Ubuntu texlive-lang-all
46 | package (installed using synaptic).
47 |
48 | The individual .tex files when can be found in:
49 | /usr/share/texmf-texlive/tex/generic/hyphen/
50 |
51 | Note that some languages use several .tex files.
52 |
53 | -------------------------------------------------------------------------------
54 |
55 | * hyph_en_GB.dic based on ukhyphen.tex (version 2007.dfsg.4-1), ukhyphen.tex
56 | is the same as the one in ".../erlguten/priv/"
57 | - Hyphenation mostly works.
58 |
59 | * hyph_sv_SE.dic is based on svhyph.tex (version 2007.dfsg.4-1)
60 | - Some hyphenations points end up being wrong, especialy between compound words
61 | and between double consonats.
62 |
63 | * hyph_nb_NO.dic is based on nohyphbx.tex (version 2007.dfsg.4-1)
64 | - Some hyphenations points end up being wrong, especialy between compound words
65 | and between double consonats.
66 |
67 | * hyph_fi_FI.dic is based on fihyph.tex (version 2007.dfsg.4-1)
68 | - Some hyphenations points end up being wrong, especialy between compound words
69 | and between double consonats.
70 |
71 | * hyph_da_DK.dic is based on a merged of dkhyph.tex, dkspecial.tex and
72 | dkcommon.tex (version 2007.dfsg.4-1).
73 | - Some hyphenations points end up being wrong, especialy between compound words
74 | and between double consonats.
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/priv/hyphenation/hyph_da_DK.dic:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/hyphenation/hyph_da_DK.dic
--------------------------------------------------------------------------------
/priv/hyphenation/hyph_fi_FI.dic:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/hyphenation/hyph_fi_FI.dic
--------------------------------------------------------------------------------
/priv/hyphenation/hyph_nb_NO.dic:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/hyphenation/hyph_nb_NO.dic
--------------------------------------------------------------------------------
/priv/hyphenation/hyph_sv_SE.dic:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/hyphenation/hyph_sv_SE.dic
--------------------------------------------------------------------------------
/priv/hyphenation/original_tex/dkhyph.tex:
--------------------------------------------------------------------------------
1 | %% dkhyphen.tex
2 | %% Copyright 1994 Frank Jensen (Frank.Jensen@hugin.com)
3 | %
4 | % This work may be distributed and/or modified under the
5 | % conditions of the LaTeX Project Public License, either version 1.3
6 | % of this license or (at your option) any later version.
7 | % The latest version of this license is in
8 | % http://www.latex-project.org/lppl.txt
9 | % and version 1.3 or later is part of all distributions of LaTeX
10 | % version 2003/12/01 or later.
11 | %
12 | % This work consists of the files dkcommon.tex, dkhyphen.tex and
13 | % dkspecial.tex.
14 | %
15 | % This file contains the hyphenation patterns for danish.
16 | %
17 | % The danish letters have been encoded as follows:
18 | % \ae -> X
19 | % \o -> Y
20 | % \aa -> Z
21 | %
22 | %
23 | % First, we input the patterns containing only `normal' letters (a-z).
24 | \input dkcommon
25 |
26 | % Next, we input patterns for the extra danish letters. We input them
27 | % twice: once for OT1 encoding and once for T1 encoding.
28 |
29 | % OT1 encoding: we have to specify a value for the \aa letter; it can
30 | % be any value (it will not be used, since OT1 doesn't contain the letter).
31 | \begingroup
32 | \lccode`X="1A
33 | \lccode`Y="1C
34 | \lccode`Z="97 % (almost) arbitrary
35 | \input dkspecial
36 | \endgroup
37 |
38 | % T1 encoding:
39 | \begingroup
40 | \lccode`X=230
41 | \lccode`Y=248
42 | \lccode`Z=229
43 | \input dkspecial
44 | \endgroup
45 | \endinput
46 |
--------------------------------------------------------------------------------
/priv/hyphenation/original_tex/dkspecial.tex:
--------------------------------------------------------------------------------
1 | %% dkspecial.tex
2 | %% Copyright 1994 Frank Jensen (Frank.Jensen@hugin.com)
3 | %
4 | % This work may be distributed and/or modified under the
5 | % conditions of the LaTeX Project Public License, either version 1.3
6 | % of this license or (at your option) any later version.
7 | % The latest version of this license is in
8 | % http://www.latex-project.org/lppl.txt
9 | % and version 1.3 or later is part of all distributions of LaTeX
10 | % version 2003/12/01 or later.
11 | %
12 | % This work consists of the files dkcommon.tex, dkhyphen.tex and
13 | % dkspecial.tex.
14 | \patterns{ % just type if you're not using INITEX
15 | .sZ3
16 | .Xr5i
17 | .Yv3r
18 | a3tY
19 | a5vX
20 | brYd3
21 | 5bX
22 | 5drYv
23 | dstZ4
24 | 3dX
25 | 3dY
26 | e3lX
27 | e3lY
28 | e3rY
29 | er5Yn
30 | e5tX
31 | e5tY
32 | e1vX
33 | e3X
34 | e5Z
35 | 3fX
36 | 3fY
37 | fY4r5en
38 | giY4
39 | g4sY
40 | g5sZ
41 | 3gX
42 | 3gY1
43 | 3gZ
44 | i5tX
45 | i3Y
46 | 3kY
47 | 3kZ
48 | lingeniY4
49 | l3vX
50 | 5lYs
51 | m5tZ
52 | 1mX
53 | 3mY
54 | 3mZ
55 | n3kX
56 | n5tX
57 | 3nX
58 | 4n5Xb
59 | 5nY
60 | o5lX
61 | or3Y
62 | o5Z
63 | 5prX
64 | 5pXd
65 | pZ3
66 | r5kX
67 | r5tX
68 | r5tY
69 | r3vX
70 | r5Xl
71 | 4rYn
72 | 5rYr
73 | 3rZd
74 | r5Zr
75 | s4kZ
76 | 3slZ
77 | s4nX
78 | 5stY
79 | 1stZ
80 | 1sX
81 | 4s5Xn
82 | 1sY
83 | s5Yk
84 | sZ4r5
85 | ti4Y
86 | 3trXk.
87 | t4sY
88 | t5sZ
89 | t3vX
90 | u3lX
91 | 3vXrd
92 | 1vXrk
93 | 5vZ
94 | y5vX
95 | Xb3l
96 | X3c
97 | X3e
98 | Xg5a
99 | X4gek
100 | X4g5r
101 | Xgs5
102 | X5i
103 | X5kv
104 | Xlle4
105 | Xn1dr
106 | X5o
107 | X1re
108 | Xr4g5r
109 | X3ri
110 | Xr4ma
111 | Xr4mo
112 | Xr5s
113 | X5si
114 | X3so
115 | X3ste
116 | X3ve
117 | Yde5
118 | Y3e
119 | Y1je
120 | Y3ke
121 | Y3le
122 | Yms5
123 | Yn3st
124 | Yn4t3
125 | Y1re
126 | Y3ri
127 | Yrne3
128 | Yr5o
129 | Y1ve
130 | Z1d
131 | Z1e
132 | Z5h
133 | Z3l
134 | Z3re
135 | Zrs5t
136 | Z5sk
137 | Z3t
138 | }
139 | \endinput
140 |
--------------------------------------------------------------------------------
/priv/hyphenation/original_tex/fihyph.tex:
--------------------------------------------------------------------------------
1 | %
2 | % -----> Finnish hyphenation patterns for MLPCTeX <------
3 | % First release January -86 by Kauko Saarinen,
4 | % Computing Centre, University of Jyvaskyla, Finland
5 | %
6 | % Completely rewritten January -88. The new patterns make
7 | % much less mistakes with foreign and compound words.
8 | % The article "Automatic Hyphenation of Finnish"
9 | % by Professor Fred Karlsson is also referred
10 | % ---------------------------------------------------------
11 | %
12 | % 8th March -89 (vers. 2.2), some vowel triples by Fred Karlsson added.
13 | % 9th January - 95: added \uccode and \lccode by Thomas Esser
14 | %
15 | % ********* Patterns may be freely distributed **********
16 | %
17 | %
18 | \begingroup
19 | \uccode`^^e4=`^^c4 \uccode`^^f6=`^^d6
20 | \lccode`^^e4=`^^e4 \lccode`^^f6=`^^f6
21 | \patterns{
22 | 1ba
23 | 1be
24 | 1bi
25 | 1bo
26 | 1bu
27 | 1by
28 | 1da
29 | 1de
30 | 1di
31 | 1do
32 | 1du
33 | 1dy
34 | 1d^^e4
35 | 1d^^f6
36 | 1fa
37 | 1fe
38 | 1fi
39 | 1fo
40 | 1fu
41 | 1fy
42 | 1ga
43 | 1ge
44 | 1gi
45 | 1go
46 | 1gu
47 | 1gy
48 | 1g^^e4
49 | 1g^^f6
50 | 1ha
51 | 1he
52 | 1hi
53 | 1ho
54 | 1hu
55 | 1hy
56 | 1h^^e4
57 | 1h^^f6
58 | 1ja
59 | 1je
60 | 1ji
61 | 1jo
62 | 1ju
63 | 1jy
64 | 1j^^e4
65 | 1j^^f6
66 | 1ka
67 | 1ke
68 | 1ki
69 | 1ko
70 | 1ku
71 | 1ky
72 | 1k^^e4
73 | 1k^^f6
74 | 1la
75 | 1le
76 | 1li
77 | 1lo
78 | 1lu
79 | 1ly
80 | 1l^^e4
81 | 1l^^f6
82 | 1ma
83 | 1me
84 | 1mi
85 | 1mo
86 | 1mu
87 | 1my
88 | 1m^^e4
89 | 1m^^f6
90 | 1na
91 | 1ne
92 | 1ni
93 | 1no
94 | 1nu
95 | 1ny
96 | 1n^^e4
97 | 1n^^f6
98 | 1pa
99 | 1pe
100 | 1pi
101 | 1po
102 | 1pu
103 | 1py
104 | 1p^^e4
105 | 1p^^f6
106 | 1ra
107 | 1re
108 | 1ri
109 | 1ro
110 | 1ru
111 | 1ry
112 | 1r^^e4
113 | 1r^^f6
114 | 1sa
115 | 1se
116 | 1si
117 | 1so
118 | 1su
119 | 1sy
120 | 1s^^e4
121 | 1s^^f6
122 | 1ta
123 | 1te
124 | 1ti
125 | 1to
126 | 1tu
127 | 1ty
128 | 1t^^e4
129 | 1t^^f6
130 | 1va
131 | 1ve
132 | 1vi
133 | 1vo
134 | 1vu
135 | 1vy
136 | 1v^^e4
137 | 1v^^f6
138 | % ------- Some common words borrowed from other languages -------
139 | % ------- This part could be updated from time to time -------
140 | %
141 | 1st2r % -stressi, -strategia etc.
142 | %
143 | % ------ Some special cases occuring with compound words only ----
144 | % ------ There still remains well known problem as 'kaivos\-aukko' etc.
145 | %a1y (common in borrowed words)
146 | ^^e42y
147 | y1a2
148 | y1o2
149 | o1y
150 | ^^f62y
151 | u1y2
152 | y1u2
153 | ^^f63a2
154 | ^^f63o2
155 | ^^e43a2
156 | ^^e43o2
157 | ^^e41u2
158 | ^^f61u2
159 | a1^^e4 % (a1^^e42 ei mahdollinen!)
160 | a1^^f6
161 | o1^^e4
162 | o1^^f6
163 | u1^^e42
164 | u1^^f62
165 | ^^e42^^e4
166 | ^^f62^^f6
167 | ^^e42^^f6
168 | ^^f62^^e4
169 | % lyhyt/pitka -vokaalipareja, tavallisesti sanarajalla
170 | aa1i2 % maa-ikkuna
171 | aa1e2
172 | aa1o2 % maa-ottelu
173 | aa1u2 % uraa-uurtava
174 | ee1a2 % tee-astia
175 | ee1i2 % tee-istutus
176 | ee1u2 % varietee-uusinta
177 | ee1y2
178 | ii1a2
179 | ii1e2
180 | ii1o2
181 | uu1a2
182 | uu1e2 % puu-esine
183 | uu1o2 % puu-osa
184 | uu1i2 % puu-istutus
185 | e1aa
186 | i1aa
187 | o1aa
188 | u1aa
189 | u1ee
190 | a1uu % kala-uuni
191 | i1uu % ravi-uutiset
192 | e1uu % virhe-uutinen
193 | o1uu % radio-uutiset
194 | ^^e4^^e41i
195 | ^^e4^^e41e
196 | ^^e4^^e43y
197 | i1^^e4^^e4
198 | e1^^e4^^e4
199 | y1^^e4^^e4
200 | i1^^f6^^f6 % yhti-^^f6^^f6n etc.
201 | %i1eu % keski-eurooppalainen
202 | % vokaalikolmikkoja etc. yhdyssanojen rajoissa
203 | % -------- vowel triples by Fred Karlsson
204 | a1ei
205 | a1oi
206 | e1ai
207 | % e1oi % ambiguous for ex. video-ilme (8.3.89)
208 | i1au
209 | % u1oi % ambiguous (8.3.89)
210 | y1ei
211 | ai1a
212 | ai1e
213 | ai1o
214 | ai1u
215 | au1a
216 | au1e
217 | eu1a
218 | ie1a
219 | ie1o
220 | %ie1u % ambiguous
221 | ie1y
222 | io1a2
223 | io1e2
224 | iu1a
225 | iu1e
226 | iu1o
227 | oi1a
228 | oi1e
229 | oi1o
230 | oi1u
231 | o1ui % veto-uistin, himo-uimari etc.
232 | ou1e
233 | ou1o
234 | ue1a
235 | ui1e
236 | uo1a
237 | % uo1i % ambiguous
238 | uo1u
239 | % ---------------- End of vowel triples --------------------
240 | e1^^f62
241 | ^^f61e2
242 | .^^e42 % don't hyphenate ^^e4-lyllinen etc.
243 | %
244 | % The following patterns contain no general scientific rule. They
245 | % are selected more or less intuitively to solve problems
246 | % with common and frequently appearing compound words.
247 | % However, every pattern resolves more than only one
248 | % hyphenation problem.
249 | %
250 | u2s % estaa virheita yhdyssanojen yhteydessa
251 | yli1o2p % yli-opisto etc.
252 | ali1a2v % ali-avaruus etc.
253 | 1sp2li % kuutio-splini etc.
254 | alous1
255 | keus1 % oikeus-oppinut etc.
256 | rtaus1
257 | 2s1ohje % -sohjelma etc.
258 | 2s1a2sia % nais-asianainen etc.
259 | 1a2sian % neuvottelu-asian etc.
260 | 1a2siat % koti-asian (ei kotia-sian)
261 | 1a2sioi % talous-asioita etc.
262 | r2as l2as % tikku-rasia etc
263 | 2s1o2pisk % xs-opiskelija etc
264 | 2n1o2pet
265 | 2s1a2loi
266 | 2n1o2pist % kansan-opisto etc.
267 | 2s1o2pist
268 | 2s1o2sa % xxs-osakas etc.
269 | 2n1o2sa % asian-osainen etc.
270 | alkei2s1
271 | perus1
272 | 2s1i2dea. 2s1i2dean
273 | 2s1e2sity % xs-esitys etc
274 | 2n1e2dus % kansan-edustaja etc.
275 | 2s1ajatu % -ajatus etc.
276 | 2s1ase
277 | 2s1apu
278 | 2s1y2rit % yhteis-yritys etc.
279 | .ydi2n1
280 | .suu2r1a2 % suur-ajot etc.
281 | 2s1y2hti
282 | 2n1otto 2n1oton
283 | 2n1anto 2n1anno
284 | 2n1a2jan 2n1aika
285 | 2n1o2mai
286 | 2n1y2lit
287 | 2s1a2len
288 | 2n1a2len
289 | 1a2siaka2s1
290 | ulo2s1 % ulos-ajo
291 | 2n1a2jo % kiven-ajo
292 | 2s1a2jo
293 | %
294 | % *** The following rules may be used on user's responsibility ***
295 | % *** for example, may be needed with narrow columns ***
296 | % >>>>>>>>>>> a1e a1o e1o o1a u1a <<<<<<<<<<<
297 | %
298 | % ----- Some districting rules by Professor Fred Karlsson's ideas ------
299 | %
300 | b2l 1b2lo bib3li
301 | b2r 1b2ri 1b2ro 1b2ru
302 | d2r 1d2ra
303 | f2l 1f2la
304 | f2r 1f2ra 1f2re
305 | g2l 1g2lo
306 | g2r 1g2ra
307 | k2l
308 | 1k2ra 1k2re 1k2ri
309 | 1k2v 1k2va
310 | p2l
311 | p2r 1p2ro
312 | c2l
313 | q2v 1q2vi
314 | sc2h ts2h
315 | ch2r
316 | }
317 | \endgroup
318 | \endinput
319 |
--------------------------------------------------------------------------------
/priv/hyphenation/original_tex/nohyphbx.tex:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/hyphenation/original_tex/nohyphbx.tex
--------------------------------------------------------------------------------
/priv/hyphenation/tb87nemeth.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/priv/hyphenation/tb87nemeth.pdf
--------------------------------------------------------------------------------
/priv/src/.gitignore:
--------------------------------------------------------------------------------
1 | Makefile
2 | *.erl
3 | *.pfb
4 |
--------------------------------------------------------------------------------
/priv/src/README.txt:
--------------------------------------------------------------------------------
1 | Font description module .erl files and Makefile will be generated here
2 |
--------------------------------------------------------------------------------
/src/eg.hrl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%==========================================================================
23 |
24 | -record(env, {pdf, % PDF process
25 | currentBox, % name of currentBox
26 | template, % current template (Mopdule Name)
27 | page, % current page
28 | dict, % dictionary with keys{free,Page,Box}
29 | % {initialsed, Page, Template}
30 | tagMap % current TagMap (function of the box)
31 | }).
32 |
33 | -record(afm2, {baseFont, % FontName
34 | firstChar, % first char in widths table
35 | lastChar, % last char in Widths table
36 | widths, % the widths table (0=undefined)
37 | kernPairs, % [{{C1,C2},K}]
38 | ascender, % num
39 | capHeight, % num
40 | descender, % num
41 | flags, % num
42 | fontBBox, % {int,int,int,int}
43 | italicAngle, % num
44 | stemV, % num
45 | xHeight}). % num
46 |
47 | -record(info, {creator,creationDate, producer, author, title, subject,
48 | keywords}).
49 |
50 | -record(pdfContext, {
51 | info,
52 | fonts,
53 | font_handler,
54 | images=[],
55 | currentpage,
56 | pages=[],
57 | scripts=[],
58 | mediabox,
59 | procset={undefined,undefined} %% { imageb,imagec }
60 | }).
61 |
62 |
63 | -record(image,{alias,width,height}).
64 |
65 | -record(box,{x=10, % X coordinate of top left hand corner of box
66 | y=800, % Y coordinate of top left hand corner of box
67 | width=210, % Width in points (72 point=1 inch)
68 | leading=12, % leading in points
69 | lines=1, % # lines in box
70 | next=none, % next= none | {DeltaPage, Tag}
71 | free=1, % first free line in the box
72 | grid=false, % plot a grid
73 | bg=default % background color in box= default | {R,G,B}
74 | }).
75 |
76 | -record(tagMap, {name=default, % Tag name
77 | font="Times-Roman", % Font name
78 | color=default, % default | {R,G,B}
79 | size=11, % font size
80 | voff=0, % vertical offset
81 | break=true % can do line breaks in blanks
82 | }).
83 |
84 |
85 | -record(face, {font, pointSize, vOffset, color, breakable}).
86 |
87 |
--------------------------------------------------------------------------------
/src/eg_embed.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Joe Armstrong
24 | %% Purpose: Font embedding code
25 | %%==========================================================================
26 |
27 | -module(eg_embed).
28 |
29 | -export([embed/1,
30 | parse_pfb/1
31 | ]).
32 |
33 |
34 | %% The format of a PBF is specified in 5040.Download_Fonts.pdf
35 | %% It is a sequence of chunks
36 | %% <<128, Type, N1, N2, N3, N4 >> <>
37 | %% <<128, 3>>
38 |
39 | %% Where
40 | %% Type = 1 -> ascii
41 | %% Type = 2 -> binary
42 | %% Len = N1 + N2*256 + N3*256*256 + N4*256*256*256,
43 |
44 | % test() ->
45 | % embed("brush.pfb").
46 |
47 | embed(F) ->
48 | P = parse_pfb(F),
49 | O = lists:map(fun({_,_,B}) -> B end, P),
50 | file:write_file(F ++ ".synth", O).
51 |
52 | %% Parse_pfb -> [{Type,Len,Bin}]
53 | %% The lengths are the required lengths in the
54 | %% object descriptor ...
55 |
56 | parse_pfb(F) ->
57 | {ok, Bin} = file:read_file(F),
58 | _L = parse(Bin).
59 |
60 | parse(<<128,3>>) ->
61 | [];
62 | parse(B) ->
63 | {B1,B2} = split_binary(B, 6),
64 | [128,Type,N1,N2,N3,N4] = binary_to_list(B1),
65 | Len = N1 + N2*256 + N3*256*256 + N4*256*256*256,
66 | %% io:format("Chunk: ~p length=~p~n",[Type, Len]),
67 | case Len of
68 | 0 -> [];
69 | _ ->
70 | {B3,B4} = split_binary(B2, Len),
71 | [{Type,Len,B3}|parse(B4)]
72 | end.
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/src/eg_font_server.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Authors: Joe Armstrong
24 | %%==========================================================================
25 |
26 | -module(eg_font_server).
27 |
28 | -include("eg.hrl").
29 |
30 |
31 | -export([start/0, stop/0, char_width/2, data/1, info/1, kern/2]).
32 |
33 | %% ============================================================================
34 |
35 | start() ->
36 | case lists:member(fonts, ets:all()) of
37 | true ->
38 | true;
39 | false ->
40 | fonts = ets:new(fonts, [named_table,set,public]),
41 | true
42 | end.
43 |
44 | stop() ->
45 | ets:delete(fonts).
46 |
47 | %% available_fonts() ->
48 | %% eg_afm:available_fonts().
49 |
50 | %% ensure_loaded(Font, Index) ->
51 | %% %% io:format("Ensure_loaded font number=~p = ~s~n", [Index, Font]),
52 | %% case ets:lookup(fonts, {info, Index}) of
53 | %% [_] ->
54 | %% true;
55 | %% [] ->
56 | %% case eg_afm:read_font_info(Font) of
57 | %% {ok, {afm_qdh1,Font,Widths,Kern,All}} ->
58 | %% ets:insert(fonts, {{info, Index}, Font}),
59 | %% ets:insert(fonts, {{allData, Font}, All}),
60 | %% lists:foreach(fun({Char,W}) ->
61 | %% ets:insert(fonts,
62 | %% {{width,Index,Char}, W})
63 | %% end, Widths),
64 | %% lists:foreach(fun({KP,W}) ->
65 | %% ets:insert(fonts,
66 | %% {{kern,Index,KP}, W})
67 | %% end, Kern),
68 | %% true;
69 | %% {error, Why} ->
70 | %% exit({cannot_load_font, Why})
71 | %% end
72 | %% end.
73 |
74 | info(Index) ->
75 | case ets:lookup(fonts, {info, Index}) of
76 | [{_,I}] ->
77 | I;
78 | [] ->
79 | exit({font_server_info,Index})
80 | end.
81 |
82 | data(Fontname) ->
83 | case ets:lookup(fonts, {allData, Fontname}) of
84 | [{_,I}] ->
85 | {ok, I};
86 | [] ->
87 | error
88 | end.
89 |
90 | char_width(N, Char) ->
91 | case ets:lookup(fonts, {width,N,Char}) of
92 | [{_,W}] ->
93 | W;
94 | [] ->
95 | io:format("Cannot figure out width of:~p ~p~n",[N, Char]),
96 | io:format("Possible \n in code etc~n"),
97 | 1000
98 | end.
99 |
100 | kern(N, KP) ->
101 | case ets:lookup(fonts, {kern,N,KP}) of
102 | [{_,W}] ->
103 | W;
104 | [] ->
105 | 0
106 | end.
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/src/eg_hyphenate.erl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/src/eg_hyphenate.erl
--------------------------------------------------------------------------------
/src/eg_lib.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Permission is hereby granted, free of charge, to any person obtaining a
3 | %% copy of this software and associated documentation files (the
4 | %% "Software"), to deal in the Software without restriction, including
5 | %% without limitation the rights to use, copy, modify, merge, publish,
6 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
7 | %% persons to whom the Software is furnished to do so, subject to the
8 | %% following conditions:
9 | %%
10 | %% The above copyright notice and this permission notice shall be included
11 | %% in all copies or substantial portions of the Software.
12 | %%
13 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
16 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
20 | %%==========================================================================
21 |
22 | %% shared internal functions
23 |
24 | -module(eg_lib).
25 |
26 | -export([find_files/3, find_files/5,
27 | priv_dir/0, priv_src_dir/0]).
28 |
29 | -include_lib("kernel/include/file.hrl").
30 |
31 |
32 | %% Examples:
33 | %% find_files(".", "*.erl", false)
34 | %% finds all files in the current directory.
35 | %% Recursive scan of sub-directories is also allowed.
36 | %%
37 | %% find_files(Dir, RegExp, Recursive, Fun/2, Acc0)
38 | %% applies Fun(File, Acc) -> Acc. to each file
39 |
40 | find_files(Dir, Re, Flag) ->
41 | Re1 = sh_to_awk(Re),
42 | lists:reverse(find_files(Dir, Re1, Flag,
43 | fun(File, Acc) ->[File|Acc] end, [])).
44 |
45 | find_files(Dir, Reg, Recursive, Fun, Acc) ->
46 | case file:list_dir(Dir) of
47 | {ok, Files} ->
48 | %% sort files of directory to make result stable; otherwise it
49 | %% depends on the file system and can vary between machines
50 | find_files(lists:sort(Files), Dir, Reg, Recursive, Fun, Acc);
51 | {error, _} -> Acc
52 | end.
53 |
54 | find_files([File|T], Dir, Reg, Recursive, Fun, Acc0) ->
55 | FullName = Dir ++ [$/|File],
56 | case file_type(FullName) of
57 | regular ->
58 | case re:run(FullName, Reg) of
59 | {match, _} ->
60 | Acc = Fun(FullName, Acc0),
61 | find_files(T, Dir, Reg, Recursive, Fun, Acc);
62 | nomatch ->
63 | find_files(T, Dir, Reg, Recursive, Fun, Acc0)
64 | end;
65 | directory ->
66 | case Recursive of
67 | true ->
68 | Acc1 = find_files(FullName, Reg, Recursive, Fun, Acc0),
69 | find_files(T, Dir, Reg, Recursive, Fun, Acc1);
70 | false ->
71 | find_files(T, Dir, Reg, Recursive, Fun, Acc0)
72 | end;
73 | error ->
74 | find_files(T, Dir, Reg, Recursive, Fun, Acc0)
75 | end;
76 | find_files([], _, _, _, _, A) ->
77 | A.
78 |
79 | file_type(File) ->
80 | case file:read_file_info(File) of
81 | {ok, Facts} ->
82 | case Facts#file_info.type of
83 | regular -> regular;
84 | directory -> directory;
85 | _ -> error
86 | end;
87 | _ ->
88 | error
89 | end.
90 |
91 | priv_src_dir() ->
92 | filename:join(priv_dir(), "src").
93 |
94 | priv_dir() ->
95 | case code:priv_dir(erlguten) of
96 | {error, _} ->
97 | filename:join(filename:dirname(code:which(?MODULE)),
98 | "../priv");
99 | N ->
100 | N
101 | end.
102 |
103 | %% NOTE: This function is copied from the deprecated stdlib 'regexp' module
104 | %% sh_to_awk(ShellRegExp)
105 | %% Convert a sh style regexp into a full AWK one. The main difficulty is
106 | %% getting character sets right as the conventions are different.
107 |
108 | sh_to_awk(Sh) -> "^(" ++ sh_to_awk_1(Sh). %Fix the beginning
109 |
110 | sh_to_awk_1([$*|Sh]) -> %This matches any string
111 | ".*" ++ sh_to_awk_1(Sh);
112 | sh_to_awk_1([$?|Sh]) -> %This matches any character
113 | [$.|sh_to_awk_1(Sh)];
114 | sh_to_awk_1([$[,$^,$]|Sh]) -> %This takes careful handling
115 | "\\^" ++ sh_to_awk_1(Sh);
116 | sh_to_awk_1("[^" ++ Sh) -> [$[|sh_to_awk_2(Sh, true)];
117 | sh_to_awk_1("[!" ++ Sh) -> "[^" ++ sh_to_awk_2(Sh, false);
118 | sh_to_awk_1([$[|Sh]) -> [$[|sh_to_awk_2(Sh, false)];
119 | sh_to_awk_1([C|Sh]) ->
120 | %% Unspecialise everything else which is not an escape character.
121 | case special_char(C) of
122 | true -> [$\\,C|sh_to_awk_1(Sh)];
123 | false -> [C|sh_to_awk_1(Sh)]
124 | end;
125 | sh_to_awk_1([]) -> ")$". %Fix the end
126 |
127 | sh_to_awk_2([$]|Sh], UpArrow) -> [$]|sh_to_awk_3(Sh, UpArrow)];
128 | sh_to_awk_2(Sh, UpArrow) -> sh_to_awk_3(Sh, UpArrow).
129 |
130 | sh_to_awk_3([$]|Sh], true) -> "^]" ++ sh_to_awk_1(Sh);
131 | sh_to_awk_3([$]|Sh], false) -> [$]|sh_to_awk_1(Sh)];
132 | sh_to_awk_3([C|Sh], UpArrow) -> [C|sh_to_awk_3(Sh, UpArrow)];
133 | sh_to_awk_3([], true) -> [$^|sh_to_awk_1([])];
134 | sh_to_awk_3([], false) -> sh_to_awk_1([]).
135 |
136 | %% Test if a character is a special character.
137 | special_char($|) -> true;
138 | special_char($*) -> true;
139 | special_char($+) -> true;
140 | special_char($?) -> true;
141 | special_char($() -> true;
142 | special_char($)) -> true;
143 | special_char($\\) -> true;
144 | special_char($^) -> true;
145 | special_char($$) -> true;
146 | special_char($.) -> true;
147 | special_char($[) -> true;
148 | special_char($]) -> true;
149 | special_char($") -> true;
150 | special_char(_C) -> false.
151 |
--------------------------------------------------------------------------------
/src/eg_mk_hyphen.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Joe Armstrong
24 | %%==========================================================================
25 |
26 | %% ============================================================================
27 | %% load hyph_*.dic files and create matching eg_hyphen_rules_*.erl
28 | %% ============================================================================
29 |
30 | -module(eg_mk_hyphen).
31 |
32 | -export([start/1,
33 | start/2
34 | ]).
35 |
36 | %% ============================================================================
37 |
38 | %% takes a list of atoms as input, to be called as "erl -s eg_mk_hyphen CC"
39 | start([CC]) ->
40 | start(lists:concat(["hyph_", CC, ".dic"]), CC).
41 |
42 | %% Pass .dic file name and lc_CC (language code and country code) to use
43 | %% in generated eg_hyphen_rules_lc_CC.erl files.
44 | %%
45 | %% * File is expected to start with a line "charset ISO8859-1 ..." or
46 | %% "ISO8859-1 ...", ensuring that the file contains Latin-1 encoded text.
47 | %% * Each NL or CR separated line may contain one hyphen rule.
48 | %% * Trailing and intial spaces are discarded before the rule is processed.
49 | %% * Anything after and including a "%" is treated as a comment an therfore
50 | %% discarded. Lines that are or become blank this way are also discarded.
51 | %% * "\hyphenation" is treated as a special rule that tells us that all rules
52 | %% following it are exceptions to the normal hyphen rules - each such rules
53 | %% contains one hyphenated word e.g. "uni-ver-sity"
54 | %%
55 | %% FileName = string()
56 | %% LangCodeStr = string()
57 | start(FileName, LangCode) ->
58 | {ok, Bin} = file:read_file(filename:join([eg_lib:priv_dir(),
59 | "hyphenation", FileName])),
60 | L = binary_to_list(Bin),
61 | Toks = string:tokens(L, "\n\r"),
62 | %% get lines after initial header
63 | L1 = lines_after_header(Toks),
64 |
65 | %% Find hyphen rules and exceptions
66 | {L2, L3} = split(clear_comments_and_sp(L1)),
67 |
68 | ModuleName = lists:concat(["eg_hyphen_rules_", LangCode]),
69 | {ok, O} = file:open(filename:join([eg_lib:priv_src_dir(),
70 | ModuleName ++ ".erl"]),
71 | [write]),
72 | io:format(O, "%% -*- coding: latin-1 -*-~n", []),
73 | io:format(O, "%% autogenerated do not edit~n",[]),
74 | io:format(O, "%%[{Char,Val}] = after char Char Val is inserted~n",[]),
75 | io:format(O, "-module(" ++ ModuleName ++ ").~n", []),
76 | io:format(O, "-export([hyphens/1, exception/1]).~n~n",[]),
77 |
78 | %% * sort to ensure that alphabetical order
79 | %% * reverse so that exception(...) clauses are generated with the largest
80 | %% match first
81 | Except = lists:reverse(lists:sort(L3)),
82 | lists:foreach(fun(I) -> mk_exception(O, I) end, Except),
83 | io:format(O, "exception(_) -> no.~n~n", []),
84 |
85 | %% * sort to ensure that alphabetical order
86 | %% * reverse so that hyphens(...) clauses are generated with the largest
87 | %% match first
88 | HyphenClauses1 = [jiggle(I) || I <- L2],
89 | HyphenClauses2 = lists:reverse(lists:sort(HyphenClauses1)),
90 | lists:foreach(
91 | fun({S1,S2}) -> io:format(O, "hyphens(\"~s\" ++ _)->~p;~n",[S1,S2]) end,
92 | HyphenClauses2),
93 | io:format(O, "hyphens(_) -> [].~n",[]),
94 |
95 | file:close(O).
96 |
97 |
98 | %% keep only non-empty non-comment content lines
99 | clear_comments_and_sp(Lines) ->
100 | ClearedLines = [string:strip(clear_comments(Line)) || Line <- Lines],
101 | %% discard empty lines
102 | [Line || Line <- ClearedLines, Line /= ""].
103 |
104 |
105 | %% "% ...." -> ""
106 | %% " foo bar % foo bar" -> " foo bar "
107 | clear_comments([]) -> [];
108 | clear_comments([$% | _]) -> [];
109 | clear_comments([C | R]) -> [C | clear_comments(R)].
110 |
111 | %% @split(RuleLines::[string()]) -> {HyhpenRules::[string()],
112 | %% Exceptions::[string()]}
113 | %% extract the hyphen rules and rule exception lines
114 | split(RuleLines) ->
115 | split(RuleLines, []).
116 |
117 | %% only found hyphen rules
118 | split([], HyphenRules) -> {lists:reverse(HyphenRules), []};
119 | %% hyphen rules and rule exceptions found
120 | split(["\\hyphenation" | ExcpL], HyphenRules) -> {lists:reverse(HyphenRules),
121 | ExcpL};
122 | split(["\\" ++ _ | _ExcpL], _) -> throw(unkown_dic_syntax);
123 | split([HyphenRule | R], HyphenRules) -> split(R, [HyphenRule | HyphenRules]).
124 |
125 |
126 | mk_exception(Stream, H) ->
127 | X = remove_hyphens(H),
128 | io:format(Stream, "exception(\"~s\") -> \"~s\";~n",[X, H]).
129 |
130 | remove_hyphens([$-|T]) -> remove_hyphens(T);
131 | remove_hyphens([H|T]) -> [H|remove_hyphens(T)];
132 | remove_hyphens([]) -> [].
133 |
134 |
135 | jiggle(X) ->
136 | jiggle(X, 0, [], []).
137 |
138 | jiggle([], _, L1, L2) ->
139 | {lists:reverse(L1), L2};
140 | jiggle([H|T], N, L1, L2) when H >= $1, H =< $9 ->
141 | jiggle(T, N, L1, [{N,H-$0}|L2]);
142 | jiggle([$0|T], N, L1, L2) ->
143 | io:format("****?~n"),
144 | jiggle(T, N, L1, L2);
145 | jiggle([H|T], N, L1, L2) ->
146 | jiggle(T, N+1, [H|L1], L2).
147 |
148 |
149 | %% we allow any header that ends with a "charset ISO8859-1 ...." or
150 | %% "ISO8859-1 ...." line
151 | lines_after_header(["charset ISO8859-1" ++ _|T]) -> T;
152 | lines_after_header(["ISO8859-1" ++ _|T]) -> T;
153 | lines_after_header([_|T]) -> lines_after_header(T).
154 |
155 |
--------------------------------------------------------------------------------
/src/eg_pdf_annot.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Mikael Karlsson
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Mikael Karlsson
24 | %% Purpose: PDF Annotations
25 | %%==========================================================================
26 |
27 | %% @doc Annotations.
28 | %%
29 | %% Purpose: Create and serialise PDF Annotations
30 | %% Ref. Chapter 8.4 Annotations in PDF reference v1.4
31 | %%
32 | %%
33 | %%
34 | %% - /Type
- /Annot
35 | %% - /Subtype
- name, Required
36 | %% - /Contents
37 | %% - text string. Required or optional depending on subtype
38 | %% - /P
39 | %% - dictionary. Optional indirect ref. to the page object
40 | %% - /Rect
- rectangle. Required
41 | %% - /NM
- text string. Optional, annotation name
42 | %% - /M
43 | %% - Date or string. Optional, last modified date and time
44 | %% - /F
45 | %% - Integer. optional, Flags specifying various characteristics
46 | %% - /BS
- Dictionary. Optional, Border style
47 | %% - /Border
48 | %% - Array. Optional, annotation border characteristics.
49 | %% Use bs inst.
50 | %% - /AP
- Dictionary. Appearance
51 | %% - /AS
52 | %% - Name. Required if ap contains one or more subdirectories.
53 | %% Appearance state, selects applicable appearance stream.
54 | %% - /C
55 | %% - Array of 3 numbers range 0-1. Optional. RGB color, for icon etc.
56 | %% - /CA
57 | %% - Number 0-1, Optional. Constant opacity value 0=no contr. 1=full
58 | %% - /T
- Text string. Optional. Text label in title bar.
59 | %% - /Popup
60 | %% - Dictionary. Optional. Indirect reference to popup annot for edit.
61 | %% - /A
62 | %% - Dictionary. Optional. Action to be performed when activated.
63 | %% - /AA
- Dictionary. Optional. Additional actions
64 | %% - /StructParent
65 | %% - Integer. Required if annotation is a structural content item.
66 | %%
67 | %%
68 | %% @end
69 |
70 | -module(eg_pdf_annot).
71 |
72 | -include("eg.hrl").
73 |
74 |
75 | -export([new_text/2, new_text/3, new_open_text/2, new_open_text/3,
76 | new_link/2, new_link/3, new_action/2, new_line/3, set_flags/2,
77 | andflags/2, orflags/2, contents/1, flag/1, isflagset/2, rect/1,
78 | set_borderstyle/3, style/1, serialise/2]).
79 |
80 | %% ============================================================================
81 |
82 | %% Subtypes
83 | subtype(text) -> {name, "Text"};
84 | subtype(link) -> {name, "Link"};
85 | subtype(freetext) -> {name, "FreeText"};
86 | subtype(line) -> {name, "Line"};
87 | subtype(square) -> {name, "Square"};
88 | subtype(circle) -> {name, "Circle"};
89 | subtype(highlight) -> {name, "Highlight"};
90 | subtype(underline) -> {name, "Underline"};
91 | subtype(squiggly) -> {name, "Squiggly"};
92 | subtype(strikeout) -> {name, "StrikeOut"};
93 | subtype(stamp) -> {name, "Stamp"};
94 | subtype(ink) -> {name, "Ink"};
95 | subtype(popup) -> {name, "Popup"};
96 | subtype(fileattachement) -> {name, "FileAttacheMent"};
97 | subtype(sound) -> {name, "Sound"};
98 | subtype(movie) -> {name, "Movie"};
99 | subtype(widget) -> {name, "Widget"};
100 | subtype(printermark) -> {name, "PrinterMark"};
101 | subtype(trapnet) -> {name, "TrapNet"}.
102 |
103 | contents(Contents) -> {string, Contents}.
104 |
105 | %% @type rect() = {X, Y, Width, Height}
106 | rect({A,B,C,D}) -> {array, [A,B,C,D]}.
107 |
108 | %% Flags
109 | flag(invisible) -> 1;
110 | flag(hidden) -> 2;
111 | flag(print) -> 4;
112 | flag(nozoom) -> 8;
113 | flag(norotate) -> 16;
114 | flag(noview) -> 32;
115 | flag(readonly) -> 64.
116 |
117 |
118 | %% @spec new(Subtype, Rect) -> dict()
119 | %% Rect = {rect, {X,Y, Width, Height}}
120 | new(SubType, {rect,{_X,_Y,_W,_H}} = Rect)->
121 | {dict,[{"Type",{name,"Annot"}},
122 | {"Subtype", subtype(SubType)},
123 | {"Rect", Rect }]}.
124 |
125 | new(SubType, Rect, Contents)->
126 | A = new(SubType, Rect),
127 | set_contents(Contents,A).
128 |
129 | %% @spec new_text(Rect::rect(), Contents::string()) ->
130 | %% text_annotation()
131 | %% @doc Text annotations represents a sticky note
132 |
133 | new_text(Rect, Contents)->
134 | new(text,Rect,Contents).
135 |
136 | %% Default when Name is not given is Note
137 | %% @spec new_text(Rect::rect(), Contents::string(), name()) ->
138 | %% text_annotation()
139 | new_text(Rect, Contents, Name)->
140 | A = new_text(Rect, Contents),
141 | store("Name", name(Name), A).
142 |
143 | %% @spec new_open_text(Rect::rect(), Contents::string()) ->
144 | %% text_annotation()
145 | %% @doc Text annotation that is open
146 |
147 | new_open_text(Rect, Contents)->
148 | A = new_text(Rect, Contents),
149 | store( "Open", true, A ).
150 |
151 | %% @spec new_open_text(Rect::rect(), Contents::string(), name()) ->
152 | %% text_annotation()
153 | new_open_text(Rect, Contents, Name)->
154 | A = new_text(Rect, Contents),
155 | B = store("Name", name(Name), A),
156 | store( "Open", true, B ).
157 |
158 | %% @type name() = comment|help|insert|key|note|paragraph
159 |
160 | name(comment) -> {name, "Comment"};
161 | name(help) -> {name, "Help"};
162 | name(insert) -> {name, "Insert"};
163 | name(key) -> {name, "Key"};
164 | name(newparagraph)-> {name, "NewParagraph"};
165 | name(note) -> {name, "Note"};
166 | name(paragraph) -> {name, "Paragraph"}.
167 |
168 |
169 | %% ------ Link annotations are either hyper text links
170 | %% or actions to performed
171 | %% @spec new_link(Rect::rect(), Dest::destination()) -> dict()
172 | new_link(Rect, Dest)->
173 | A = new(link,Rect),
174 | %% [ PageNo | T ] = Dest,
175 | store("Border",{array,[16,16,1]}, store("Dest", Dest, A )).
176 |
177 |
178 |
179 | %% @spec new_link(Rect::rect(), Dest::destination(), Highlight) -> dict()
180 | %% Highlight = none | invert | outline | push
181 |
182 | new_link(Rect, Dest, Highlight)->
183 | A = new_link(Rect, Dest),
184 | store( "H", highlight(Highlight), A ).
185 |
186 |
187 |
188 | highlight(none) -> {name, "N"};
189 | highlight(invert) -> {name, "I"}; %% Default
190 | highlight(outline) -> {name, "O"};
191 | highlight(push) -> {name, "P"}.
192 |
193 |
194 | %% Action is a predefined action dictionary
195 | new_action(Rect, {action, Action})->
196 | A = new(link, Rect),
197 | store("A", {action, Action}, A).
198 |
199 | %% ------ Line annotations
200 | new_line(Rect, Contents, {Point1, Point2})->
201 | A = new(line,Rect, Contents),
202 | {X1, Y1} = Point1, {X2, Y2} = Point2,
203 | store("L", {array,[X1, Y1, X2, Y2]}, A ).
204 |
205 |
206 | set_contents(Contents, Annot)->
207 | store("Contents", {string,Contents}, Annot).
208 |
209 | store(Key, Value, Dict)->
210 | eg_pdf_lib:store_in_dict({Key, Value}, Dict).
211 |
212 |
213 | set_borderstyle(Width, Style, Annot)->
214 | S = style(Style),
215 | A = {dict,[{"Type",{name,"Border"}},
216 | {"W", Width},
217 | {"S", S}]},
218 | store("BS", A, Annot).
219 |
220 | style(solid) -> {name, "S"};
221 | style(dashed) -> {name, "D"};
222 | style(beveled) -> {name, "B"};
223 | style(inset) -> {name, "I"};
224 | style(underline) -> {name, "U"}.
225 |
226 | %% Annotation flags
227 |
228 | orflags(Flag, Flags)->
229 | flag(Flag) bor Flags.
230 |
231 | andflags(Flag, Flags)->
232 | flag(Flag) band Flags.
233 |
234 | isflagset(Flag, Flags)->
235 | case andflags(Flag, Flags) of
236 | 0 ->
237 | false;
238 | _ ->
239 | true
240 | end.
241 |
242 | set_flags(Flags, Annot)->
243 | store("F", Flags, Annot).
244 |
245 |
246 |
247 | serialise(Annots, I)->
248 | serialise(Annots, I, [], []).
249 |
250 | serialise([], I, Is, Os) ->
251 | A = {{obj,I,0},{array,lists:map(fun(J) ->
252 | {ptr,J,0}
253 | end,
254 | lists:reverse(Is))}},
255 | {I+1, {ptr,I,0}, lists:reverse([A|Os])};
256 | serialise([H|T], I, Fs, E) ->
257 | O = mk_annot(I, H),
258 | serialise(T, I+1, [I|Fs], [O|E]).
259 |
260 | mk_annot(I, {annot,A}) ->
261 | {{obj,I,0},
262 | {dict,dict:to_list(A)}
263 | }.
264 |
--------------------------------------------------------------------------------
/src/eg_pdf_image.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Mikael Karlsson
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Mikael Karlsson
24 | %% Purpose: Import images to PDF
25 | %%==========================================================================
26 |
27 | -module(eg_pdf_image).
28 |
29 | %% Purpose: Import images from file, currently jpg only
30 | %% Pack into XObjects
31 | %%
32 |
33 | -export([mk_images/4, get_head_info/1, process_header/1]).
34 |
35 | -include("eg.hrl").
36 |
37 | %% ============================================================================
38 |
39 |
40 | mk_images([], I, Is, Os) ->
41 | A = {{obj,I,0},{dict,lists:map(fun({Alias, ImageIndex}) ->
42 | {Alias, {ptr,ImageIndex,0}}
43 | end,
44 | lists:reverse(Is))}},
45 | {I+1, {ptr,I,0}, lists:reverse([A|Os])};
46 | mk_images([{ImageURI, #image{alias=Alias}=Im}|T], I, Fs, E) ->
47 | O = mk_image(I, ImageURI, Im),
48 | mk_images(T, I+1, [{Alias,I}|Fs], [O|E]).
49 |
50 | mk_image(I, File, #image{alias=_Alias, width=W, height=H}) ->
51 | Image = read_image(File),
52 | case process_header(Image) of
53 | {jpeg_head,{Width, Height, Ncomponents, Data_precision}} ->
54 | Extras = [{"Filter", {name,"DCTDecode"}},
55 | {"ColorSpace",{name, colorspace(Ncomponents)}},
56 | {"BitsPerComponent", Data_precision}];
57 | _ ->
58 | {Width, Height} = {W,H},
59 | Extras = []
60 | end,
61 | {{obj,I,0},
62 | {stream,
63 | {dict,[{"Type",{name,"XObject"}},
64 | {"Subtype",{name,"Image"}},
65 | {"Width",Width},
66 | {"Height", Height}| Extras ]},
67 | Image}
68 | }.
69 |
70 |
71 | colorspace(0)-> "DeviceGray";
72 | colorspace(1)-> "DeviceGray";
73 | colorspace(2)-> "DeviceGray";
74 | colorspace(3)-> "DeviceRGB";
75 | colorspace(4)-> "DeviceCMYK".
76 |
77 | read_image(File) ->
78 | {ok, Image} = file:read_file(File),
79 | Image.
80 |
81 | get_head_info(File) ->
82 | process_header(read_image(File)).
83 |
84 | %% JPEG support
85 | -define(SOF0, 16#C0). %% Start Of Frame
86 | -define(SOF1, 16#C1). %% Digit indicates compression type
87 | -define(SOF2, 16#C2). %% Only SOF0-SOF2 are now in common use
88 | -define(SOF3, 16#C3).
89 | -define(SOF5, 16#C5).
90 | -define(SOF6, 16#C6).
91 | -define(SOF7, 16#C7).
92 | -define(SOF9, 16#C9).
93 | -define(SOF10, 16#CA).
94 | -define(SOF11, 16#CB).
95 | -define(SOF13, 16#CD).
96 | -define(SOF14, 16#CE).
97 | -define(SOF15, 16#CF).
98 | -define(SOI, 16#D8). %% Start Of Image (beginning of file)
99 | -define(EOI, 16#D9). %% End Of Image
100 | -define(SOS, 16#DA). %% Start Of Scan (begin of compressed data)
101 | %% -define(APP0, 16#E0). %% Application-specific markers, don't bother
102 | %% -define(APP12, 16#EC).
103 | %% -define(COM, 16#FE). %% Comment
104 |
105 |
106 | %% JPEG file
107 | process_header( << 16#FF:8, ?SOI:8, Rest/binary >> )->
108 | process_jpeg( Rest );
109 | process_header(_Any) ->
110 | image_format_not_yet_implemented_or_unknown.
111 |
112 |
113 | %% JPEG file header processing
114 |
115 | %% Skip any leading 16#FF
116 | process_jpeg( << 16#FF:8,Rest/binary >> ) -> process_jpeg(Rest);
117 |
118 | %% Codes 0xC4, 0xC8, 0xCC shall not be treated as SOFn.
119 | process_jpeg( << ?SOF0:8,Rest/binary >> ) -> jpeg_sof( Rest);
120 | process_jpeg( << ?SOF1:8,Rest/binary >> ) -> jpeg_sof( Rest);
121 | process_jpeg( << ?SOF2:8,Rest/binary >> ) -> jpeg_sof( Rest);
122 | process_jpeg( << ?SOF3:8,Rest/binary >> ) -> jpeg_sof( Rest);
123 | process_jpeg( << ?SOF5:8,Rest/binary >> ) -> jpeg_sof( Rest);
124 | process_jpeg( << ?SOF6:8,Rest/binary >> ) -> jpeg_sof( Rest);
125 | process_jpeg( << ?SOF7:8,Rest/binary >> ) -> jpeg_sof( Rest);
126 | process_jpeg( << ?SOF9:8,Rest/binary >> ) -> jpeg_sof( Rest);
127 | process_jpeg( << ?SOF10:8,Rest/binary >> ) -> jpeg_sof(Rest);
128 | process_jpeg( << ?SOF11:8,Rest/binary >> ) -> jpeg_sof(Rest);
129 | process_jpeg( << ?SOF13:8,Rest/binary >> ) -> jpeg_sof(Rest);
130 | process_jpeg( << ?SOF14:8,Rest/binary >> ) -> jpeg_sof(Rest);
131 | process_jpeg( << ?SOF15:8,Rest/binary >> ) -> jpeg_sof(Rest);
132 | process_jpeg( << ?SOS:8,_Rest/binary >> ) ->[];
133 | process_jpeg( << ?EOI:8,_Rest/binary >> ) -> jeoi; %% Tables only
134 | process_jpeg( << _Any:8, Rest/binary >> )->process_jpeg(skip_marker(Rest));
135 | process_jpeg( << >> ) -> [].
136 |
137 | jpeg_sof ( Rest )->
138 | << Length:16, Data_precision:8, Height:16, Width:16,
139 | Ncomponents:8, Rest2/binary >> = Rest, Complen = Ncomponents * 3,
140 | Length = Complen + 8, %% This is a guard that will cause an error exception
141 | << _SkipComponents:Complen/binary, _Rest3/binary >> = Rest2,
142 | {jpeg_head,{Width, Height, Ncomponents, Data_precision}}.
143 | %% process_jpeg(Rest3)].
144 |
145 | skip_marker(Image)->
146 | << Length:16, Rest/binary >> = Image,
147 | AdjLen = Length-2,
148 | << _Skip:AdjLen/binary, Rest2/binary >> = Rest,
149 | Rest2.
150 |
--------------------------------------------------------------------------------
/src/eg_pdf_obj.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Mikael Karlsson
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Authors: Mikael Karlsson
24 | %% Joe Armstrong
25 | %% Purpose: PDF objects api
26 | %%==========================================================================
27 |
28 | %%
29 | %% @doc PDF Objects.
30 | %%
31 | %% Purpose: Create and manipulate PDF Objects
32 | %%
33 | %%
34 | %% @end
35 |
36 | -module(eg_pdf_obj).
37 |
38 | -export([catalogue/2, info/1, destination/2, fonts/2]).
39 |
40 | %% ============================================================================
41 |
42 | %% @spec catalogue(PagesRef::integer(), Options) -> dict()
43 | %% Options = [Option]
44 | %% Option = {'"Version"', name()} | {'"PageLabels"', number_tree()} |
45 | %% {'"Names"', dict()}
46 | %% Ref = integer()
47 | %% @doc Creates a Catalogue dictionary.
48 | %% @see eg_pdf_lib
49 | catalogue(PagesRef, Options) ->
50 | {dict,[{"Type",{name,"Catalog"}},
51 | {"Pages",{ptr, PagesRef,0}}|
52 | lists:map( fun catalogue_opt/1, Options)]}.
53 | catalogue_opt({"Version" = A, {name, _}} = B) ->
54 | {A, B};
55 | catalogue_opt({"PageLabels" = A, {number_tree, _ } = B}) ->
56 | {A, B};
57 | catalogue_opt({"Names" = A, {dict, _ } = B}) ->
58 | {A, B}.
59 |
60 |
61 | %% @spec info(Options) -> dict()
62 | %% Options = [Option]
63 | %% Option = {'"Creator"', string()} | {'"CreationDate"', Date} |
64 | %% {'"Producer"', string()} | {'"Author"', string()} | {'"Title"', string()} |
65 | %% {'"Subject"', string()} | {'"Keywords"', string()}
66 | %% @doc Creates a PDF Info dictionary.
67 | info(Options) ->
68 | {dict, lists:map( fun info_opt/1, Options)}.
69 |
70 | info_opt({"Creator" = A, B}) ->
71 | { A, {string, B}};
72 | info_opt({"CreationDate" = A, B }) ->
73 | { A, {date, B}};
74 | info_opt({"Producer" = A, B}) ->
75 | { A, {string, B}};
76 | info_opt({"Author"= A, B}) ->
77 | { A, {string, B}};
78 | info_opt({"Title"= A, B}) ->
79 | { A, {string, B}};
80 | info_opt({"Subject" = A, B}) ->
81 | { A , {string, B}};
82 | info_opt({"Keywords" = A, B}) ->
83 | { A, {string, B}}.
84 |
85 |
86 |
87 | %% @spec destination(PageRef::integer(), BoundBox) -> array()
88 | %% BoundBox = {'"XYZ"', Left, Top, Zoom } | '"Fit"' |
89 | %% {'"FitH"', Top} | {'"FitV"', Left} |
90 | %% {'"FitR"', Left, Bottom, Right, Top} | '"FitB"' |
91 | %% {'"FitBH"', Top} | {'"FitBV"', Left}
92 | %% Top = integer()
93 | %% Bottom = integer()
94 | %% Right = integer()
95 | %% Bottom = integer()
96 | %% Zoom = null | number()
97 | %% @doc Creates a destination array.
98 | %% PageRef is the indirect reference Ptr to the Page Object.
99 | %% see also: PDF reference chapter 8.2.1 Destinations
100 | destination(PageRef, {"XYZ", Left, Top, Zoom }) ->
101 | {array,[{ptr, PageRef, 0}, {name,"XYZ"}, Left, Top, Zoom ]};
102 | destination(PageRef, "Fit") ->
103 | {array,[{ptr, PageRef, 0}, {name,"Fit"}]};
104 | destination(PageRef, {"FitH", Top}) ->
105 | {array,[{ptr, PageRef, 0}, {name,"FitH"}, Top ]};
106 | destination(PageRef, {"FitV", Left}) ->
107 | {array,[{ptr, PageRef, 0}, {name,"FitV"}, Left ]};
108 | destination(PageRef, {"FitR", Left, Bottom, Right, Top}) ->
109 | {array,[{ptr, PageRef, 0}, {name,"FitR"}, Left, Bottom, Right, Top ]};
110 | destination(PageRef, "FitB") ->
111 | {array,[{ptr, PageRef, 0}, {name,"FitB"} ]};
112 | destination(PageRef, {"FitBH", Top}) ->
113 | {array,[{ptr, PageRef, 0}, {name,"FitBH"}, Top ]};
114 | destination(PageRef, {"FitBV", Left}) ->
115 | {array,[{ptr, PageRef, 0}, {name,"FitBH"}, Left ]}.
116 |
117 | %% ==========================================================
118 | %% Fonts
119 | %% ==========================================================
120 |
121 | %% @spec fonts(Fonts, Objects::pdftype()) -> {FontsPtr, Objects}
122 |
123 | fonts(Fonts, Objects) ->
124 | Free0 = eg_pdf_lib:get_next_ref(Objects),
125 | Fonts1 = lists:map(fun(I) -> eg_font_map:handler(I) end, Fonts),
126 | {_Free,FontsPtr,O1s} = mk_fonts(Fonts1, Free0, [], []),
127 | {FontsPtr, eg_pdf_lib:store_object(O1s, Objects)}.
128 |
129 | mk_fonts([], I, Fs, Os) ->
130 | A = {{obj,I,0},{dict,lists:map(fun({Alias, FontObj}) ->
131 | {Alias, {ptr,FontObj,0}}
132 | end, lists:reverse(Fs))}},
133 | {I+1, {ptr,I,0}, lists:reverse([A|Os])};
134 | mk_fonts([Handler|T], I, Fs, E) ->
135 | %% io:format("I need the font:~p~n",[Handler]),
136 | Index = Handler:index(),
137 | Alias = "F" ++ eg_pdf_op:i2s(Index),
138 | case Handler:type() of
139 | internal ->
140 | O = {{obj,I,0},mkFont(Handler)},
141 | mk_fonts(T, I+1, [{Alias,I}|Fs], [O|E]);
142 | {Index, pdf_builtin} ->
143 | O1 = {{obj,I,0}, mkFont1(Handler, I+1, Index)},
144 | O2 = {{obj,I+1,0}, mkFontDescriptor(Handler, false, 0)},
145 | mk_fonts(T, I+2, [{Alias,I}|Fs], [O2,O1|E]);
146 | external ->
147 | O1 = {{obj,I,0}, mkFont1(Handler, I+1, Index)},
148 | O2 = {{obj,I+1,0}, mkFontDescriptor(Handler, true,I+2)},
149 | O3 = {{obj,I+2,0}, mkFontFile(Handler)},
150 | mk_fonts(T, I+3, [{Alias,I}|Fs], [O3,O2,O1|E])
151 | end.
152 |
153 | %% mkFont is used for the 14 inbuilt fonts
154 | mkFont(FontHandler) ->
155 | Index = FontHandler:index(),
156 | Alias = "F" ++ eg_pdf_op:i2s(Index),
157 | %% io:format("mkFont Alias=~s FontHandler=~p~n",[Alias, FontHandler]),
158 | {dict,[{"Type",{name,"Font"}},
159 | {"Subtype",{name,"Type1"}},
160 | {"Name",{name,Alias}},
161 | {"BaseFont",{name,FontHandler:fontName()}},
162 | {"Encoding",{name,encoding(FontHandler)}}]}.
163 |
164 | encoding(M) ->
165 | %% Change the encoding to "MacRomanEncoding" except for
166 | %% "FontSpecific" encodings ...
167 | %% This seems to work for everything except those fonts
168 | %% which have a "FontSpecif" encoding.
169 | %% *usally the encoding in the AFM file is
170 | %% "AdobeStandardEncoding" - but this gives an error
171 | %% for fonts with encoding "AppleStandard". Setting
172 | %% *everything* to MacRomanEncoding seems to work for all cases
173 | %% except Zapfdingblats which is "FontSpecific"
174 | %% - this might not work with files produced on an apple ?
175 | %% - I have not yet tested this on an apple
176 | case M:encoding() of
177 | S = "FontSpecific" ->
178 | S;
179 | _ ->
180 | "MacRomanEncoding"
181 | end.
182 |
183 | mkFont1(M, FontDescriptorPrt, Index) ->
184 | FirstChar = M:firstChar(),
185 | LastChar = M:lastChar(),
186 | Widths = make_width(M:encoding(), M, FirstChar, LastChar),
187 | {dict,[{"Type",{name,"Font"}},
188 | {"Subtype",{name,"Type1"}},
189 | {"Name",{name,"F" ++ eg_pdf_op:i2s(Index)}},
190 | {"BaseFont",{name,M:fontName()}},
191 | {"Encoding",{name,encoding(M)}},
192 | {"FirstChar",FirstChar},
193 | {"LastChar",LastChar},
194 | {"Widths", {array,Widths}},
195 | {"FontDescriptor",{ptr,FontDescriptorPrt,0}}]}.
196 |
197 | make_width("AdobeStandardEncoding", M, F, L) ->
198 | Seq = lists:seq(F,L),
199 | Fu = fun(unknown) -> 0;
200 | (X) -> X
201 | end,
202 | Map = eg_convert:mac2pdf(Seq),
203 | [Fu(M:width(X)) || X <- Map];
204 | make_width(_, M, _, _) ->
205 | M:widths().
206 |
207 | mkFontDescriptor(M, Embedded, I) ->
208 | {X1,X2,X3,_X4} = M:fontBBox(),
209 | %% io:format("Flags FIXED to 6 ...~n"),
210 | FontBBox = [X1,X2,X3,X3],
211 | D0 = [{"Type",{name,"FontDescriptor"}},
212 | {"Ascent", M:ascender()},
213 | {"CapHeight", M:capHeight()},
214 | {"Descent", M:descender()},
215 | {"Flags", M:flags()},
216 | {"FontBBox",{array,FontBBox}},
217 | {"FontName",{name,M:fontName()}},
218 | {"ItalicAngle",M:italicAngle()},
219 | {"StemV",M:stemV()},
220 | {"XHeight",M:xHeight()}],
221 | D = case Embedded of
222 | true ->
223 | [{"FontFile", {ptr,I,0}}|D0];
224 | false ->
225 | D0
226 | end,
227 | {dict, D}.
228 |
229 | %% {{obj,8,0},
230 | %% {dict,[{"Type",{name,"FontDescriptor"}},
231 | %% {"Ascent",890},
232 | %% {"CapHeight",707},
233 | %% {"Descent",65306},
234 | %% {"Flags",6},
235 | %% {"FontBBox",{array,[-100,-65311,1218,895]}},
236 | %% {"FontName",{name,"UtopiaMedium"}},
237 | %% {"ItalicAngle",0},
238 | %% {"StemV",80},
239 | %% {"XHeight",512},
240 | %% {"FontFile",{ptr,9,0}}]}},
241 | %% {{obj,9,0},
242 | %% {stream,94215,
243 | %% "stream_9_0_94215",
244 | %% [{"Length",94215},
245 | %% {"Length1",5750},
246 | %% {"Length2",87922},
247 | %% {"Length3",543}]}},
248 |
249 | mkFontFile(Handler) ->
250 | {Len,Len1,Len2,Len3,Bin} = get_font_program(Handler),
251 | {stream,{dict,[{"Length",Len},
252 | {"Length1",Len1},
253 | {"Length2",Len2},
254 | {"Length3",Len3}]},
255 | Bin}.
256 |
257 |
258 | get_font_program(Handler) ->
259 | File = filename:join(eg_lib:priv_src_dir(),
260 | atom_to_list(Handler) ++ ".pfb"),
261 | %% io:format("reading Font from:~s~n",[File]),
262 | P = eg_embed:parse_pfb(File),
263 | case P of
264 | [{_,L1,B1},{_,L2,B2},{_,L3,B3}|_] ->
265 | {L1+L2+L3,L1,L2,L3,list_to_binary([B1,B2,B3])};
266 | _ ->
267 | error
268 | end.
269 |
--------------------------------------------------------------------------------
/src/eg_pdf_page.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2004 Mikael Karlsson
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Mikael Karlsson
24 | %% Purpose: PDF Pages
25 | %%==========================================================================
26 |
27 | %% @doc Page.
28 | %%
29 | %% Purpose: Create PDF Pages
30 | %% Ref. Chapter 3.6.2 Page objects in PDF reference v1.4
31 | %%
32 | %%
33 | %%
34 | %% - /Type
- /Page
35 | %% - /Parent
- dictionary, Required; indirect reference. The parent
36 | %% page tree node.
37 | %% - /LastModified
38 | %% - date, Required if PieceInfo
39 | %% - /Resources
40 | %% - dictionary. Required, inheritable. The resources required by the
41 | %% page.
42 | %% - /MediaBox
- rectangle. Required, inheritable. Boundaries
43 | %% of physical medium.
44 | %% - /CropBox
- rectangle. Optional, inheritable. Visible region
45 | %% of default user space. Defaults to value of MediaBox
46 | %% - /BleedBox
47 | %% - rectangle, Optional. Clipping region for production environment.
48 | %% Defaults to value of CropBox.
49 | %% - /TrimBox
50 | %% - rectangle, Optional. Intended dimensions of finished page after
51 | %% trimming.
52 | %% - /ArtBox
- rectangle, Optional.
53 | %% Intended dimensions of the finished page after trimming.
54 | %% - /BoxColorInfo
55 | %% - dictionary, Optional. Se PDF reference
56 | %% - /Contents
- stream or array. Content stream.
57 | %% - /Rotate
58 | %% - integer, Optional, inheritable. The number of degrees the page
59 | %% is rotated cloclwise when displayed.
60 | %% - /Group
61 | %% - dictionary, Optional. See PDF reference
62 | %% - /Thumb
- stream, Optional. Stream object defining the page's
63 | %% thumbnail image.
64 | %% - /B
- array, Optional. Array of indirect references to
65 | %% article beads appearing on the page.
66 | %% - /Dur
- number, Optional. Display duration in number of
67 | %% seconds during presentations.
68 | %% - /Trans
- dictionary, Optional. Transition dictionary
69 | %% for presentations
70 | %% - /Annots
- array, Optional. Array of annotation
71 | %% dictionaries.
72 | %% - /AA
- dictionary, Optional. Additional actions dictionary
73 | %% - /Metadata
- stream, Optional. Metadata for the page
74 | %% - /PieceInfo
- dictionary, Optional. See PDF reference.
75 | %% - /StructParents
- integer, Required if the page contains
76 | %% structural content items.
77 | %% - /ID
- string, Optional. Digital id of the page parent Web
78 | %% Capture content set.
79 | %% - /PZ
- number, Optional. Preferred zoom factor.
80 | %% - /SeparationInfo
- dictionary, Optional. Separation dictionary
81 | %% to generate color separations fopr the page.
82 | %%
83 | %%
84 | %% @end
85 |
86 | -module(eg_pdf_page).
87 |
88 | -export([page/3,
89 | append_page/2,
90 | append_page2tree/2,
91 | append_to_page/3,
92 | get_page/2,
93 | get_page_contents/2,
94 | page_tree/5]).
95 |
96 | %% ============================================================================
97 |
98 |
99 | %% @spec page(ParenRef::integer(), ContentRef::integer(), Options) -> dict()
100 | %% Options = [Option]
101 | %% Option = {'"LastModified"', date()} | {'"Resources"', dict() } |
102 | %% {'"Annots"', array() } | {Key, pdftype()}
103 | page(ParentRef, ContentsRef, Options) ->
104 | {dict, [{"Type", {name,"Page"}},
105 | {"Parent", {ptr,ParentRef,0}},
106 | {"Contents", {ptr, ContentsRef, 0}}
107 | | lists:map( fun page_opt/1, Options ) ]}.
108 |
109 | page_opt({"LastModified" = A, {date, Date}}) ->
110 | {A,{date, Date}};
111 | page_opt({"Resources", {dict,_}} = A) ->
112 | A;
113 | page_opt({"Resources", {ptr,_,_}} = A) ->
114 | A;
115 | page_opt({"Annots", _}=A ) ->
116 | A;
117 | page_opt({A,B}) ->
118 | {A,B}.
119 |
120 | %% @spec page_tree(KidRefs, FontsPtr::ptr(), XObjectsPtr::ptr(),
121 | %% MediaBox::rect(), ProcSet) -> dict()
122 | %% KidRefs = [ number() ]
123 | %% ProcSet = imageb | imagec | imagebc
124 | %% @doc Creates a Pages (Page Tree) dictionary
125 | page_tree(KidRefs, FontsPtr, XObjectsPtr, MediaBox = {rect,{_A,_B,_C,_D}},
126 | ProcSet ) ->
127 | ImProcSet = case ProcSet of
128 | imagebc -> [{name, "ImageB"},{name, "ImageC"}];
129 | imageb -> [{name, "ImageB"}];
130 | imagec -> [{name, "ImageC"}];
131 | _ -> []
132 | end,
133 | {dict,[{"Type",{name,"Pages"}},
134 | {"Count",length(KidRefs)},
135 | {"MediaBox", MediaBox },
136 | {"Kids",{array, lists:map(fun(I) ->{ptr,I,0} end, KidRefs)}},
137 | {"Resources",
138 | {dict,[{"Font", FontsPtr },{"XObject", XObjectsPtr },
139 | {"ProcSet", {array,[{name,"PDF"},{name,"Text"} |
140 | ImProcSet]}}]}}]}.
141 |
142 |
143 | append_page(PageContents, Objects) ->
144 | [PageTreeObj] = eg_pdf_lib:get_objects_of_type("Pages", Objects),
145 | PTRef = eg_pdf_lib:get_ref(PageTreeObj),
146 | {ContentRef,Objects1} = eg_pdf_lib:add_object({stream, PageContents},
147 | Objects),
148 | {PageRef, Objects2} = eg_pdf_lib:add_object(page(PTRef,ContentRef,[]),
149 | Objects1),
150 | NewPTreeItem = append_page2tree(PageRef, eg_pdf_lib:pdf_item(PageTreeObj)),
151 | Objects3 = eg_pdf_lib:store_object(
152 | eg_pdf_lib:make_object(PTRef, NewPTreeItem), Objects2),
153 | Objects3.
154 |
155 |
156 | append_page2tree(Ref, PageTreeItem) ->
157 | Key = "Kids",
158 | {array, Kids} = eg_pdf_lib:find_in_dict(Key, PageTreeItem),
159 | NewKids = Kids ++ [{ptr, Ref, 0}],
160 | eg_pdf_lib:store_in_dict({Key, {array, NewKids}}, PageTreeItem).
161 |
162 | get_page(PageNo, Objects) ->
163 | [PageTreeObj] = eg_pdf_lib:get_objects_of_type("Pages", Objects),
164 | PageTree = eg_pdf_lib:pdf_item(PageTreeObj),
165 | {array, Kids} = eg_pdf_lib:find_in_dict("Kids", PageTree),
166 | PagePtr = lists:nth(PageNo, Kids),
167 | case eg_pdf_lib:search_object(PagePtr, Objects) of
168 | {value, Object} ->
169 | Object;
170 | false ->
171 | no_page_available
172 | end.
173 |
174 | get_page_contents(PageObj, Objects) ->
175 | PageDict = eg_pdf_lib:pdf_item(PageObj),
176 | case eg_pdf_lib:find_in_dict("Contents", PageDict) of
177 | {ptr, _I, _J} = Ptr ->
178 | {value, Object} = eg_pdf_lib:search_object(Ptr, Objects),
179 | Object;
180 | PtrList ->
181 | lists:map(fun(Ptr) ->
182 | {value, Object} = eg_pdf_lib:search_object(Ptr, Objects),
183 | Object
184 | end, PtrList)
185 | end.
186 |
187 | append_to_page(S, PageObj, Objects) ->
188 | {Key, {stream, Str}} = get_page_contents(PageObj, Objects),
189 | eg_pdf_lib:store_object({Key, {stream, Str ++ S}}, Objects).
190 |
191 |
192 |
193 |
--------------------------------------------------------------------------------
/src/eg_richText.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Permission is hereby granted, free of charge, to any person obtaining a
3 | %% copy of this software and associated documentation files (the
4 | %% "Software"), to deal in the Software without restriction, including
5 | %% without limitation the rights to use, copy, modify, merge, publish,
6 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
7 | %% persons to whom the Software is furnished to do so, subject to the
8 | %% following conditions:
9 | %%
10 | %% The above copyright notice and this permission notice shall be included
11 | %% in all copies or substantial portions of the Software.
12 | %%
13 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
14 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
15 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
16 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
17 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
18 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
19 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
20 | %%==========================================================================
21 |
22 | -module(eg_richText).
23 |
24 | %% OLD AND BROKEN doc ?! (see modern version further down)
25 |
26 | %% encapsulates operations on text() and inline() objects
27 |
28 | %% ADT
29 | %% +deftype richText() = {richText, [inLine()]
30 | %% +deftype inLine() = Word | FixedString | Opaque | Space | NL
31 | %% +deftype Word = {word, Width, Face, Str},
32 | %% +deftype FixedStr = {fixedStr, Width, Face, Str},
33 | %% +deftype Opaque = {opaque, Width, X}
34 | %% +deftype Space = {space, Width, Face}
35 | %% +deftype NL = {nl, Face}
36 | %% +deftype Face = {Font, PointSize, Voffset, Color, Breakable}
37 | %% +deftype Color = default | {R,G,B}
38 |
39 | %% Interface
40 | %% str2text(Foint, PointSize, Str) -> text()
41 | %% text2str(text()) -> str().
42 |
43 | %% ----------------------------------------------------------------------------
44 | %% This is what str2richText/6 returns, above ADT and Interface appears to be
45 | %% out of date.
46 | %%
47 | %% @type richText() = {richText, [inLine()]}
48 | %% @type inLine() = word() | space() | nl()
49 | %% @type word() = {word, Width::thousendth_pt(), Face::record(face),
50 | %% Str::string()}
51 | %% @type space() = {space, Width::thousendth_pt(), Face::record(face)}
52 | %% @type nl() = {nl, Face::record(face)}
53 | %% @type thousendth_pt() = integer()
54 | %% @end
55 | %% ----------------------------------------------------------------------------
56 |
57 | -export([test/1,
58 | cloan_space/1,
59 | cloan_word/2,
60 | font/1,
61 | fontFromFace/1,
62 | classify_inline/1,
63 | widthExcludingSpaces/1,
64 | pointSize/1,
65 | width/1,
66 | color/1,
67 | is_face_breakable/1,
68 | is_breakable/1,
69 | is_space/1,
70 | is_nl/1,
71 | is_word/1,
72 | lineWidth/1,
73 | numberOfSpaces/1,
74 | mk_test_word/1,
75 | mk_face/5,
76 | mk_fixedStr/2,
77 | mk_word/2,
78 | mk_nl/1,
79 | mk_space/1,
80 | string/1,
81 | str2richText/1,
82 | str2richText/2,
83 | str2richText/6,
84 | richText2str/1,
85 | width_of/3
86 | ]).
87 |
88 |
89 | -include("eg.hrl").
90 |
91 |
92 | %% -define(DEBUG, true).
93 |
94 | -ifdef(DEBUG).
95 | dbg_io(Str) -> dbg_io(Str,[]).
96 | dbg_io(Str,Args) ->
97 | io:format("eg_richText: ~p " ++ Str, [self()] ++ Args),
98 | ok.
99 | -else.
100 | dbg_io(_) -> ok.
101 | dbg_io(_,_) -> ok.
102 | -endif.
103 |
104 |
105 | test(1) ->
106 | str2richText("TimesDutch", 12, 0, default, true,
107 | "Hello joe how are you today?
108 | May I take this opportunity
109 | of saying
110 | that my favorite color is blue.
111 | Have a nice day,
112 | from Mr. C. Computer.").
113 |
114 | richText2str({richText, L}) ->
115 | eg_pdf_op:flatten(lists:map(fun inline2str/1, L)).
116 |
117 | inline2str({word,_,_Face,Str}) -> Str;
118 | inline2str({space,_, _}) -> " ";
119 | inline2str({nl,_}) -> "\n";
120 | inline2str({fixedStr,_,_Face,Str}) -> Str;
121 | inline2str(_) -> "".
122 |
123 | %% ----------------------------------------------------------------------------
124 | str2richText(Str) ->
125 | str2richText("Times-Roman", 12, 0, default, true, Str).
126 |
127 | str2richText(Str, Pts) ->
128 | str2richText("Times-Roman", Pts, 0, default, true, Str).
129 |
130 | %% ----------------------------------------------------------------------------
131 | %% @spec str2richText(Font, Point, Voff, Color, Break, Str) -> richText()
132 | %% @doc convert string to "word" sequence containing word font/size info
133 | %% @end------------------------------------------------------------------------
134 | str2richText(Font, Point, Voff, Color, Break, Str) ->
135 | valid_bool(Break),
136 | F = fontHandler(Font),
137 | Face = #face{font=F, pointSize=Point, vOffset=Voff,
138 | color=Color, breakable=Break},
139 | L1 = normalise_str(Str, []),
140 | L2 = lists:map(fun({wd1,S}) ->
141 | Width = width_of(F, Point, S),
142 | {word, Width, Face, S};
143 | (spaces) ->
144 | Width = width_of(F, Point, [$\s]),
145 | {space, Width, Face};
146 | (lineFeed) ->
147 | {nl, Face}
148 | end, L1),
149 | {richText, L2}.
150 |
151 | valid_bool(true) -> true;
152 | valid_bool(false) -> true;
153 | valid_bool(X) -> exit({badarg, str2richText, breakNotBool, was, X}).
154 |
155 | %% ----------------------------------------------------------------------------
156 | %% @spec normalise_str(Str, Acc) -> [spaces | lineFeed | {wd1, Word::string()}]
157 | %% @doc split Str into word and space segments, single and duplicate
158 | %% whitespace chars get replaced by a single 'spaces', NL -> lineFeed
159 | %% @end------------------------------------------------------------------------
160 | normalise_str([], L) ->
161 | lists:reverse(L);
162 | normalise_str([$\n|T], L) ->
163 | normalise_str(T, [lineFeed|L]);
164 | normalise_str([H|T], L) ->
165 | case is_white(H) of
166 | true ->
167 | T1 = skip_white(T),
168 | normalise_str(T1, [spaces|L]);
169 | false ->
170 | {Word, T1} = collect_word(T, [H]),
171 | normalise_str(T1, [{wd1,Word}|L])
172 | end.
173 |
174 | is_white($\s) -> true;
175 | is_white(160) -> true; %% non-break-space
176 | is_white($\t) -> true;
177 | is_white($\r) -> true;
178 | is_white(_) -> false.
179 |
180 | skip_white(X=[H|T]) ->
181 | case is_white(H) of
182 | true -> skip_white(T);
183 | false -> X
184 | end;
185 | skip_white([]) ->
186 | [].
187 |
188 | collect_word(X=[$\n|_T], L) ->
189 | {lists:reverse(L), X};
190 | collect_word(X=[H|T], L) ->
191 | case is_white(H) of
192 | true -> {lists:reverse(L), X};
193 | false -> collect_word(T, [H|L])
194 | end;
195 | collect_word([], L) ->
196 | {lists:reverse(L), []}.
197 |
198 | width_of(Font, PointSize, Str) ->
199 | PointSize * sizeof(Font, Str).
200 |
201 |
202 | %%----------------------------------------------------------------------
203 | %% sizeof(FontIndex, Str)
204 | %% Computes width of Str which is of type FontIndex
205 | %% Size is correctly adjusted for kerning information
206 |
207 | sizeof(Font, Str) ->
208 | Widths = lists:map(fun(I) -> char_width(Font, I) end, Str),
209 | %% dbg_io("Str=|~s| Widths=~p~nFont=~p~n",[Str, Widths, Font]),
210 | W1 = lists:sum(Widths),
211 | %% and add the correct kerning info
212 | kern_adj(Str, W1, Font).
213 |
214 | char_width(Font, I) ->
215 | case Font:width(I) of
216 | Width when is_integer(Width) ->
217 | Width;
218 | _ ->
219 | dbg_io("Character ~w in font ~p has no width~n", [I, Font]),
220 | Font:width($\s)
221 | end.
222 |
223 | kern_adj([H1,H2|T], W, Font) ->
224 | Extra = Font:kern(H1, H2),
225 | kern_adj([H2|T], W+Extra, Font);
226 | kern_adj(_, W, _) ->
227 | W.
228 |
229 | %%----------------------------------------------------------------------
230 | %% access funtions
231 |
232 | is_space(X) -> element(1,X) == space.
233 |
234 | is_word(X) -> element(1, X) == word.
235 |
236 | is_nl(X) -> element(1, X) == nl.
237 |
238 | is_breakable({word,_,Face,_Str}) -> Face#face.breakable;
239 | is_breakable(_) -> false.
240 |
241 | %% Make a new word based on the face of an old word
242 |
243 | cloan_word({word,_,Face,_}, Str) ->
244 | Font = Face#face.font,
245 | PointSize = Face#face.pointSize,
246 | W = width_of(Font, PointSize, Str),
247 | {word, W, Face, Str}.
248 |
249 | cloan_space({word,_,Face,_}) ->
250 | cloan_space_from_face(Face);
251 | cloan_space({nl, Face}) ->
252 | cloan_space_from_face(Face).
253 |
254 | cloan_space_from_face(Face) ->
255 | Font = Face#face.font,
256 | PointSize = Face#face.pointSize,
257 | W = width_of(Font, PointSize, [$\s]),
258 | {space, W, Face}.
259 |
260 | width({word,W,_,_}) -> W;
261 | width({opaque,W,_}) -> W;
262 | width({space,W,_}) -> W;
263 | width({nl,_}) -> 0;
264 | width({fixedStr,W,_,_}) -> W.
265 |
266 | font({word,_,F,_}) -> F#face.font;
267 | font({opaque,_,_F}) -> unknown;
268 | font({space,_,F}) -> F#face.font;
269 | font({nl,F}) -> F#face.font;
270 | font({fixedStr,_,F,_}) -> F#face.font.
271 |
272 | fontFromFace(F) -> F#face.font.
273 |
274 | color({word,_,F,_}) -> F#face.color;
275 | color({opaque,_,_F}) -> unknown;
276 | color({space,_,F}) -> F#face.color;
277 | color({nl,F}) -> F#face.color;
278 | color({fixedStr,_,F,_}) -> F#face.color.
279 |
280 | pointSize({word,_,F,_}) -> F#face.pointSize;
281 | pointSize({opaque,_,_F}) -> unknown;
282 | pointSize({space,_,F}) -> F#face.pointSize;
283 | pointSize({nl,F}) -> F#face.pointSize;
284 | pointSize({fixedStr,_,F,_}) -> F#face.pointSize.
285 |
286 | classify_inline({word,_W,_,_}) -> word;
287 | classify_inline({opaque,_W,_}) -> opaque;
288 | classify_inline({space,_W,_}) -> space;
289 | classify_inline({nl,_}) -> nl;
290 | classify_inline({fixedStr,_W,_,_}) -> fixedStr.
291 |
292 | string({word,_,_,S}) -> S;
293 | string({fixedStr,_,_,S}) -> S;
294 | string({space,_,_}) -> " ".
295 |
296 | %% +deftype FixedStr = {fixedStr, Width, Face, Str},
297 | %% +deftype Opaque = {opaque, Width, X}
298 | %% +deftype Space = {space, Width, Face}
299 | %% +deftype NL = {nl, Face}
300 | %% +deftype Face = {Font, PointSize, Voffset, Color, Breakable}
301 | %% +deftype Color = default | {R,G,B}
302 |
303 | mk_word(Face, Str) ->
304 | F = Face#face.font,
305 | P = Face#face.pointSize,
306 | Width = width_of(F, P, Str),
307 | {word, Width, Face, Str}.
308 |
309 | mk_fixedStr(Face, Str) ->
310 | F = Face#face.font,
311 | P = Face#face.pointSize,
312 | Width = width_of(F, P, Str),
313 | {fixedStr, Width, Face, Str}.
314 |
315 | mk_nl(Face) ->
316 | {nl, Face}.
317 |
318 | mk_space(Face) ->
319 | F = Face#face.font,
320 | P = Face#face.pointSize,
321 | Width = P * char_width(F, 32),
322 | {space, Width, Face}.
323 |
324 | %% make a word that we can play with
325 |
326 | mk_test_word(Str) ->
327 | F = fontHandler("Times-Roman"),
328 | Face = #face{font=F, pointSize=16, vOffset=0,
329 | color=default, breakable=true},
330 | Width = width_of(F, 16, Str),
331 | {word, Width, Face, Str}.
332 |
333 | mk_face(Font, PointSize, Breakable, Color, VoffSet) ->
334 | F = fontHandler(Font),
335 | #face{font=F, pointSize=PointSize, vOffset=VoffSet,
336 | color=Color, breakable=Breakable}.
337 |
338 | fontHandler(Font) ->
339 | case eg_font_map:handler(Font) of
340 | undefined ->
341 | dbg_io("There is no font called:~s~n",[Font]),
342 | dbg_io("Using Times-Roman~n"),
343 | eg_font_map:handler("Times-Roman");
344 | Mod ->
345 | Mod
346 | end.
347 |
348 | lineWidth(Toks) ->
349 | lists:foldl(fun(I, S) -> width(I) + S end, 0, Toks).
350 |
351 | numberOfSpaces(Toks) ->
352 | Toks1 = lists:filter(fun(I) -> is_space(I) end, Toks),
353 | length(Toks1).
354 |
355 | widthExcludingSpaces(Toks) ->
356 | lists:foldl(fun(I, S) ->
357 | case is_space(I) of
358 | true -> S;
359 | false -> S + width(I)
360 | end
361 | end, 0, Toks).
362 |
363 | is_face_breakable(F) ->
364 | F#face.breakable.
365 |
366 |
--------------------------------------------------------------------------------
/src/eg_richText2pdf.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Joe Armstrong
24 | %% Purpose: Convert internal form of line to PDF
25 | %%==========================================================================
26 |
27 | -module(eg_richText2pdf).
28 |
29 | %% There is a bug in this code: Blanks *inside*
30 | %% strings are subject to expansion caused by the Tw operator
31 |
32 | -export([richText2pdf/8]).
33 |
34 |
35 | -record(pdf, {color = default,
36 | xy = {-1,-1},
37 | face = {none,none},
38 | tw = -1,
39 | inTJ = false,
40 | code = []}).
41 |
42 | %% -define(DEBUG, true).
43 |
44 | -ifdef(DEBUG).
45 | dbg_io(Str) -> dbg_io(Str,[]).
46 | dbg_io(Str,Args) ->
47 | io:format("eg_richText2pdf: ~p " ++ Str, [self()] ++ Args),
48 | ok.
49 | -else.
50 | %dbg_io(_) -> ok.
51 | dbg_io(_,_) -> ok.
52 | -endif.
53 |
54 | %% ============================================================================
55 |
56 | %% returns: Code
57 | %% usage : * add pdf content to PDF using eg_pdf:append_stream(PDF, Code)
58 | %% * note that this must be wrapped in eg_pdf:begin_text(PDF) and
59 | %% eg_pdf:end_text(PDF) to create a 'text object' this is required
60 | %% as the usage of Rot adds a 'Tm' (transformation matrix) in the pdf
61 | %% source, which may only be used inside a 'text object' (chp 5.3
62 | %% in pdf reference manual 1.4 and 1.7)
63 | richText2pdf(X, Y0, Type, Rot, Lines, Leading, Widths, Offsets) ->
64 | Y = Y0 - Leading,
65 | P = start(),
66 | P2 = case Type of
67 | justified ->
68 | {_Cos, _Sin, P1} = init_rotation_matrix(X, Y0, Rot, P),
69 | make_justified(X,Y,Leading,Lines,Offsets,Widths,P1);
70 | Style when Style == left_justified;
71 | Style == right_justified;
72 | Style == centered ->
73 | {_Cos, _Sin, P1} = init_rotation_matrix(X, Y0, Rot, P),
74 | make_para(X, Y, Leading, Lines,Offsets,Widths,Style,P1)
75 | end,
76 | finalise(P2).
77 |
78 | make_justified(_X, _Y, _Leading, [], _, _, P) -> P;
79 | make_justified(X, Y, _Leading, [H], [O|_], [W|_], P) ->
80 | line2pdf(X+O,Y,H,W,last_line_justified, P);
81 | make_justified(X, Y, Leading, [H|T], [O|_O1] = O0, [W|_W1] = W0, P) ->
82 | {O2, W2} = last_offset_width(O0, W0),
83 | P1 = line2pdf(X+O,Y,H,W,justified,P),
84 | make_justified(X, Y-Leading, Leading, T, O2, W2, P1).
85 |
86 | make_para(_X, _Y, _Leading, [], _, _, _, P) -> P;
87 | make_para(X, Y, _Leading, [H], [O|_], [W|_], Style, P) ->
88 | line2pdf(X+O,Y,H,W,Style, P);
89 | make_para(X, Y, Leading, [H|T], [O|_O1] = O0, [W|_W1] = W0, Style, P) ->
90 | {O2, W2} = last_offset_width(O0, W0),
91 | P1 = line2pdf(X+O,Y,H,W,Style,P),
92 | make_para(X, Y-Leading, Leading, T, O2, W2, Style, P1).
93 |
94 | last_offset_width([O|O1],[W|W1]) ->
95 | O2 = if O1 == [] -> [O];
96 | true -> O1
97 | end,
98 | W2 = if W1 == [] -> [W];
99 | true -> W1
100 | end,
101 | {O2, W2}.
102 |
103 | line2pdf(X, Y, {richText, Line}, Len, Style, P) ->
104 | TotWidth = eg_richText:lineWidth(Line)/1000,
105 | NS = eg_richText:numberOfSpaces(Line),
106 | case Style of
107 | justified ->
108 | Tw = if
109 | NS > 0 ->
110 | Width = (Len - TotWidth)/NS,
111 | Width;
112 | NS == 0 ->
113 | 0
114 | end,
115 | %% dbg_io("Line=~p~n",[Line]),
116 | %% dbg_io("NS=~p Tw=~p Len=~p TotWidth=~p~n",
117 | %% [NS,Tw,Len,TotWidth]),
118 | make_line(X, Y, Line, Tw, P);
119 | last_line_justified ->
120 | %% The last line of a justfied para has to be handled with care
121 | %% It might happen that the line needs to be squashed ...
122 | if
123 | TotWidth > Len ->
124 | line2pdf(X, Y, {richText, Line}, Len, justified, P);
125 | true ->
126 | line2pdf(X, Y, {richText, Line}, Len, left_justified, P)
127 | end;
128 | left_justified ->
129 | make_line(X, Y, Line, 0, P);
130 | right_justified ->
131 | Excess = Len - TotWidth,
132 | make_line(X+Excess, Y, Line, 0, P);
133 | centered ->
134 | %% dbg_io("Len = ~p~n",[Len]),
135 | %% dbg_io("TotWidth = ~p~n",[TotWidth]),
136 | Offset = round(Len - TotWidth) div 2,
137 |
138 | %% dbg_io("Offset = ~p~n",[Offset]),
139 | make_line(X+Offset, Y, Line, 0, P)
140 | end.
141 |
142 | make_line(X, Y, Line, Tw, P) ->
143 | %% dbg_io("make line~p at pos=~p ~p~n",[Line,X,Y]),
144 | P1 = add_move(X, Y, P),
145 | make_line(Line, Tw, P1).
146 |
147 | make_line([H|T], Tw, P) ->
148 | case eg_richText:classify_inline(H) of
149 | space ->
150 | {Font,Size} = get_font_info(H),
151 | P1 = ensure_face(Font, Size, P),
152 | P2 = ensure_tw(Tw, P1),
153 | make_line(T, Tw, add_space(Font, P2));
154 | word ->
155 | {Font,Size} = get_font_info(H),
156 | Str = eg_richText:string(H),
157 | %% dbg_io("Outputting Word=~p Font=~p oldFont=~p~n",
158 | %% [H,Font,P#pdf.face]),
159 | P1 = ensure_face(Font, Size, P),
160 | P2 = ensure_tw(Tw, P1),
161 | Color = eg_richText:color(H),
162 | P3 = ensure_color(Color, P2),
163 | make_line(T, Tw, add_string(Font, Str, P3));
164 | fixedStr ->
165 | {Font,Size} = get_font_info(H),
166 | Str = eg_richText:string(H),
167 | P1 = ensure_face(Font, Size, P),
168 | P2 = ensure_tw(0, P1),
169 | make_line(T, Tw, add_string(Font, Str, P2));
170 | _ ->
171 | dbg_io("Don't know how to make a line with a: ~p~n",[H]),
172 | make_line(T, Tw, P)
173 | end;
174 | make_line([], _, P) ->
175 | P.
176 |
177 | get_font_info(X) ->
178 | {eg_richText:font(X), eg_richText:pointSize(X)}.
179 |
180 | finalise(P) ->
181 | P1 = close_tj(P),
182 | lists:reverse(P1#pdf.code).
183 |
184 | start() -> #pdf{}.
185 |
186 | init_rotation_matrix(X, Y, 0, P) ->
187 | %% dbg_io("here=~p~n",[{X,Y,0,P}]),
188 | C = "1 0 0 1 " ++ eg_pdf_op:n2s(X) ++ " " ++ eg_pdf_op:n2s(Y) ++ " Tm ",
189 | P1 = add_code(C, P#pdf{xy={X,Y}}),
190 | {1,0,P1};
191 | init_rotation_matrix(X, Y, Rot, P) ->
192 | Rads = 3.14159*Rot/180,
193 | Cos = math:cos(Rads),
194 | Sin = math:sin(Rads),
195 | C = eg_pdf_op:n2s(Cos) ++ " " ++ eg_pdf_op:n2s(Sin) ++ " " ++
196 | eg_pdf_op:n2s(-Sin) ++ " " ++ eg_pdf_op:n2s(Cos) ++ " " ++
197 | eg_pdf_op:n2s(X) ++ " " ++ eg_pdf_op:n2s(Y) ++ " Tm ",
198 | P1 = add_code(C, P#pdf{xy={X,Y}}),
199 | {Cos, Sin, P1}.
200 |
201 | add_move(X, Y, P) ->
202 | P1 = close_tj(P),
203 | case P1#pdf.xy of
204 | {-1, -1} ->
205 | %% dbg_io("Here aaa*********~n"),
206 | C = "1 0 0 1 " ++ eg_pdf_op:n2s(X) ++ " " ++
207 | eg_pdf_op:n2s(Y) ++ " Tm ",
208 | add_code(C, P1#pdf{xy={X,Y}});
209 | {X, Y} ->
210 | add_code("0 0 TD ", P1);
211 | {OldX, OldY} ->
212 | Dx = X - OldX,
213 | Dy = Y - OldY,
214 | C = eg_pdf_op:n2s(Dx) ++ " " ++ eg_pdf_op:n2s(Dy) ++ " TD ",
215 | add_code(C, P1#pdf{xy={X,Y}})
216 | end.
217 |
218 | ensure_face(Font, Pts, P) ->
219 | case P#pdf.face of
220 | {Font, Pts} ->
221 | P;
222 | {_, _} ->
223 | P1 = close_tj(P),
224 | P2 = P1#pdf{face={Font,Pts}},
225 | Index = Font:index(),
226 | add_code("/F" ++ eg_pdf_op:i2s(Index) ++ " " ++
227 | eg_pdf_op:i2s(Pts) ++ " Tf ", P2)
228 | end.
229 |
230 | ensure_color(Color, P) ->
231 | case P#pdf.color of
232 | Color ->
233 | P;
234 | _ ->
235 | P1 = close_tj(P),
236 | P2 = P1#pdf{color=Color},
237 | Code = set_color(Color),
238 | add_code(Code, P2)
239 | end.
240 |
241 |
242 | set_color(default) ->
243 | set_color({0,0,0});
244 | set_color({R,G,B}) ->
245 | eg_pdf_op:f2s(R) ++ " " ++ eg_pdf_op:f2s(G) ++" " ++
246 | eg_pdf_op:f2s(B) ++ " rg ".
247 |
248 | close_tj(P) ->
249 | case P#pdf.inTJ of
250 | true ->
251 | add_code("] TJ ", P#pdf{inTJ=false});
252 | false ->
253 | P
254 | end.
255 |
256 | open_tj(P) ->
257 | case P#pdf.inTJ of
258 | false ->
259 | add_code("[", P#pdf{inTJ=true});
260 | true ->
261 | P
262 | end.
263 |
264 | ensure_tw(N, P) ->
265 | case P#pdf.tw of
266 | N -> P;
267 | _ ->
268 | P1 = close_tj(P),
269 | add_code(eg_pdf_op:n2s(N) ++ " Tw ", P1#pdf{tw=N})
270 | end.
271 |
272 | add_string(Font, Str, P) ->
273 | %% font etc are set
274 | P1 = open_tj(P),
275 | Code = str2pdf(Font, Str),
276 | add_code(Code, P1).
277 |
278 | add_space(Font, P) ->
279 | add_string(Font, " ", P).
280 |
281 | add_code(Str, P) ->
282 | C1 = P#pdf.code,
283 | P#pdf{code=lists:reverse(Str, C1)}.
284 |
285 |
286 | str2pdf(_Font, "") -> "";
287 | str2pdf(Font, Str) ->
288 | K = str2TJ(Font, Str),
289 | K1 = lists:map(fun({Str1,Kern}) -> {quote_strings(Str1), Kern} end, K),
290 | Pdf1 = lists:map(fun({S,I}) -> ["(", S,")",eg_pdf_op:i2s(I)] end, K1),
291 | eg_pdf_op:flatten(Pdf1).
292 |
293 | quote_strings([$(|T]) -> [$\\,$(|quote_strings(T)];
294 | quote_strings([$)|T]) -> [$\\,$)|quote_strings(T)];
295 | quote_strings([$\\|T]) -> [$\\,$\\|quote_strings(T)];
296 | %%quote_strings([$"|T]) -> [$\\,$"|quote_strings(T)];
297 | quote_strings([H|T]) -> [H|quote_strings(T)];
298 | quote_strings([]) -> [].
299 |
300 | %% str2TJ(Font, Str) -> [{str(),int()}].
301 |
302 | str2TJ(Font, Str) ->
303 | str2TJ(Font, Str, [], []).
304 |
305 | str2TJ(Font, [32,H|T], Tmp, L) ->
306 | str2TJ(Font, [H|T], [32|Tmp], L);
307 | str2TJ(Font, [H,32|T], Tmp, L) ->
308 | str2TJ(Font, T, [32,H|Tmp], L);
309 | str2TJ(Font, [H1,H2|T], Tmp, L) ->
310 | case Font:kern(H1, H2) of
311 | 0 ->
312 | str2TJ(Font, [H2|T], [H1|Tmp], L);
313 | N ->
314 | Str = lists:reverse([H1|Tmp]),
315 | str2TJ(Font, [H2|T], [], [{Str,-N}|L])
316 | end;
317 | str2TJ(Font, [H|T], Tmp, L) ->
318 | str2TJ(Font, T, [H|Tmp], L);
319 | str2TJ(_Font, [], [], L) ->
320 | lists:reverse(L);
321 | str2TJ(_Font, [], Tmp, L) ->
322 | lists:reverse([{lists:reverse(Tmp), 0}|L]).
323 |
324 | %% To set the font use /Fn Pt Tf
325 | %% [(A) 90 (W) 120 (A) 105 (Y again - correctly kerned) ] TJ
326 |
--------------------------------------------------------------------------------
/src/eg_xml2richText.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Joe Armstrong
24 | %%==========================================================================
25 |
26 | -module(eg_xml2richText).
27 |
28 | -export([normalise_xml/2,
29 | normalise_xml/3,
30 | default_tagMap/1]).
31 |
32 | -include("eg.hrl").
33 |
34 | %% -define(DEBUG, true).
35 |
36 | -ifdef(DEBUG).
37 | dbg_io(Str) -> dbg_io(Str,[]).
38 | dbg_io(Str,Args) ->
39 | io:format("eg_xml2richText: ~p " ++ Str, [self()] ++ Args),
40 | ok.
41 | -else.
42 | %dbg_io(_) -> ok.
43 | dbg_io(_,_) -> ok.
44 | -endif.
45 |
46 | %%----------------------------------------------------------------------
47 | %% normalise_xml(XML, RichTextTags, FontMap) ->
48 | %% XML = XML parse tree
49 | %% The tree is walked - if any Tag is in RichTextTags
50 | %% Then the subtree of this tag is assumend to be rich text
51 | %% RichTextTags = [Tag]
52 | %% FontMap = [#face{}]
53 |
54 | %% Invarients no consequative spaces
55 | %% or spaces next to NLs
56 |
57 | default_tagMap(Pts) ->
58 | {[p],
59 | [{default,eg_richText:mk_face("Times-Roman", Pts, true, default, 0)},
60 | {em, eg_richText:mk_face("Times-Italic", Pts, true, default, 0)},
61 |
62 | %% XXX !!! the font ZapfChancery-MediumItalic is not availible
63 | {red, eg_richText:mk_face("ZapfChancery-MediumItalic", Pts, true,
64 | {1,0,0},0)},
65 | {blue, eg_richText:mk_face("ZapfChancery-MediumItalic", Pts, true,
66 | {0,0,1},0)},
67 |
68 | {code, eg_richText:mk_face("Courier", Pts, false, default, 0)},
69 | {b, eg_richText:mk_face("Times-Bold", Pts, true, default, 0)}
70 | ]}.
71 |
72 | normalise_xml(XML, {StandardTags, TagMap}) ->
73 | normalise_xml(XML, StandardTags, TagMap).
74 |
75 | normalise_xml({Tag, Args, L}, RichTextTags, TagMap) ->
76 | case lists:member(Tag, RichTextTags) of
77 | true ->
78 | L1 = normalise_richText(L, TagMap),
79 | {Tag, Args, L1};
80 | false ->
81 | L1 = lists:map(fun(I) ->
82 | normalise_xml(I, RichTextTags, TagMap)
83 | end, L),
84 | {Tag, Args, L1}
85 | end;
86 | normalise_xml(Z, _, _) ->
87 | dbg_io("I cannot normalise:~p~n",[Z]).
88 |
89 | normalise_richText(Items, FontMap) ->
90 | L0 = lists:foldl(fun(I, L0) -> normalise_inline(I, FontMap, L0) end,
91 | [], Items),
92 | L1 = lists:reverse(L0),
93 | test_inline_invarient(L1),
94 | {richText, L1}.
95 |
96 | test_inline_invarient([H1,H2|T]) ->
97 | case {eg_richText:classify_inline(H1), eg_richText:classify_inline(H2)} of
98 | {space, space} ->
99 | dbg_io("Warning spaces:~p ~p~n",[H1,H2]),
100 | test_inline_invarient([H2|T]);
101 | {nl, space} ->
102 | dbg_io("Warning NL + NL:~p ~p~n",[H1,H2]),
103 | test_inline_invarient([H1|T]);
104 | {space,nl} ->
105 | dbg_io("Warning spaces + NL:~p ~p~n",[H1,H2]),
106 | test_inline_invarient([H2|T]);
107 | _ ->
108 | test_inline_invarient([H2|T])
109 | end;
110 | test_inline_invarient(_) ->
111 | true.
112 |
113 | normalise_inline({raw,Str}, FontMap, L) ->
114 | normalise_tag(default, Str, FontMap, L);
115 | normalise_inline({Tag, _, [{raw,Str}]}, FontMap, L) ->
116 | normalise_tag(Tag, Str, FontMap, L);
117 | normalise_inline({_Tag, _, []}, _FontMap, L) ->
118 | L.
119 |
120 | normalise_tag(Tag, Str, FontMap, L) ->
121 | Face = get_face(Tag, FontMap),
122 | case eg_richText:is_face_breakable(Face) of
123 | true ->
124 | normalise_str(Str, Face, L, skip_ws);
125 | false ->
126 | normalise_str(Str, Face, L, keep_ws)
127 | % Wd = eg_richText:mk_fixedStr(Face, Str),
128 | % [Wd|L]
129 | end.
130 |
131 | get_face(Tag, [{Tag,Face}|_]) -> Face;
132 | get_face(Tag, [_|T]) -> get_face(Tag, T);
133 | get_face(Tag, []) ->
134 | dbg_io("There is no face associated with Tag=~p~n",[Tag]),
135 | eg_pdf:default_face().
136 |
137 | %% Collect spaces nls etc.
138 | %% in a breakable face
139 | normalise_str([$\r,$\n|T], Face, L, WS) ->
140 | normalise_str(T, Face, [eg_richText:mk_nl(Face)|L], WS);
141 | normalise_str([$\n|T], Face, L, WS) ->
142 | normalise_str(T, Face, [eg_richText:mk_nl(Face)|L], WS);
143 | normalise_str([H|T], Face, L, WS) ->
144 | case {is_white(H), WS} of
145 | {true, skip_ws} ->
146 | %% Hop over the white space
147 | %% If we get to \n put in a NL otherwise
148 | %% put in a space
149 | T1 = skip_white(T),
150 | case T1 of
151 | [] ->
152 | Space = eg_richText:mk_space(Face),
153 | normalise_str(T1, Face, [Space|L], WS);
154 | [H2|_] ->
155 | case is_nl(H2) of
156 | true ->
157 | normalise_str(T1, Face, L, WS);
158 | false ->
159 | Space = eg_richText:mk_space(Face),
160 | normalise_str(T1, Face, [Space|L], WS)
161 | end
162 | end;
163 | {true, keep_ws} ->
164 | Space = eg_richText:mk_space(Face),
165 | normalise_str(T, Face, [Space|L], WS);
166 | {false, _} ->
167 | {Str, T1} = collect_word(T, [H]),
168 | Word = eg_richText:mk_word(Face, Str),
169 | normalise_str(T1, Face, [Word|L], WS)
170 | end;
171 | normalise_str([], _, L, _WS) ->
172 | L.
173 |
174 | %% End Normalise XML
175 | %%----------------------------------------------------------------------
176 |
177 | %%----------------------------------------------------------------------
178 | %% misc
179 |
180 | is_white($\s) -> true;
181 | is_white($\t) -> true;
182 | is_white(_) -> false.
183 |
184 | is_white_or_nl($\n) -> true;
185 | is_white_or_nl($\r) -> true;
186 | is_white_or_nl(X) -> is_white(X).
187 |
188 | is_nl($\n) -> true;
189 | is_nl($\r) -> true;
190 | is_nl(_) -> false.
191 |
192 | skip_white(X=[H|T]) ->
193 | case is_white(H) of
194 | true -> skip_white(T);
195 | false -> X
196 | end;
197 | skip_white([]) ->
198 | [].
199 |
200 | collect_word(X=[H|T], L) ->
201 | case is_white_or_nl(H) of
202 | true -> {lists:reverse(L), X};
203 | false -> collect_word(T, [H|L])
204 | end;
205 | collect_word([], L) ->
206 | {lists:reverse(L), []}.
207 |
208 |
--------------------------------------------------------------------------------
/src/eg_xml_lite.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Authors: Joe Armstrong
24 | %% Purpose: XML parser
25 | %%==========================================================================
26 |
27 | -module(eg_xml_lite).
28 |
29 | -export([parse_all_forms/1,
30 | parse_all_forms/2,
31 | parse_single_form/2,
32 | parse_file/1,
33 | continue/2,
34 | pp/1,
35 | xml2bin/2,
36 | bin2xml/2,
37 | test/1
38 | ]).
39 |
40 |
41 | %% ============================================================================
42 |
43 | %% Test cases
44 |
45 | test(1) ->
46 | parse_all_forms("aaaaa");
47 | test(2) ->
48 | {more, C} = parse_single_form("<", 0),
49 | continue(C, "abc>");
50 | test(3) ->
51 | reent_test("aaaaa"
52 | "gg aa");
53 | test(4) ->
54 | parse_all_forms("bc");
55 | test(5) ->
56 | parse_all_forms("
57 |
58 |
59 | ");
60 | test(6) ->
61 | parse_all_forms("aaa
aaa
");
62 | test(7) ->
63 | parse_all_forms("aaaa aa
");
65 | test(8) ->
66 | parse_all_forms("
67 |
68 |
69 | aaa
").
70 |
71 | %% This is a reentrant parser for XML streams
72 |
73 | %% +deftype parse_result() = {ok, xmlParseTree(), RestString : string()}
74 | %% | {more, cont()}
75 | %% | {error, parse_error()}
76 | %% +type start(Str) -> parse_result().
77 | %% +type more(Str, Cont) -> parse_result().
78 | %% +type format_error(parser_error()) -> string().
79 | %% +type start_cont() -> cont().
80 |
81 | %% parse_file(File) -> {error, What} | [Forms]
82 |
83 | parse_file(F) ->
84 | case file:read_file(F) of
85 | {ok, Bin} ->
86 | Result = parse_all_forms(binary_to_list(Bin), 1),
87 | %% case Result of
88 | %% {error, E} -> true;
89 | %% Tree -> pp(Tree)
90 | %% end,
91 | Result;
92 | Error ->
93 | Error
94 | end.
95 |
96 | xml2bin(In, Out) ->
97 | case file:read_file(In) of
98 | {ok, Bin} ->
99 | case parse_all_forms(binary_to_list(Bin), 0) of
100 | {ok, Tree, _} ->
101 | file:write_file(Out, term_to_binary(Tree));
102 | E = {error, _X} ->
103 | E;
104 | {more, _} ->
105 | {error, incomplete}
106 | end;
107 | Error ->
108 | Error
109 | end.
110 |
111 | bin2xml(In, Out) ->
112 | case file:read_file(In) of
113 | {ok, Bin} ->
114 | Tree = binary_to_term(Bin),
115 | file:write_file(Out, pp(Tree));
116 | Error ->
117 | Error
118 | end.
119 |
120 | atomize(A={Atom,_}) when is_atom(Atom) ->
121 | A;
122 | atomize({Str,Args,List}) ->
123 | {list_to_atom(Str), Args, lists:map(fun atomize/1, List)}.
124 |
125 | %%----------------------------------------------------------------------
126 |
127 | %% Top level ...
128 |
129 | parse_all_forms(Str) -> parse_all_forms(Str, 0).
130 |
131 | parse_all_forms(Str, Line) -> top_parse_loop(Str, Line, []).
132 |
133 | top_parse_loop(Str, Line, L) ->
134 | case parse_single_form(Str, Line) of
135 | {ok, Form, Str1, Line1} ->
136 | case all_blanks(Str1) of
137 | true ->
138 | lists:reverse([Form|L]);
139 | false ->
140 | top_parse_loop(Str1, Line1, [Form|L])
141 | end;
142 | E={error, _Why} ->
143 | E;
144 | {more, _Cont} ->
145 | {error, more_data_expected}
146 | end.
147 |
148 | parse_single_form(Str, Line) ->
149 | parse([], Str, Line).
150 |
151 | continue(Cont, Str) ->
152 | Cont(Str).
153 |
154 | parse(State, Str, Line) ->
155 | tokenise_result(eg_xml_tokenise:get_next_token(Str, Line), State).
156 |
157 | parse_cont(State, Cont, Str) ->
158 | tokenise_result(eg_xml_tokenise:continue(Cont, Str), State).
159 |
160 | tokenise_result({error, Line, What}, _State) ->
161 | {error,{errorInLine,Line,What}};
162 | tokenise_result({done, Token, Str1, Line1}, State) ->
163 | %% io:format("Token= ~p Str1=~p Line1=~p~n",[Token, Str1, Line1]),
164 | case step_parser(State, Token) of
165 | {more, State1} ->
166 | parse(State1, Str1, Line1);
167 | {done, Parse} ->
168 | {ok, Parse, Str1, Line1};
169 | {error, What} ->
170 | {error, {errorInLine, Line1,What}}
171 | end;
172 | tokenise_result({more, Cont}, State) ->
173 | {more, fun(Str) -> parse_cont(State, Cont, Str) end}.
174 |
175 | %% The Stack is just [{STag,Args,Collected}]
176 | %% pcdata and completed frames are just pushed onto the stack
177 | %% When an end tag is found it is compared with the start tag
178 | %% if it matches the stack frame is popped and it is
179 | %% merged into the previous stack frame
180 |
181 | %% step_parser(State, Event) -> {more, State1} | {done, Parse} | {error, What}
182 |
183 | step_parser(Stack, {sTag, _, Tag, Args}) ->
184 | %% Push new frame onto the stack
185 | {more, [{Tag, lists:sort(Args), []}|Stack]};
186 | step_parser([{Tag,Args,C}|L], _P={Flat, _, D}) when Flat == pi;
187 | Flat == raw;
188 | Flat == cdata;
189 | Flat == comment;
190 | Flat == doctype ->
191 | {more, [{Tag,lists:sort(Args),[{Flat,D}|C]}|L]};
192 | step_parser([{Tag,Args,C}|L], {empty, _, TagE, ArgsE}) ->
193 | {more, [{Tag,Args,[{TagE,lists:sort(ArgsE),[]}|C]}|L]};
194 | step_parser([{Tag, Args, C}|L], {eTag, _, Tag}) ->
195 | %% This is a matching endtag
196 | %% Now we normalise the arguments that were found
197 | C1 = deblank(lists:reverse(C)),
198 | pfinish([{Tag,Args,C1}|L]);
199 | step_parser([{STag, _Args, _C}|_L], {eTag, _, Tag}) ->
200 | {error,{badendtagfound,Tag,starttagis,STag}};
201 | step_parser([], {raw, _, S}) ->
202 | case all_blanks(S) of
203 | true ->
204 | {more, []};
205 | false ->
206 | {error, {nonblank_data_found_before_first_tag, S}}
207 | end;
208 | step_parser([], {Tag,_,D}) when Tag==comment; Tag==doctype; Tag==pi ->
209 | {done, {Tag, D}};
210 | step_parser(S, I) ->
211 | io:format("UUgh:Stack=~p Item=~p~n",[S, I]).
212 |
213 |
214 | pfinish([X]) -> {done, {xml, atomize(X)}};
215 | pfinish([H1,{Tag,Args,L}|T]) -> {more, [{Tag,Args,[H1|L]}|T]}.
216 |
217 | deblank(S=[{raw, _C}]) -> S;
218 | deblank(X) -> deblank1(X).
219 |
220 | deblank1([H={raw,X}|T]) ->
221 | case all_blanks(X) of
222 | true -> deblank1(T);
223 | false -> [H|deblank1(T)]
224 | end;
225 | deblank1([H|T]) ->
226 | [H|deblank1(T)];
227 | deblank1([]) ->
228 | [].
229 |
230 | all_blanks(L) -> lists:all(fun is_Blank/1, L).
231 |
232 | is_Blank($ ) -> true;
233 | is_Blank($\n) -> true;
234 | is_Blank($\t) -> true;
235 | is_Blank($\r) -> true;
236 | is_Blank(_) -> false.
237 |
238 |
239 | %% Pretty printer
240 |
241 | pp(Tree) ->
242 | pp(Tree, 0).
243 |
244 | pp({Node,Args,[{raw,Str}]}, Level) ->
245 | S = name(Node),
246 | [indent(Level),"<",S,pp_args(Args),">",Str,"",S,">\n"];
247 | pp({Node,Args,[]}, Level) ->
248 | S = name(Node),
249 | [indent(Level),"<",S,pp_args(Args),">",S,">\n"];
250 | pp({Node,Args,L}, Level) ->
251 | S = name(Node),
252 | [indent(Level),"<",S,pp_args(Args),">\n",
253 | lists:map(fun(I) -> pp(I, Level+2) end, L),
254 | indent(Level),"",S,">\n"];
255 | pp({raw,Str}, Level) ->
256 | [indent(Level),Str,"/n"];
257 | pp(X, _Level) ->
258 | io:format("How do I pp:~p~n",[X]),
259 | ["oops"].
260 |
261 | pp_args([]) -> [];
262 | pp_args([{Key,Val}|T]) ->
263 | Q=quote(Val),
264 | [" ",name(Key),"=",Q,Val,Q|pp_args(T)].
265 |
266 | quote(Str) ->
267 | case lists:member($", Str) of
268 | true -> $';
269 | false -> $"
270 | end.
271 |
272 | name(X) ->
273 | atom_to_list(X).
274 |
275 | indent(0) -> [];
276 | indent(N) -> [$ |indent(N-1)].
277 |
278 | reent_test(_O)->a.
279 |
280 |
--------------------------------------------------------------------------------
/src/erlguten.app.src:
--------------------------------------------------------------------------------
1 | %% -*- mode: Erlang; fill-column: 75; comment-column: 50; -*-
2 |
3 | {application, erlguten,
4 | [{description, "System for high-quality typesetting"},
5 | {vsn, "%VSN%"},
6 | {modules, ["%MODULES%"]},
7 | {registered, []},
8 | {applications, [kernel, stdlib]}]}.
9 |
--------------------------------------------------------------------------------
/src/erlguten.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Authors: Joe Armstrong
24 | %% Purpose: Main program
25 | %%==========================================================================
26 |
27 | -module(erlguten).
28 |
29 | -export([batch/1, get_tag_schema/2, parse_flow/1]).
30 |
31 | -export([test/0,bug/0]).
32 |
33 | -import(lists, [map/2]).
34 |
35 | -include("eg.hrl").
36 |
37 | test() -> format("test1.map").
38 |
39 | bug() -> format("test2.map").
40 |
41 |
42 | batch([X]) ->
43 | format(atom_to_list(X)).
44 |
45 | %% A map file has the following structure
46 | %%
47 | %%
48 | %%
49 | %% ...
50 | %% ...
51 | %%
52 | %%
53 | %% ...
54 | %%
55 | %%
56 | %%
57 | %% Logic:
58 | %% in Env
59 | %% set template=template1
60 | %% set current page=1
61 | %% enter intro
62 | %% set currentBox = intro
63 | %% set dict entry {initialised, Page, one}
64 | %% set dict entry {free, Page, intro} = 1
65 | %% set tagMap for template1:tagMap(one, intro)
66 | %% call template1:handler(p, Args, Data, Env) -> Env1
67 | %% call template2:handler(q, Args, Data, Env1) -> Env2
68 | %% etc.
69 |
70 | format(File) ->
71 | V = eg_xml_lite:parse_file(File),
72 | io:format("read:~p~n",[V]),
73 | Out = filename:rootname(File) ++ ".pdf",
74 | case V of
75 | {error, _W} ->
76 | io:format("Error in source(~s):~p~n",[File, V]),
77 | exit(1);
78 | [{pi,_},{xml,{data, [{"page", N}], Templates}}] ->
79 | Page = list_to_integer(N),
80 | io:format("Data starts on page:~p~n",[Page]),
81 | PDF = eg_pdf:new(),
82 | Env = #env{page=Page, pdf=PDF, dict=dict:new()},
83 | loop(Templates, Env),
84 | {Serialised, _PageNo} = eg_pdf:export(PDF),
85 | file:write_file(Out,[Serialised]),
86 | io:format("Created a file called:~p~n",[Out]),
87 | eg_pdf:delete(PDF);
88 | _ ->
89 | io:format("bad XML - must begin \"
94 | io:format("tempate Args=~p~n",[Args]),
95 | Template= get_template_name(Args),
96 | io:format("Template:~p~n",[Template]),
97 | Env1 = Env#env{template=Template},
98 | io:format("tempate data=~p~n",[Data]),
99 | Env2 = instanciate_template(Template, Env1),
100 | Env3 = format_boxes(Data, Env2),
101 | loop(T, Env3);
102 | loop([], Env) ->
103 | Env.
104 |
105 | format_boxes([{Box,_Args,Data}|T], Env) ->
106 | Env1 = initialise_box(Box, Env),
107 | %% loop over the paragraphs in the Box
108 | Env2 = format_paragraphs(Data, Box, Env1),
109 | format_boxes(T, Env2);
110 | format_boxes([], E) ->
111 | E.
112 |
113 | initialise_box(Box, E) ->
114 | #env{dict=Dict, page=Page, pdf=PDF, template=Template}=E,
115 | Dict1 = dict:store({free,Page,Box}, 1, Dict),
116 | B = Template:box(Box),
117 | #box{x=XX,y=YY,leading=Lead, width=Width, lines=Lines} = B,
118 | eg_pdf_lib:draw_box(PDF, XX, YY,Width, Lead,Lines),
119 | Env1 = E#env{dict=Dict1, currentBox=Box},
120 | %% initialse the tagMap
121 | initialise_tagMap(Template, Box, Env1).
122 |
123 | format_paragraphs([{ParaTag,Args,Data}|T], Box, Env) ->
124 | Template = Env#env.template,
125 | case (catch Template:handler(Box, ParaTag, Args, Data, Env)) of
126 | {'EXIT', Why} ->
127 | io:format("oops ~w: ~w ~w Args=~p Data=~p~n",[Template,Box,
128 | ParaTag,
129 | Args,Data]),
130 | io:format("Why=~p~n",[Why]),
131 | exit(1);
132 | Env1 ->
133 | format_paragraphs(T, Box, Env1)
134 | end;
135 | format_paragraphs([], _Box, E) ->
136 | E.
137 |
138 | initialise_tagMap(Template, Box, E) ->
139 | Ts = case (catch Template:tagMap(Box)) of
140 | {'EXIT', _Why} ->
141 | io:format("error in tagmap for ~p:~p~n",
142 | [Template,Box]),
143 | io:format("using defualt~n"),
144 | default_tagmap();
145 | L -> L
146 | end,
147 | PDF = E#env.pdf,
148 | TagMap = map(fun(I) ->
149 | io:format("Tagmap entry=~p~n",[I]),
150 | eg_pdf:ensure_font_gets_loaded(PDF, I#tagMap.font),
151 | #tagMap{font=F, size=Psize, color=Color,
152 | voff=V, break=Break, name=N} = I,
153 | {N, eg_richText:mk_face(F, Psize, Break, Color, V)}
154 | end, Ts),
155 | E#env{tagMap=TagMap}.
156 |
157 |
158 | default_tagmap() ->
159 | [#tagMap{name=defult,font="Times-Roman",size=11},
160 | #tagMap{name=em,font="Times-Italic", size=11},
161 | #tagMap{name=code,font="Courier",size=11,break=false}].
162 |
163 | instanciate_template(Template, E) ->
164 | #env{dict=Dict,page=Page,pdf=PDF} = E,
165 | _E1 = case dict:find(Key={initialised, Page, Template}, Dict) of
166 | error ->
167 | io:format("calling first instanciation Page:~p "
168 | "Template: ~p ~n", [Page, Template]),
169 | Template:on_instanciation(Page, PDF),
170 | Dict1 = dict:store(Key, true, Dict),
171 | E#env{dict=Dict1};
172 | _ ->
173 | E
174 | end.
175 |
176 | get_tag_schema(Tag, [H|T]) ->
177 | case H of
178 | Tag -> H;
179 | _ -> get_tag_schema(Tag, T)
180 | end;
181 | get_tag_schema(Tag, []) ->
182 | exit({missing,tag,Tag}).
183 |
184 | parse_flow([{"galley",F},{"name",_Tag}]) ->
185 | case eg_xml_lite:parse_file(F) of
186 | {error, E} ->
187 | io:format("Error in galley(~p):~p~n",[F, E]),
188 | exit(1);
189 | _L ->
190 | %G = parse_galley(F, L),
191 | %get_box(Tag, G)
192 | true
193 | end.
194 |
195 | get_template_name([{"name", N}]) ->
196 | list_to_atom(N).
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
--------------------------------------------------------------------------------
/test/.gitignore:
--------------------------------------------------------------------------------
1 | *.beam
2 | eg_test*.pdf
3 | kd_test*.pdf
4 | tmo_doc.pdf
5 |
--------------------------------------------------------------------------------
/test/content1.con:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | ErlGuten. is a system for hiqh quality typesetting,
7 | ErlGuten is free software. ErlGuten aims to produce typographic
8 | quality PDF directly from XML or from a program.
9 |
10 | The aim of ErlGuten is to produce high quality PDF from a layout
11 | language or from a program. The ErlGuten distribution includes a
12 | programming API, so that Erlang programs can produce PDF - and a
13 | typesetting system for typesetting documents written in XML.
14 |
15 | The document that you are reading was authored in XML and typeset
16 | by ErlGuten. The name ErlGuten is chosen because the program is
17 | written in Erlang - the Guten part is a reference to
18 | Gutenberg the father of printing.
19 |
20 | ErlGuten is a system for high quality typesetting, so we take a
21 | great deal of care when formatting text, a large number of
22 | optimizations are performed which improve the quality of the printed
23 | text. Many of these optimizations are usually only found in expensive
24 | professional type-setting programs. We believe that WYSIWYG programs
25 | have destroyed the fine art of typesetting - ErlGuten is a modest
26 | attempt to improve the situation.
27 |
28 | We have chosen XML as the input language for it's wide appeal.
29 | XML provides only a thin abstraction layer over the typesetting system
30 | - so the adventurous can use the programming interface to ErlGuten -
31 | to directly produce typographic quality PDF in real-time. We expect
32 | this facility to be useful for the dynamic generation of documents
33 | from web-servers.
34 |
35 | In ErlGuten we take the view that the highest level of
36 | abstraction is the layout of a document - we are very
37 | concerned that the user can specify the exact position of
38 | text on the printed page. At the next level of abstraction we are
39 | concerned with the typefaces that are used to format different regions
40 | of the document.
41 |
42 | ErlGuten is designed for the production of large and complex
43 | documents with complex layout requirements, like newspapers
44 | or books. In ErlGuten layout, content, and document
45 | management are considered separate issues. Layout is template
46 | based - Content is assumed to be stored as a large number of
47 | documents in a file system or data base, document management is
48 | considered as a mapping operation which takes documents in the
49 | content data base and maps them onto templates to produce hight
50 | quality output.
51 |
52 | This is normal text, set 30 picas wide in 12/14 Times Roman.
53 | Many different typefaces can be used within a paragraph.
54 | Emphasized text is set in Times-Italic. Hyphenation uses the
55 | TeX hyphenation algorithm. Any of the 35 built-in PDF typefaces with
56 | the same point size can be mixed with a paragraph. The term
57 | {person,"Joe"}
is an Erlang term which has been typeset
58 | in 12 point courier. The paragraph justification algorithm
59 | does proper kerning so, for example, the word AWAY is
60 | correctly kerned! - line breaks within a paragraph are selected by a
61 | sophisticated global optimization technique.
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/test/ebutik.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/test/ebutik.jpg
--------------------------------------------------------------------------------
/test/eg_test1.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Mikael Karlsson
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Authors: Mikael Karlsson
24 | %% Purpose: Test PDF documents main api
25 | %%==========================================================================
26 |
27 | -module(eg_test1).
28 |
29 | -export([test/0]).
30 |
31 | test()->
32 | PDF = eg_pdf:new(),
33 | eg_pdf:set_pagesize(PDF,a4),
34 | eg_pdf:set_author(PDF,"Mikael Karlsson"),
35 | eg_pdf:set_title(PDF, "Test of PDF API"),
36 | eg_pdf:set_subject(PDF,"PDF is cool, but Erlang is cooler"),
37 | eg_pdf:set_keywords(PDF,"Erlang, PDF, Gutenberg"),
38 | %% eg_pdf:set_date(PDF,2003,3,31),
39 | draft(PDF),
40 | eg_pdf:new_page(PDF),
41 | draft(PDF),
42 |
43 | eg_pdf:set_page(PDF,1),
44 | eg_pdf:image(PDF,'joenew.jpg',{390,440},{height,140}),
45 | eg_pdf:image(PDF,'joenew.jpg',{390,200},{width,140}),
46 | eg_pdf:image(PDF,'joenew.jpg',{190,300},{140,140}),
47 | eg_pdf:begin_text(PDF),
48 | eg_pdf:set_font(PDF, "Times-Italic", 240),
49 | eg_pdf:set_text_pos(PDF, 60,600),
50 | eg_pdf:textbr(PDF, "Wow"),
51 | eg_pdf:set_font(PDF, "Times-Roman", 42),
52 | eg_pdf:set_text_pos(PDF, 60,-40),
53 | eg_pdf:set_text_leading(PDF,60),
54 | eg_pdf:text(PDF, "Welcome home "),
55 | eg_pdf:set_text_rise(PDF, 20),
56 | eg_pdf:textbr(PDF, "Joe, "),
57 | eg_pdf:set_text_rise(PDF, 0),
58 | eg_pdf:textbr(PDF, "hope you had a"),
59 | eg_pdf:textbr(PDF, "nice trip"),
60 | eg_pdf:end_text(PDF),
61 |
62 | eg_pdf:set_page(PDF,2),
63 |
64 | eg_pdf:begin_text(PDF),
65 | eg_pdf:set_font(PDF,"Times-Roman", 24),
66 | eg_pdf:set_text_pos(PDF,60,750),
67 | eg_pdf:set_text_leading(PDF,26),
68 | eg_pdf:textbr(PDF, "Times-Roman 24 pt"),
69 | eg_pdf:set_font(PDF, "Times-Italic", 16),
70 | eg_pdf:textbr(PDF,"Times-Italic 16 pt"),
71 | eg_pdf:set_font(PDF, "Courier", 6),
72 | eg_pdf:textbr(PDF, "Courier 6 pt"),
73 | eg_pdf:set_text_leading(PDF,14),
74 | eg_pdf:set_font(PDF,"Blahonga", 12),
75 | eg_pdf:textbr(PDF, "The blahonga font will fall back to Times-Roman"),
76 | eg_pdf:textbr(PDF, "This is a check of ( ) \\ escape chars"),
77 | eg_pdf:kernedtext(PDF,
78 | [ "This is a test of Kerning: A", 120, "W",
79 | 120, "A", 95, "Y again" ]),
80 | eg_pdf:break_text(PDF),
81 | eg_pdf:textbr(PDF, "This is a text without Kerning: AWAY again"),
82 | eg_pdf:break_text(PDF),
83 | eg_pdf:end_text(PDF),
84 |
85 | eg_pdf:new_page(PDF),
86 | eg_pdf:line(PDF,100,100,200,100),
87 | eg_pdf:bezier(PDF,100,100,100,200,200,200,200,100),
88 | eg_pdf:path(PDF,stroke),
89 | eg_pdf:set_fill_color_RGB(PDF,0.5,0.7,0.2),
90 | eg_pdf:bezier(PDF,300,100,300,200,500,200,500,100),
91 | eg_pdf:path(PDF,close_fill_stroke),
92 | eg_pdf:set_fill_color(PDF,purple),
93 | eg_pdf:bezier(PDF,{300,400},{300,450},{500,450},{500,400}),
94 | eg_pdf:bezier_c(PDF,{500,350},{400,350},{300,400}),
95 | eg_pdf:path(PDF,fill),
96 | eg_pdf:set_dash(PDF,dash),
97 | eg_pdf:set_fill_color(PDF,slateblue),
98 | eg_pdf:line(PDF,100,250,400,250),
99 | eg_pdf:poly(PDF,[{100,300},{150,350},{200,350},{250,300}]),
100 | eg_pdf:path(PDF,fill_stroke),
101 | eg_pdf:set_dash(PDF,solid),
102 | eg_pdf:set_stroke_color(PDF,khaki),
103 | eg_pdf:circle(PDF, {200,200}, 200),
104 | eg_pdf:path(PDF, stroke),
105 | eg_pdf:set_stroke_color(PDF, {16#00,16#FF,16#00}),
106 | eg_pdf:circle(PDF, {200,300}, 50),
107 | eg_pdf:path(PDF, stroke),
108 | eg_pdf:ellipse(PDF, {200,300}, {50,100}),
109 | eg_pdf:path(PDF, stroke),
110 | eg_pdf:ellipse(PDF, {200,300}, {100,50}),
111 | eg_pdf:path(PDF, stroke),
112 | eg_pdf:circle(PDF, {200,300}, 100),
113 | eg_pdf:path(PDF, stroke),
114 | eg_pdf:grid(PDF,[50,100,150],[600,700,800]),
115 | eg_pdf:round_rect(PDF,{300,600},{200,100},20),
116 | eg_pdf:path(PDF, stroke),
117 | eg_pdf:rectangle(PDF,{300,600},{200,100}, stroke),
118 | eg_pdf:new_page(PDF),
119 | colortest(PDF),
120 | {Serialised, _PageNo} = eg_pdf:export(PDF),
121 | file:write_file("eg_test1.pdf",[Serialised]),
122 | eg_pdf:delete(PDF).
123 |
124 | %% Write a DRAFT text rotated in the background
125 | draft(PDF)->
126 | eg_pdf:save_state(PDF),
127 | pageno(PDF),
128 | eg_pdf:set_fill_gray(PDF,0.75),
129 | eg_pdf:rectangle(PDF, 100,800,410,5, fill),
130 | eg_pdf:rectangle(PDF, 100,42,410,5,fill_then_stroke),
131 | eg_pdf:translate(PDF,150,650),
132 | eg_pdf:mirror_yaxis(PDF,300),
133 | eg_pdf:rotate(PDF,300),
134 | eg_pdf:begin_text(PDF),
135 | eg_pdf:set_font(PDF,"Helvetica-Bold", 160),
136 | eg_pdf:set_text_rendering(PDF, fill),
137 | eg_pdf:set_text_pos(PDF, 0,0),
138 | eg_pdf:textbr(PDF, "DRAFT"),
139 | eg_pdf:end_text(PDF),
140 | eg_pdf:restore_state(PDF).
141 |
142 | pageno(PDF)->
143 | eg_pdf:begin_text(PDF),
144 | eg_pdf:set_font(PDF,"Times-Roman", 11),
145 | A = eg_pdf:get_page_no(PDF),
146 | Str = "Page " ++ eg_pdf_op:n2s(A),
147 | Width = eg_pdf:get_string_width(PDF,"Times-Roman", 11, Str),
148 | case A rem 2 of
149 | 0 ->
150 | eg_pdf:set_text_pos(PDF, 100, 50);
151 | 1 ->
152 | eg_pdf:set_text_pos(PDF, 510 - Width, 50)
153 | end,
154 | eg_pdf:text(PDF, "Page " ++ eg_pdf_op:n2s(A)),
155 | eg_pdf:end_text(PDF).
156 |
157 |
158 | colortest(PDF)->
159 | D=50,S=750, M=60,
160 | eg_pdf:save_state(PDF),
161 | eg_pdf:translate(PDF, M, S),
162 | colortest1(PDF,0,[white,silver,gray,black,maroon,red,fuchsia,purple,lime,
163 | green,olive,yellow,navy,blue,teal,aqua]),
164 | eg_pdf:restore_state(PDF),
165 | eg_pdf:save_state(PDF),
166 | eg_pdf:translate(PDF, M, S-D),
167 | colortest1(PDF,0,[blue2,blue3,blue4,blueviolet,cornflowerblue,darkorchid,
168 | darkslateblue,dodgerblue,lightskyblue,mediumblue,
169 | mediumpurple, mediumslateblue,midnightblue,purpleblue,
170 | royalblue,skyblue2, slateblue]),
171 | eg_pdf:restore_state(PDF),
172 | eg_pdf:save_state(PDF),
173 | eg_pdf:translate(PDF, M, S-2*D),
174 | colortest1(PDF,0,[aquamarine4,cadetblue,darkturquoise,lightblue,
175 | lightseagreen,lightslategray,lightsteelblue,
176 | mediumturquoise,paleturquoise,powderblue,skyblue,
177 | steelblue,turquoise]),
178 | eg_pdf:restore_state(PDF),
179 | eg_pdf:save_state(PDF),
180 | eg_pdf:translate(PDF, M, S-3*D),
181 | colortest1(PDF,0,[antiquewhite3,antiquewhite4,azure3, beige,darkslategray,
182 | gainsboro,honeydew,slategray,thistle
183 | ]),
184 | eg_pdf:restore_state(PDF),
185 | eg_pdf:save_state(PDF),
186 | eg_pdf:translate(PDF, M, S-4*D),
187 | colortest1(PDF,0,[aquamarine,chartreuse,darkgreen,darkseagreen,forestgreen,
188 | green2,green3,green4,greenyellow,lawngreen,limegreen,
189 | mediumaquamarine,mediumseagreen,mediumspringgreen,
190 | olivedrab,palegreen]),
191 | eg_pdf:restore_state(PDF),
192 | eg_pdf:save_state(PDF),
193 | eg_pdf:translate(PDF, M, S-5*D),
194 | colortest1(PDF,0,[seagreen,springgreen,yellowgreen]),
195 | eg_pdf:restore_state(PDF),
196 | eg_pdf:save_state(PDF),
197 | eg_pdf:translate(PDF, M, S-6*D),
198 | colortest1(PDF,0,[magenta,magenta2,magenta3,magenta4,mediumorchid,orchid,
199 | plum,violet]),
200 | eg_pdf:restore_state(PDF),
201 | eg_pdf:save_state(PDF),
202 | eg_pdf:translate(PDF, M, S-7*D),
203 | colortest1(PDF,0,[brown,burlywood,chocolate,coral,darkgoldenrod,darkorange,
204 | darksalmon,deeppink,firebrick,gold,goldenrod,hotpink,
205 | indianred,lightcoral,lightpink,lightsalmon]),
206 | eg_pdf:restore_state(PDF),
207 | eg_pdf:save_state(PDF),
208 | eg_pdf:translate(PDF, M, S-8*D),
209 | colortest1(PDF,0,[maroon0,orange,orangered,palevioletred,peachpuff,peru,
210 | pink,red2,red3,red4,rosybrown,salmon,sandybrown,sienna,
211 | tomato,violetred]),
212 | eg_pdf:restore_state(PDF),
213 | eg_pdf:save_state(PDF),
214 | eg_pdf:translate(PDF, M, S-9*D),
215 | colortest1(PDF,0,[aliceblue,azure,floralwhite,ghostwhite,ivory,lavender,
216 | lavenderblush,lightcyan,lightyellow,linen,mintcream,
217 | mistyrose,oldlace,seashell,snow,whitesmoke]),
218 | eg_pdf:restore_state(PDF),
219 | eg_pdf:save_state(PDF),
220 | eg_pdf:translate(PDF, M, S-10*D),
221 | colortest1(PDF,0,[antiquewhite,bisque,blancedalmond,comsilk,darkkhaki,
222 | darkolivegreen,khaki,lemonchiffon,lightgoldenrod,
223 | lightgoldenrodyellow]),
224 | eg_pdf:restore_state(PDF),
225 | eg_pdf:save_state(PDF),
226 | eg_pdf:translate(PDF, M, S-11*D),
227 | colortest1(PDF,0,[moccasin,palegoldenrod,papayawhip,
228 | tan,wheat,yellow2,yellow3,yellow4]),
229 |
230 | eg_pdf:restore_state(PDF).
231 |
232 | colortest1(_PDF,_N,[])->
233 | [];
234 | colortest1(PDF,N,[H|T])->
235 | eg_pdf:set_fill_color(PDF,H),
236 | eg_pdf:rectangle(PDF,{0,20},{20,20}),
237 | eg_pdf:path(PDF,fill_stroke),
238 | eg_pdf:set_fill_color(PDF,black),
239 | eg_pdf:begin_text(PDF),
240 | eg_pdf:set_font(PDF,"Times-Roman", 8),
241 | eg_pdf:set_text_pos(PDF,0,(N rem 2)*10),
242 | eg_pdf:text(PDF,atom_to_list(H)),
243 | eg_pdf:end_text(PDF),
244 | eg_pdf:translate(PDF,30,0),
245 | colortest1(PDF,N+1,T).
246 |
--------------------------------------------------------------------------------
/test/eg_test2.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Joe Armstrong
24 | %% Last Edit: 2003-03-11
25 | %% Purpose: Test cases
26 | %%==========================================================================
27 |
28 |
29 | %% This is for the brave who want to try writing PDF by hand
30 | %% The ouput of this program is a total mess :-)
31 | %% To run this program evaluate
32 | %% eg_test2:test() - this makes a two page PDF document
33 | %% called default.pdf
34 |
35 |
36 | -module(eg_test2).
37 |
38 | -include("../src/eg.hrl").
39 |
40 | -export([test/0]).
41 |
42 |
43 | %% ============================================================================
44 |
45 | test() ->
46 | Info = #info{creator="Erlang",
47 | creationDate={{2003,2,15},{15,20,11}},
48 | producer="mkPdf",
49 | author="",
50 | title="",
51 | subject="",
52 | keywords="ErlangKeyword"},
53 | Fonts = ["Times-Roman", "Times-Italic", "Courier"],
54 | %% = FR FI FC
55 | Pages = [page(1),page(2),page(3)],
56 | Pages1 = zap(Pages),
57 | MediaBox={0,0,595,842},
58 | Fonts1 = lists:map(fun(I) -> eg_font_map:handler(I) end, Fonts),
59 | eg_pdf_assemble:make_pdf_file("eg_test2.pdf",
60 | Info, Fonts1, Pages1, MediaBox).
61 |
62 | zap(Pages) ->
63 | FR = cmd("Times-Roman"),
64 | FI = cmd("Times-Italic"),
65 | FC = cmd("Courier"),
66 | lists:map(fun({page,I}) -> {page, xform(I, FR, FI, FC)} end, Pages).
67 |
68 | cmd(F) ->
69 | M = eg_font_map:handler(F),
70 | "/F" ++ eg_pdf_op:i2s(M:index()) ++ " ".
71 |
72 | xform("/FR " ++ T, FR, FI, FC) -> FR ++ xform(T, FR, FI, FC);
73 | xform("/FI " ++ T, FR, FI, FC) -> FI ++ xform(T, FR, FI, FC);
74 | xform("/FC " ++ T, FR, FI, FC) -> FC ++ xform(T, FR, FI, FC);
75 | xform([H|T], FR, FI, FC) -> [H|xform(T, FR, FI, FC)];
76 | xform([], _, _, _) -> [].
77 |
78 | %% Two pages of PDF
79 | page(1) ->
80 | {page,
81 | "
82 | 0.6000 g 0.6000 G
83 | 20 750 m 100 750 l S
84 | BT
85 | /FI 240 Tf
86 | -1.0000 -0.0000 0.0000 -1.0000 600 600 Tm (Wow)Tj
87 |
88 | /FR 14 Tf
89 | 1 0 0 1 20 750 Tm
90 | 18 0 Td (Line 1 indent 36 point) Tj
91 | -18 -16 Td (line 2 indebt 0) Tj
92 | 0 -16 Td (line 3 indent 0) Tj
93 | 0 -16 Td (line 4 indent 0) Tj
94 | 12 -16 Td (line 5 indent 12 points) Tj
95 | -12 -16 Td (line 6 indent 0 ) Tj
96 |
97 | ET
98 | "
99 | };
100 | %% page 2 has a lot of junk so I can check my
101 | %% computation of units is correct
102 | page(2) ->
103 | {page,
104 | "
105 | BT
106 |
107 | %% width of a=444 b=500 space=250
108 | %% (aaa bbb) = 3*444+3*500+250 = 3082*16/1000 = 49.31 (50+49.31) = 99.31
109 |
110 | /FR 16 Tf 18 TL 1 0 0 1 50 450 Tm [(aaa bbb) 0 ] TJ
111 |
112 | ET
113 |
114 | 50 475 m
115 | 50 400 l
116 | 99.31 400 l
117 | 99.31 475 l S
118 |
119 | %% same as above (width = 3082-300) = 2782*16/1000 = 44.51 + 200 = 244.51
120 |
121 | BT
122 | /FR 16 Tf 18 TL 1 0 0 1 200 450 Tm [(aa)300(a) ( bbb) 0 ] TJ
123 | ET
124 |
125 | 200 475 m
126 | 200 400 l
127 | 244.51 400 l
128 | 244.51 475 l S
129 |
130 | %% normal width = 3082 (extra) =
131 | %% total = 3082 + 880 = 3962 => *16/1000 = 63.39 + 300 = 363.39
132 |
133 | BT
134 | /FR 16 Tf 18 TL 1 0 0 1 300 450 Tm 52 Tw [(aaa bbb) 0 ] TJ
135 | ET
136 |
137 | %% Calculate (aaa bbb) = 3*444+3*500+2*250
138 | %% = 3332 *16/1000 = 53.31 + 2*52 = 157.31
139 |
140 | 300 475 m
141 | 300 400 l
142 | 457.31 400 l
143 | 457.31 475 l S
144 |
145 | BT
146 |
147 | /FR 24 Tf 20 750 Td (Times-Roman 24 pt) Tj
148 | 26 TL T*
149 | /FI 16 Tf (Times-Italic 16)Tj
150 | T*
151 | /FC 6 Tf (Courier 6)Tj
152 | T*
153 | /FR 12 Tf (The tuple) Tj
154 | /FI 12 Tf ( person, ) Tj
155 | /FR 12 Tf (for example, is written,) Tj
156 | /FC 12 Tf ({person,\"joe\"}) Tj
157 | /FR 12 Tf ( and represents a person.) Tj
158 |
159 |
160 | /FR 16 Tf
161 | 18 TL
162 | 1 0 0 1 50 650 Tm
163 | (Hello) Tj
164 | T*
165 | (Joe) Tj
166 | 0.60000 g
167 | 0.60000 G
168 |
169 | 1 0 0 1 100 600 Tm
170 | (100 x 600 0.6 gray text) Tj
171 |
172 | 1 0 0 rg
173 | 1 0 0 RG
174 |
175 | 1 0 0 1 150 550 Tm
176 | (150 x 550 red text) Tj
177 |
178 | 0.9659 0.2588 -0.2588 0.9659 100 500 Tm
179 | (100x400 red text with 15 degree rotation) Tj
180 |
181 | -1 0 0 -1 200 500 Tm
182 | (Upside down text) Tj
183 |
184 | 0 0 1 rg
185 | 0 0 1 RG
186 | 0 1 -1 0 30 500 Tm
187 | (90 degree blue text) Tj
188 |
189 | 0 1 0 rg
190 | 0 1 0 RG
191 |
192 | 1 0 0 1 350 650 Tm
193 | (Testing Hello World - abcWAdef ) Tj
194 | T*
195 | [ (T) 70 (esting) (T) 300 (esting) -3000 (abcW) 120 (Adef.) ] TJ
196 | T*
197 | 1 Tr
198 | (PDF )Tj
199 | -5 Ts (is ) Tj
200 | -10 Ts (really ) Tj
201 | -15 Ts (fun ) Tj
202 | -20 Ts (stuff ) Tj
203 | ET
204 |
205 | 450 720 m
206 | 150 720 l
207 | S
208 |
209 | 1.0 0.0 0.0 RG
210 | 0 1 0 rg
211 |
212 | 500 700 50 75 re B
213 |
214 | "
215 | };
216 | page(3) ->
217 | {page,
218 | "
219 | % experiment with text rotation and special effects
220 | % NOTE xpdf does not display this correctly acrobat does :-)
221 | BT
222 |
223 | /FR 80 Tf
224 |
225 | % translate to 50 650
226 | 1 0 0 1 50 650 Tm (ABC)Tj
227 |
228 | /FC 60 Tf
229 | % translate 300 650 scale x by 0.2
230 | 1 0 0 1 20 800 Tm (courier unscaled) Tj
231 | 0.8 0 0 1 20 750 Tm (courier scaled)Tj
232 |
233 | /FR 80 Tf
234 |
235 | % 10 degree rotation cos(10) = 0.9848 sin(10)=0.1736
236 | % matric = cos sin -sin cos X Y
237 |
238 | 0.9848 0.1736 -0.1736 0.9848 50 550 Tm (ROT 10) Tj
239 |
240 | %% 10 degress skew
241 | %% tan(10) = 0.176327
242 | % matrix = 1 tan(A) tan(B) 1 0 0]
243 |
244 | 1 0.1763 0.1763 1 50 480 Tm (Skew 10) Tj
245 |
246 | -1 0 0 1 300 400 Tm (Mirror) Tj
247 |
248 | -1 0 0 1 300 320 Tm (rorriM) Tj
249 |
250 | 1 0 0 1 300 500 Tm 1 0 0 rg (Red) Tj 0 0 0 rg (Black) Tj
251 |
252 | ET
253 | "
254 | }.
255 |
256 |
257 |
258 |
259 |
260 |
261 |
--------------------------------------------------------------------------------
/test/eg_test3.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Author: Joe Armstrong
24 | %% Purpose: Test cases
25 | %%==========================================================================
26 |
27 | -module(eg_test3).
28 |
29 | -export([test/0, norm/0]).
30 |
31 | -include("../src/eg.hrl").
32 |
33 | %% ============================================================================
34 |
35 | box(PDF, Color, X, Y, W, H) ->
36 | eg_pdf:set_fill_color(PDF, Color),
37 | eg_pdf:rectangle(PDF,{X, Y},{W,H}),
38 | eg_pdf:path(PDF,fill),
39 | eg_pdf:set_fill_color(PDF,black).
40 |
41 |
42 | test() ->
43 | PDF = eg_pdf:new(),
44 | eg_pdf:set_pagesize(PDF,a4),
45 | eg_pdf:set_page(PDF,1),
46 | eg_pdf:show_grid(PDF, a4),
47 | box(PDF, moccasin, 50, 300, 225, 350),
48 | zap(PDF, gold, title, 20, 830, 66, 24, 24, 1),
49 | zap(PDF, simple, 60, 650, 35, 14, 16, 5),
50 | zap(PDF, simple, 60, 560, 30, 14, 16, 5),
51 | zap(PDF, whitesmoke, two, 300, 760, 44, 18,20, 3),
52 | zap(PDF, romanAndCourier1, 60, 360, 35, 14, 16, 7),
53 | zap(PDF, palegreen, complex, 400, 600, 26, 12, 14, 22),
54 | zap(PDF, 5, 60, 450, 35, 12, 14, 6),
55 | zap(PDF, azure, narrow, 280, 650, 16, 8,10, 38),
56 | %% eg_pdf:show_grid(PDF, a4),
57 | eg_pdf:image(PDF,'./joenew.jpg',{50, 650},{width,200}),
58 | {Serialised, _PageNo} = eg_pdf:export(PDF),
59 | file:write_file("eg_test3.pdf",[Serialised]),
60 | eg_pdf:delete(PDF).
61 |
62 | ensure_fonts_are_loaded(PDF, {_,TagMap}) ->
63 | lists:foreach(fun({_,Face}) ->
64 | FontHandler = eg_richText:fontFromFace(Face),
65 | Font = FontHandler:fontName(),
66 | eg_pdf:ensure_font_gets_loaded(PDF, Font)
67 | end, TagMap).
68 |
69 |
70 | zap(PDF, Color, Sample, X, Y, Measure, PtSize, Leading, NLines) ->
71 | Width = Measure*6 + 20,
72 | Ht = NLines * PtSize + 20,
73 | box(PDF, Color, X, Y-Ht+10, Width, Ht),
74 | zap(PDF, Sample, X+10, Y+10, Measure, PtSize, Leading, NLines).
75 |
76 | zap(PDF, Sample, X, Y, Measure, PtSize, Leading, NLines) ->
77 | %% Measure in picas
78 | Len = Measure*6,
79 | Xml = parse_xml_para_str(xml(Sample)),
80 | %% io:format("XML=~p~n",[Xml]),
81 | TagMap = eg_xml2richText:default_tagMap(PtSize),
82 | ensure_fonts_are_loaded(PDF, TagMap),
83 | Norm = eg_xml2richText:normalise_xml(Xml, TagMap),
84 | %% io:format("Norm=~p~n",[Norm]),
85 | {p, _, RichText} = Norm,
86 | Widths = [Len-20|lists:duplicate(NLines-1, Len)],
87 | Off = [20|lists:duplicate(NLines-1, 0)],
88 | case eg_line_break:break_richText(RichText, {justified, Widths}) of
89 | impossible ->
90 | io:format("Cannot break line are widths ok~n");
91 | {Lines,_,_} ->
92 | Code = eg_richText2pdf:richText2pdf(X, Y, justified, 0, Lines,
93 | Leading, Widths, Off),
94 | eg_pdf:begin_text(PDF),
95 | eg_pdf:append_stream(PDF, Code),
96 | eg_pdf:end_text(PDF)
97 | %% eg_pdf_lib:draw_box(PDF, X, Y, Len, Leading, NLines)
98 | end.
99 |
100 | parse_xml_para_str(Str) ->
101 | [{xml, XmlPara}] = eg_xml_lite:parse_all_forms(Str),
102 | XmlPara.
103 |
104 |
105 | %%----------------------------------------------------------------------
106 | %% test data sets
107 |
108 | %% Here are some widths
109 | %% Times Roman A = 722
110 | %% space = 250
111 | %% a = 444
112 | %% b = 500
113 | %% c = 444
114 | %% W = 944
115 |
116 | xml(1) ->
117 | "aaa aaa aaa aaa bbb ccc ddd eee aaa ddd ss aaa aaa aaa
118 | bbb bbb bbb bbb bbb bbb bbb ccc ddd
119 |
";
120 | xml(narrow) ->
121 | "This is a long narrow box set in Times-Roman. Times-Roman was
122 | designed for printing long and narrow newspaper columns. It actually looks
123 | pretty horrid if set in wide measures. This is set narrow and tight. The
124 | really catestrophic thing about Times-Roman is that is is probably the
125 | most commonly used typeface, despite the fact it in manifestly
126 | unsuitable for the purpose it is being used for. Using narrow columns
127 | you can cram in loads of virtually unreadable data - no body will thank
128 | you, apart from environmentalists, who, I suppose will be pleased at the
129 | number of trees which are being saved.
";
130 | xml(simple) ->
131 | "This is normal text, with no emphasised code,
132 | the next example will be more complicated. This example
133 | is just simple text. In the next example I will show some
134 | text with emphasis.
";
135 | xml(two) ->
136 | "This is normal text, with a small
137 | ammount of emphasised text.
138 | This example only has two typefaces.
";
139 | xml(romanAndCourier1) ->
140 | "This is normal text, with a small
141 | ammount of courier
text.
142 | This example only has two typefaces.
";
143 | xml(complex) ->
144 | "This is normal text, set 5 picas wide in 12/14 Times Roman.
145 | I even allow some emphasised term, set in Times-Italic. The TeX
146 | hyphenation algorithm is also implemented.
147 | I have also some cursive text and an example of
148 | an Erlang term. The term {person, \"Joe\"}
is an Erlang term.
149 | The variable X
, was immediately followed by
150 | a comma. The justification algorithm does proper kerning,
151 | which is more than Microsoft Word can do. AWAY again is
152 | correctly kerned! Erlang terms {like, this}
153 | are typeset in courier.
";
154 | xml(4) ->
155 | "This is Times Roman.
";
156 | xml(5) -> "is AWAY correctly kerned? Erlang terms
157 | {like, this}
are typeset in courier.
158 | The red terms are typeset in ZapfChancery-MediumItalic.
159 | Then I can set blue terms as well.
";
160 | xml(title) ->
161 | "This page tests justification routines
".
162 |
163 | norm() -> "(This is normal text, with some **emphasised code**, I have
164 | also some *cursive text* and an example of and Erlang term. The
165 | term <{person, \"Joe\"}> is an Erlang term. The variable , was
166 | immediately followed by a comma.)".
167 |
168 |
169 |
--------------------------------------------------------------------------------
/test/eg_test4.erl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/test/eg_test4.erl
--------------------------------------------------------------------------------
/test/eg_test5.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%==========================================================================
23 |
24 | -module(eg_test5).
25 |
26 | -export([test/0, test/1]).
27 |
28 |
29 | test() ->
30 | test(9).
31 |
32 | test(1) ->
33 | text(1,11);
34 | test(2) ->
35 | %% Noraml para test - fits exactly into three lines
36 | eg_line_break:break_richText(text(1,11), {justified, [190,190,190]});
37 | test(3) ->
38 | %% This has some splill
39 | eg_line_break:break_richText(text(1,11), {justified, [190,190]});
40 | test(4) ->
41 | eg_line_break:break_richText(text(1,11), {ragged, [190,190,190,190]});
42 | test(5) ->
43 | %% fits exactly
44 | eg_line_break:break_richText(text(1,11),
45 | {preformatted, [200,200,200,200,200,200,200]});
46 | test(6) ->
47 | %% Has some spill
48 | eg_line_break:break_richText(text(1,11), {preformatted, [200,200,200]});
49 | test(7) ->
50 | eg_line_break:break_richText(text(1,11),
51 | {centered, [210,210,210,210,210,210,210,210]});
52 | %% test the line breaker
53 | test(8) ->
54 | W1 = eg_richText:mk_test_word("Have"),
55 | W2 = eg_richText:mk_test_word("a"),
56 | W3 = eg_richText:mk_test_word("splended"),
57 | W4 = eg_richText:mk_test_word("opportunity"),
58 | eg_line_break:make_partitions([W1,W2,W3,W4], eg_hyphen_rules_en_GB);
59 | test(9) ->
60 | PDF = eg_pdf:new(),
61 | eg_pdf:set_pagesize(PDF,a4),
62 | eg_pdf:set_page(PDF,1),
63 | eg_pdf:begin_text(PDF),
64 | eg_pdf:set_font(PDF, "Times-Roman", 24),
65 | demo(PDF, 0, 350, 475, 12, 13, 0, 180),
66 | demo(PDF, 45, 325, 600, 11, 12, 0, 190),
67 | demo(PDF, 90, 250, 575, 11, 12, 0, 190),
68 | demo(PDF, 135, 150, 600, 10, 11, 0, 190),
69 | demo(PDF, 180, 300, 200, 14, 16, 0, 130),
70 | demo(PDF, 225, 150, 375, 11, 12, 0, 130),
71 | demo(PDF, 270, 125, 500, 9, 10, 0, 60),
72 | demo(PDF, 315, 375, 375, 12, 13, 10, 120),
73 | eg_pdf:end_text(PDF),
74 | eg_pdf:show_grid(PDF, a4),
75 | {Serialised, _PageNo} = eg_pdf:export(PDF),
76 | file:write_file("eg_test5.pdf",[Serialised]),
77 | eg_pdf:delete(PDF).
78 |
79 | demo(PDF, Rot, X, Y, PointSize, Leading, Offset, Width) ->
80 | Widths = [Width-Offset|lists:duplicate(30,Width)],
81 | Off = [Offset|lists:duplicate(30,0)],
82 | {Lines,_,_} = eg_line_break:break_richText(text(1,Rot,PointSize),
83 | {justified, Widths}),
84 | Code = eg_richText2pdf:richText2pdf(X, Y, justified, Rot, Lines,
85 | Leading, Widths, Off),
86 | io:format("Code=~p~n",[Code]),
87 | eg_pdf:append_stream(PDF, Code).
88 |
89 | % for(0, _F) ->
90 | % true;
91 | % for(N, F) ->
92 | % F(N),
93 | % for(N-1, F).
94 |
95 | % justified_para(Leading, Offset, Width, N) ->
96 | % justified_para(Leading, Offset, Width, 0, N).
97 |
98 | % justified_para(Leading, Offset, Width, Rot, N) ->
99 | % {justified, Leading, Rot,
100 | % [Offset|lists:duplicate(N-1, 0)],
101 | % [Width-Offset|lists:duplicate(N-1,Width)]}.
102 |
103 | % ragged_para(Leading, Offset, Width, N) ->
104 | % {ragged, Leading,
105 | % [Offset|lists:duplicate(N-1, 0)],
106 | % [Width-Offset|lists:duplicate(N-1,Width)]}.
107 |
108 | text(N, Pts) ->
109 | text(N, 0, Pts).
110 |
111 | text(1, Rot, Pts) ->
112 | eg_richText:str2richText("Rotation =" ++ eg_pdf_op:i2s(Rot) ++
113 | " Hello joe how are you today?
114 | May I take this opportunity
115 | of saying
116 | that my favorite color is blue.
117 | Have a nice day,
118 | from Mr. C. Computer.", Pts).
119 |
120 |
--------------------------------------------------------------------------------
/test/eg_test6.erl:
--------------------------------------------------------------------------------
1 | %%==========================================================================
2 | %% Copyright (C) 2003 Joe Armstrong
3 | %%
4 | %% Permission is hereby granted, free of charge, to any person obtaining a
5 | %% copy of this software and associated documentation files (the
6 | %% "Software"), to deal in the Software without restriction, including
7 | %% without limitation the rights to use, copy, modify, merge, publish,
8 | %% distribute, sublicense, and/or sell copies of the Software, and to permit
9 | %% persons to whom the Software is furnished to do so, subject to the
10 | %% following conditions:
11 | %%
12 | %% The above copyright notice and this permission notice shall be included
13 | %% in all copies or substantial portions of the Software.
14 | %%
15 | %% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 | %% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | %% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
18 | %% NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
19 | %% DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20 | %% OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21 | %% USE OR OTHER DEALINGS IN THE SOFTWARE.
22 | %%
23 | %% Authors: Joe Armstrong
24 | %% Purpose: Grid planning sheet
25 | %%==========================================================================
26 |
27 | -module(eg_test6).
28 |
29 | -export([test/0]).
30 |
31 | %% ============================================================================
32 |
33 | test()->
34 | PDF = eg_pdf:new(),
35 | eg_pdf:set_pagesize(PDF,a4),
36 | eg_pdf:set_page(PDF,1),
37 | %% eg_pdf:set_font(PDF, "GoodCityModern", 40),
38 | eg_pdf:set_font(PDF, "Victorias-Secret", 40),
39 | eg_pdf:moveAndShow(PDF, 50, 700, "Hello Joe from Gutenburg"),
40 |
41 | {Serialised, _PageNo} = eg_pdf:export(PDF),
42 | file:write_file("eg_test6.pdf",[Serialised]),
43 | eg_pdf:delete(PDF).
44 |
45 |
--------------------------------------------------------------------------------
/test/erlguten:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | erl -pa ../ebin -pa `pwd` -s erlguten batch $1 -s erlang halt
3 |
--------------------------------------------------------------------------------
/test/galley_001.gal:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/test/galley_002.gal:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/test/joenew.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/test/joenew.jpg
--------------------------------------------------------------------------------
/test/kd_test1.erl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/test/kd_test1.erl
--------------------------------------------------------------------------------
/test/template1.tem:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
9 |
10 |
12 |
13 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/test/template_001.tem:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
35 |
36 |
37 |
38 |
39 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/test/test1.map:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
16 |
17 |
18 | Using Erlang in typography applications
"
19 |
20 |
21 |
22 | INTRODUCTION
"
23 |
24 |
25 |
26 | This is a small footnote set in 8/10 Times Italic
"
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/test/test1.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.4
2 | 1 0 obj
3 | <<
4 | /Type /Font
5 | /Subtype /Type1
6 | /Name /F3
7 | /BaseFont /Helvetica
8 | /Encoding /MacRomanEncoding
9 | >>
10 | endobj
11 | 2 0 obj
12 | <<
13 | /Type /Font
14 | /Subtype /Type1
15 | /Name /F5
16 | /BaseFont /Courier
17 | /Encoding /MacRomanEncoding
18 | >>
19 | endobj
20 | 3 0 obj
21 | <<
22 | /Type /Font
23 | /Subtype /Type1
24 | /Name /F1
25 | /BaseFont /Times-Bold
26 | /Encoding /MacRomanEncoding
27 | >>
28 | endobj
29 | 4 0 obj
30 | <<
31 | /Type /Font
32 | /Subtype /Type1
33 | /Name /F2
34 | /BaseFont /Times-Italic
35 | /Encoding /MacRomanEncoding
36 | >>
37 | endobj
38 | 5 0 obj
39 | <<
40 | /Type /Font
41 | /Subtype /Type1
42 | /Name /F4
43 | /BaseFont /Times-Roman
44 | /Encoding /MacRomanEncoding
45 | >>
46 | endobj
47 | 6 0 obj
48 | <<
49 | /F3 1 0 R
50 | /F5 2 0 R
51 | /F1 3 0 R
52 | /F2 4 0 R
53 | /F4 5 0 R
54 | >>
55 | endobj
56 | 7 0 obj
57 | <<
58 | /Type /Pages
59 | /Count 1
60 | /MediaBox [ 0 0 595 842 ]
61 | /Kids [ 9 0 R ]
62 | /Resources <<
63 | /Font 6 0 R
64 | /ProcSet [ /PDF /Text ]
65 | >>
66 |
67 | >>
68 | endobj
69 | 8 0 obj
70 | <>
71 | stream
72 | BT
73 | 1 0 0 1 100 728 Tm 0 Tw /F1 32 Tf
74 | 0 Tw [ (ErlGuten)0 ] TJ
75 | ET
76 | BT
77 | 1 0 0 1 100 698 Tm 0 Tw /F2 10 Tf
78 | 0 Tw [ (Using Erlang in typo)10 (gr)15 (aphy applications)0 ] TJ
79 | ET
80 |
81 | q
82 | 0.90 0.80 0.60 rg
83 | 101 779 370 22 re f
84 |
85 | Q
86 | BT
87 | 1 0 0 1 106 784 Tm 0 Tw /F3 10 Tf
88 | 0 Tw [ (INTR)20 (ODUCTION)0 ] TJ
89 | ET
90 | BT
91 | 1 0 0 1 100 50 Tm 0 Tw /F2 8 Tf
92 | 0 Tw [ (This is a small footnote set in 8/10 T)55 (imes Italic)0 ] TJ
93 | ET
94 | q 0.4 g 0.4 G 0 w 100 60 m 100 50 l S 460 60 m 460 50 l S 100 60 m 460 60 l S 100 50 m 460 50 l S Q BT
95 | 1 0 0 1 100 666 Tm 12 0 Td 0.34 Tw /F2 12 Tf
96 | 0.34 Tw [ (ErlGuten.)0 ] TJ
97 | /F4 12 Tf
98 | 0.34 Tw [ ( is a system for hiqh quality typesetting, ErlGuten is free soft-)0 ] TJ
99 | -12 -14 Td -1.02 Tw [ (w)10 (are. ErlGuten aims to produce typographic quality PDF directly from XML)0 ] TJ
100 | 0 -14 Td 0 Tw [ (or from a program.)0 ] TJ
101 | ET
102 | BT
103 | 1 0 0 1 100 624 Tm 12 0 Td 0.38 Tw /F4 12 Tf
104 | 0.38 Tw [ ( The aim of ErlGuten is to produce high quality PDF from a layout lan-)0 ] TJ
105 | -12 -14 Td -0.94 Tw [ (guage or from a program. The ErlGuten distrib)20 (ution includes a programming)0 ] TJ
106 | 0 -14 Td 0.48 Tw [ (API, so that Erlang programs can produce PDF - and a typesetting system)0 ] TJ
107 | 0 -14 Td 0 Tw [ (for typesetting documents written in XML.)0 ] TJ
108 | ET
109 | BT
110 | 1 0 0 1 100 568 Tm 12 0 Td -0.04 Tw /F4 12 Tf
111 | -0.04 Tw [ (The document that you are reading w)10 (as authored in XML and typeset by)0 ] TJ
112 | -12 -14 Td 0.49 Tw [ (ErlGuten. The name ErlGuten is chosen because the program is written in)0 ] TJ
113 | 0 -14 Td 0 Tw [ (Erlang - the )0 ] TJ
114 | /F2 12 Tf
115 | 0 Tw [ (Guten)0 ] TJ
116 | /F4 12 Tf
117 | 0 Tw [ ( part is a reference to )0 ] TJ
118 | /F2 12 Tf
119 | 0 Tw [ (Gutenber)37 (g)0 ] TJ
120 | /F4 12 Tf
121 | 0 Tw [ ( the f)10 (ather of printing.)0 ] TJ
122 | ET
123 | BT
124 | 1 0 0 1 100 526 Tm 12 0 Td 0.01 Tw /F4 12 Tf
125 | 0.01 Tw [ (ErlGuten is a system for high quality typesetting, so we tak)10 (e a great deal)0 ] TJ
126 | -12 -14 Td -0.56 Tw [ (of care when formatting te)15 (xt, a lar)18 (ge number of optimizations are performed)0 ] TJ
127 | 0 -14 Td 0.25 Tw [ (which impro)15 (v)15 (e the quality of the printed te)15 (xt. Man)15 (y of these optimizations)0 ] TJ
128 | 0 -14 Td -0.18 Tw [ (are usually only found in e)15 (xpensi)25 (v)15 (e professional type-setting programs. W)80 (e)0 ] TJ
129 | 0 -14 Td -0.40 Tw [ (belie)25 (v)15 (e that WYSIWYG programs ha)20 (v)15 (e destro)10 (yed the f)20 (ine art of typesetting)0 ] TJ
130 | 0 -14 Td 0 Tw [ (- ErlGuten is a modest attempt to impro)15 (v)15 (e the situation.)0 ] TJ
131 | ET
132 | BT
133 | 1 0 0 1 100 442 Tm 12 0 Td 0.70 Tw /F4 12 Tf
134 | 0.70 Tw [ (W)80 (e ha)20 (v)15 (e chosen XML as the input language for it')55 (s wide appeal. XML)0 ] TJ
135 | -12 -14 Td -0.65 Tw [ (pro)15 (vides only a thin abstraction layer o)15 (v)15 (er the typesetting system - so the ad-)0 ] TJ
136 | 0 -14 Td 0.19 Tw [ (v)15 (enturous can use the programming interf)10 (ace to ErlGuten - to directly pro-)0 ] TJ
137 | 0 -14 Td -0.47 Tw [ (duce typographic quality PDF in real-time. W)80 (e e)15 (xpect this f)10 (acility to be use-)0 ] TJ
138 | 0 -14 Td 0 Tw [ (ful for the dynamic generation of documents from web-serv)15 (ers.)0 ] TJ
139 | ET
140 | BT
141 | 1 0 0 1 100 372 Tm 12 0 Td 0.61 Tw /F4 12 Tf
142 | 0.61 Tw [ (In ErlGuten we tak)10 (e the vie)25 (w that the highest le)25 (v)15 (el of abstraction is the)0 ] TJ
143 | -12 -14 Td 0.26 Tw /F2 12 Tf
144 | 0.26 Tw [ (layout)0 ] TJ
145 | /F4 12 Tf
146 | 0.26 Tw [ ( of a document - we are v)15 (ery concerned that the user can specify the)0 ] TJ
147 | 0 -14 Td -0.47 Tw /F2 12 Tf
148 | -0.47 Tw [ (e)20 (xact)0 ] TJ
149 | /F4 12 Tf
150 | -0.47 Tw [ ( position of te)15 (xt on the printed page. At the ne)15 (xt le)25 (v)15 (el of abstraction we)0 ] TJ
151 | 0 -14 Td -0.27 Tw [ (are concerned with the typef)10 (aces that are used to format dif)25 (ferent re)15 (gions of)0 ] TJ
152 | 0 -14 Td 0 Tw [ (the document.)0 ] TJ
153 | ET
154 | BT
155 | 1 0 0 1 100 302 Tm 12 0 Td -0.15 Tw /F4 12 Tf
156 | -0.15 Tw [ (ErlGuten is designed for the production of lar)18 (ge and comple)15 (x documents)0 ] TJ
157 | -12 -14 Td 0.63 Tw [ (with comple)15 (x layout requirements, lik)10 (e )0 ] TJ
158 | /F2 12 Tf
159 | 0.63 Tw [ (ne)15 (wspaper)10 (s)0 ] TJ
160 | /F4 12 Tf
161 | 0.63 Tw [ ( or )0 ] TJ
162 | /F2 12 Tf
163 | 0.63 Tw [ (books)0 ] TJ
164 | /F4 12 Tf
165 | 0.63 Tw [ (. In ErlGuten)0 ] TJ
166 | 0 -14 Td 0.13 Tw [ (layout, content, and document management are considered separate issues.)0 ] TJ
167 | 0 -14 Td 0.07 Tw [ (Layout is )0 ] TJ
168 | /F2 12 Tf
169 | 0.07 Tw [ (template based)0 ] TJ
170 | /F4 12 Tf
171 | 0.07 Tw [ ( - Content is assumed to be stored as a lar)18 (ge num-)0 ] TJ
172 | 0 -14 Td -0.95 Tw [ (ber of documents in a f)20 (ile system or data base, document management is con-)0 ] TJ
173 | 0 -14 Td 0.41 Tw [ (sidered as a mapping operation which tak)10 (es documents in the content data)0 ] TJ
174 | 0 -14 Td 0 Tw [ (base and maps them onto templates to produce hight quality output.)0 ] TJ
175 | ET
176 | BT
177 | 1 0 0 1 100 204 Tm 12 0 Td 0.50 Tw /F4 12 Tf
178 | 0.50 Tw [ (This is normal te)15 (xt, set 30 picas wide in 12/14 T)35 (imes Roman. Man)15 (y di-)0 ] TJ
179 | -12 -14 Td 0.37 Tw [ (f)25 (ferent typef)10 (aces can be used within a paragraph. )0 ] TJ
180 | /F2 12 Tf
181 | 0.37 Tw [ (Emphasized te)20 (xt)0 ] TJ
182 | /F4 12 Tf
183 | 0.37 Tw [ ( is set in)0 ] TJ
184 | 0 -14 Td -0.01 Tw [ (T)35 (imes-Italic. Hyphenation uses the T)70 (eX h)5 (yphenation algorithm. An)15 (y of the)0 ] TJ
185 | 0 -14 Td 1.40 Tw [ (35 b)20 (uilt-in PDF typef)10 (aces with the same point size can be mix)15 (ed with a)0 ] TJ
186 | 0 -14 Td -0.37 Tw [ (paragraph. The term )0 ] TJ
187 | /F5 12 Tf
188 | 0 Tw [ ({person,"Joe"})0 ] TJ
189 | /F4 12 Tf
190 | -0.37 Tw [ ( is an Erlang term which has been)0 ] TJ
191 | 0 -14 Td -0.67 Tw [ (typeset in 12 point )0 ] TJ
192 | /F2 12 Tf
193 | -0.67 Tw [ (courier)0 ] TJ
194 | /F4 12 Tf
195 | -0.67 Tw [ (. The paragraph justif)20 (ication algorithm does prop-)0 ] TJ
196 | 0 -14 Td -0.71 Tw [ (er )0 ] TJ
197 | /F2 12 Tf
198 | -0.71 Tw [ (k)10 (erning)0 ] TJ
199 | /F4 12 Tf
200 | -0.71 Tw [ ( so, for e)15 (xample, the w)10 (ord A)90 (W)120 (A)105 (Y is correctly k)10 (erned! - line breaks)0 ] TJ
201 | 0 -14 Td -0.19 Tw [ (within a paragraph are selected by a sophisticated global optimization tech-)0 ] TJ
202 | 0 -14 Td 0 Tw [ (nique.)0 ] TJ
203 | ET
204 |
205 | endstream
206 | endobj
207 | 9 0 obj
208 | <<
209 | /Type /Page
210 | /Parent 7 0 R
211 | /Contents 8 0 R
212 | >>
213 | endobj
214 | 10 0 obj
215 | <<
216 | /Type /Catalog
217 | /Pages 7 0 R
218 | >>
219 | endobj
220 | 11 0 obj
221 | <<
222 | /Creator (Erlang)
223 | /CreationDate (D:20030215152011)
224 | /Producer (erlguten-2.0)
225 | /Author ()
226 | /Title ()
227 | /Subject ()
228 | /Keywords (ErlangKeyword)
229 | >>
230 | endobj
231 | xref
232 | 0 12
233 | 0000000000 65535 f
234 | 0000000009 00000 n
235 | 0000000127 00000 n
236 | 0000000243 00000 n
237 | 0000000362 00000 n
238 | 0000000483 00000 n
239 | 0000000603 00000 n
240 | 0000000684 00000 n
241 | 0000000845 00000 n
242 | 0000006837 00000 n
243 | 0000006906 00000 n
244 | 0000006960 00000 n
245 | trailer
246 | <<
247 | /Size 12
248 | /Root 10 0 R
249 | /Info 11 0 R
250 | >>
251 | startxref
252 | 7131
253 | %%EOF
254 |
--------------------------------------------------------------------------------
/test/test1.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ErlGuten
"
6 |
7 |
8 |
9 | Using Erlang in typography applications
"
10 |
11 |
12 |
13 | INTRODUCTION
"
14 |
15 |
16 |
17 | This is a small footnote set in 8/10 Times Italic
"
18 |
19 |
20 |
21 |
22 | ErlGuten. is a system for hiqh quality typesetting,
23 | ErlGuten is free software. ErlGuten aims to produce typographic
24 | quality PDF directly from XML or from a program.
25 |
26 | The aim of ErlGuten is to produce high quality PDF from a layout
27 | language or from a program. The ErlGuten distribution includes a
28 | programming API, so that Erlang programs can produce PDF - and a
29 | typesetting system for typesetting documents written in XML.
30 |
31 | The document that you are reading was authored in XML and typeset
32 | by ErlGuten. The name ErlGuten is chosen because the program is
33 | written in Erlang - the Guten part is a reference to
34 | Gutenberg the father of printing.
35 |
36 | ErlGuten is a system for high quality typesetting, so we take a
37 | great deal of care when formatting text, a large number of
38 | optimizations are performed which improve the quality of the printed
39 | text. Many of these optimizations are usually only found in expensive
40 | professional type-setting programs. We believe that WYSIWYG programs
41 | have destroyed the fine art of typesetting - ErlGuten is a modest
42 | attempt to improve the situation.
43 |
44 | We have chosen XML as the input language for it's wide appeal.
45 | XML provides only a thin abstraction layer over the typesetting system
46 | - so the adventurous can use the programming interface to ErlGuten -
47 | to directly produce typographic quality PDF in real-time. We expect
48 | this facility to be useful for the dynamic generation of documents
49 | from web-servers.
50 |
51 | In ErlGuten we take the view that the highest level of
52 | abstraction is the layout of a document - we are very
53 | concerned that the user can specify the exact position of
54 | text on the printed page. At the next level of abstraction we are
55 | concerned with the typefaces that are used to format different regions
56 | of the document.
57 |
58 | ErlGuten is designed for the production of large and complex
59 | documents with complex layout requirements, like newspapers
60 | or books. In ErlGuten layout, content, and document
61 | management are considered separate issues. Layout is template
62 | based - Content is assumed to be stored as a large number of
63 | documents in a file system or data base, document management is
64 | considered as a mapping operation which takes documents in the
65 | content data base and maps them onto templates to produce hight
66 | quality output.
67 |
68 | This is normal text, set 30 picas wide in 12/14 Times Roman.
69 | Many different typefaces can be used within a paragraph.
70 | Emphasized text is set in Times-Italic. Hyphenation uses the
71 | TeX hyphenation algorithm. Any of the 35 built-in PDF typefaces with
72 | the same point size can be mixed with a paragraph. The term
73 | {person,"Joe"}
is an Erlang term which has been typeset
74 | in 12 point courier. The paragraph justification algorithm
75 | does proper kerning so, for example, the word AWAY is
76 | correctly kerned! - line breaks within a paragraph are selected by a
77 | sophisticated global optimization technique.
78 |
79 |
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/test/test2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Erlguten
"
6 |
7 |
8 |
9 | This is a small footnote set in 6/8 Times Italic. Note that the order
10 | of lines in the output has nothing to do with the order on the page.
"
11 |
12 |
13 |
14 |
15 | Welcome to ErlGuten. ErlGuten is a system for
16 | typesetting. The aim of ErlGuten is to produce high quality PDF from
17 | a layout language or from a program. The ErlGuten distribution
18 | includes a programming API, so that programs can produce PDF - and a
19 | typesetting system for typesetting documents written in XML.
20 |
21 | The document that you are reading was authored in XML and typeset
22 | by ErlGuten. The name ErlGuten is chosen because the program is
23 | written in Erlang - the Guten part is a reference to
24 | Gutenberg the father of printing.
25 |
26 | ErlGuten is a system for high quality typesetting, so we take a
27 | great deal of care when formatting text, a large number of
28 | optimizations are performed which improve the quality of the printed
29 | text. Many of these optimizations are only found in expensive
30 | professional type-setting programs. We believe that WYSIWYG programs
31 | have destroyed the fine art of typesetting - ErlGuten is a modest
32 | attempt to improve the situation.
33 |
34 | We have chosen XML as the input language for it's wide appeal -
35 | not because of any intrinsic advantages that XML might have. XML
36 | provides only a thin abstraction layer over the typesetting system -
37 | so the adventurous can use the programming interface to ErlGuten - to
38 | directly produce typographic quality PDF in real-time. We expect this
39 | facility to be useful for the dynamic generation of documents from
40 | web-servers.
41 |
42 | In ErlGuten we take the view that the highest level of
43 | abstraction is the layout of a document - we are very
44 | concerned that the user can specify the exact position of
45 | text on the printed page. At the next level of abstraction we are
46 | concerned with the typefaces that are used to format different regions
47 | of the document - our system makes use of the 14 in-built PDF fonts -
48 | for specialist work type 1 postscript fonts can be used and embedded
49 | in the resulting output. The ErlGuten distribution includes a number
50 | of public domain Type 1 postscript fonts that can be freely included
51 | in any document produced by ErlGuten.
52 |
53 | Here, paragraphs are composed of 11/13
54 | NewCenturySchlbk-Roman set in a 30 pica measure.
55 | Emphasized text is set in NewCentrySchlbk-Italic. The TeX
56 | hyphenation algorithm is also implemented. I have also some
57 | cursive text and an example of an Erlang term.
58 |
59 |
60 |
61 | The term {person,"Joe"}
is an Erlang term. The
62 | variable X
, was immediately followed by a comma. The
63 | justification algorithm does proper kerning, which is more
64 | than Microsoft Word can do. AWAY again is correctly kerned!
65 | Erlang terms {like,this}
are typeset in
66 | courier.
67 |
68 | Note, if punctuation is used, it must be attached
69 | to the preceding tagged block, like this, but never
70 | like this, which is incorrect.
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/test/tmobile.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/richcarl/erlguten/debd6120907e5e18b4bca5fbd5bdd9cb653f282d/test/tmobile.jpg
--------------------------------------------------------------------------------
/vsn.mk:
--------------------------------------------------------------------------------
1 | VSN=2.5.1
2 |
--------------------------------------------------------------------------------