fpdf 1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (6) hide show
  1. data/lib/bookmark.rb +99 -0
  2. data/lib/chinese.rb +445 -0
  3. data/lib/fpdf.rb +1536 -0
  4. data/lib/fpdf_eps.rb +139 -0
  5. data/lib/makefont.rb +1787 -0
  6. metadata +50 -0
@@ -0,0 +1,99 @@
1
+ # Translation of the bookmark class from the PHP FPDF script from Olivier Plathey
2
+ # Translated by Sylvain Lafleur and ?? with the help of Brian Ollenberger
3
+ #
4
+ # First added in 1.53b
5
+ #
6
+ # Usage is as follows:
7
+ #
8
+ # require 'fpdf'
9
+ # require 'bookmark'
10
+ # pdf = FPDF.new
11
+ # pdf.extend(PDF_Bookmark)
12
+ #
13
+ # This allows it to be combined with other extensions, such as the Chinese
14
+ # module.
15
+
16
+ module PDF_Bookmark
17
+ def PDF_Bookmark.extend_object(o)
18
+ o.instance_eval('@outlines,@OutlineRoot=[],0')
19
+ super(o)
20
+ end
21
+
22
+ def Bookmark(txt,level=0,y=0)
23
+ y=self.GetY() if y==-1
24
+ @outlines.push({'t'=>txt,'l'=>level,'y'=>y,'p'=>self.PageNo()})
25
+ end
26
+
27
+ def putbookmarks
28
+ @nb=@outlines.size
29
+ return if @nb==0
30
+ lru=[]
31
+ level=0
32
+ @outlines.each_index do |i|
33
+ o=@outlines[i]
34
+ if o['l']>0
35
+ parent=lru[o['l']-1]
36
+ # Set parent and last pointers
37
+ @outlines[i]['parent']=parent
38
+ @outlines[parent]['last']=i
39
+ if o['l']>level
40
+ # Level increasing: set first pointer
41
+ @outlines[parent]['first']=i
42
+ end
43
+ else
44
+ @outlines[i]['parent']=@nb
45
+ end
46
+ if o['l']<=level and i>0
47
+ # Set prev and next pointers
48
+ prev=lru[o['l']]
49
+ @outlines[prev]['next']=i
50
+ @outlines[i]['prev']=prev
51
+ end
52
+ lru[o['l']]=i
53
+ level=o['l']
54
+ end
55
+ # Outline items
56
+ n=@n+1
57
+ @outlines.each_index do |i|
58
+ o=@outlines[i]
59
+ newobj
60
+ out('<</Title '+(textstring(o['t'])))
61
+ out('/Parent '+(n+o['parent']).to_s+' 0 R')
62
+ if o['prev']
63
+ out('/Prev '+(n+o['prev']).to_s+' 0 R')
64
+ end
65
+ if o['next']
66
+ out('/Next '+(n+o['next']).to_s+' 0 R')
67
+ end
68
+ if o['first']
69
+ out('/First '+(n+o['first']).to_s+' 0 R')
70
+ end
71
+ if o['last']
72
+ out('/Last '+(n+o['last']).to_s+' 0 R')
73
+ end
74
+ out(sprintf('/Dest [%d 0 R /XYZ 0 %.2f
75
+ null]',1+2*o['p'],(@h-o['y'])*@k))
76
+ out('/Count 0>>')
77
+ out('endobj')
78
+ end
79
+ # Outline root
80
+ newobj
81
+ @OutlineRoot=@n
82
+ out('<</Type /Outlines /First '+n.to_s+' 0 R')
83
+ out('/Last '+(n+lru[0]).to_s+' 0 R>>')
84
+ out('endobj')
85
+ end
86
+
87
+ def putresources
88
+ super
89
+ putbookmarks
90
+ end
91
+
92
+ def putcatalog
93
+ super
94
+ if not @outlines.empty?
95
+ out('/Outlines '+@OutlineRoot.to_s+' 0 R')
96
+ out('/PageMode /UseOutlines')
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,445 @@
1
+ # Chinese support ported by Brian Ollenberger from Oliver Plathey's
2
+ # Chinese PDF support.
3
+ #
4
+ # First added in 1.53b
5
+ #
6
+ # This is currently totally untested. Please let me know if you run into any bugs.
7
+ #
8
+ # Usage is as follows:
9
+ #
10
+ # require 'fpdf'
11
+ # require 'chinese'
12
+ # pdf = FPDF.new
13
+ # pdf.extend(PDF_Chinese)
14
+ #
15
+ # This allows it to be combined with other extensions, such as the bookmark
16
+ # module.
17
+
18
+ module PDF_Chinese
19
+ Big5_widths = {' '=>250,'!'=>250,'"'=>408,'#'=>668,'$'=>490,'%'=>875,'&'=>698,'\''=>250,
20
+ '('=>240,')'=>240,'*'=>417,'+'=>667,','=>250,'-'=>313,'.'=>250,'/'=>520,'0'=>500,'1'=>500,
21
+ '2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>250,';'=>250,
22
+ '<'=>667,'='=>667,'>'=>667,'?'=>396,'@'=>921,'A'=>677,'B'=>615,'C'=>719,'D'=>760,'E'=>625,
23
+ 'F'=>552,'G'=>771,'H'=>802,'I'=>354,'J'=>354,'K'=>781,'L'=>604,'M'=>927,'N'=>750,'O'=>823,
24
+ 'P'=>563,'Q'=>823,'R'=>729,'S'=>542,'T'=>698,'U'=>771,'V'=>729,'W'=>948,'X'=>771,'Y'=>677,
25
+ 'Z'=>635,'['=>344,'\\'=>520,']'=>344,'^'=>469,'_'=>500,'`'=>250,'a'=>469,'b'=>521,'c'=>427,
26
+ 'd'=>521,'e'=>438,'f'=>271,'g'=>469,'h'=>531,'i'=>250,'j'=>250,'k'=>458,'l'=>240,'m'=>802,
27
+ 'n'=>531,'o'=>500,'p'=>521,'q'=>521,'r'=>365,'s'=>333,'t'=>292,'u'=>521,'v'=>458,'w'=>677,
28
+ 'x'=>479,'y'=>458,'z'=>427,'{'=>480,'|'=>496,'}'=>480,'~'=>667}
29
+
30
+ GB_widths = {' '=>207,'!'=>270,'"'=>342,'#'=>467,'$'=>462,'%'=>797,'&'=>710,'\''=>239,
31
+ '('=>374,')'=>374,'*'=>423,'+'=>605,','=>238,'-'=>375,'.'=>238,'/'=>334,'0'=>462,'1'=>462,
32
+ '2'=>462,'3'=>462,'4'=>462,'5'=>462,'6'=>462,'7'=>462,'8'=>462,'9'=>462,':'=>238,';'=>238,
33
+ '<'=>605,'='=>605,'>'=>605,'?'=>344,'@'=>748,'A'=>684,'B'=>560,'C'=>695,'D'=>739,'E'=>563,
34
+ 'F'=>511,'G'=>729,'H'=>793,'I'=>318,'J'=>312,'K'=>666,'L'=>526,'M'=>896,'N'=>758,'O'=>772,
35
+ 'P'=>544,'Q'=>772,'R'=>628,'S'=>465,'T'=>607,'U'=>753,'V'=>711,'W'=>972,'X'=>647,'Y'=>620,
36
+ 'Z'=>607,'['=>374,'\\'=>333,']'=>374,'^'=>606,'_'=>500,'`'=>239,'a'=>417,'b'=>503,'c'=>427,
37
+ 'd'=>529,'e'=>415,'f'=>264,'g'=>444,'h'=>518,'i'=>241,'j'=>230,'k'=>495,'l'=>228,'m'=>793,
38
+ 'n'=>527,'o'=>524,'p'=>524,'q'=>504,'r'=>338,'s'=>336,'t'=>277,'u'=>517,'v'=>450,'w'=>652,
39
+ 'x'=>466,'y'=>452,'z'=>407,'{'=>370,'|'=>258,'}'=>370,'~'=>605}
40
+
41
+ def AddCIDFont(family,style,name,cw,cMap,registry)
42
+ fontkey=family.downcase + style.upcase;
43
+ unless @fonts[fontkey].nil?
44
+ Error("Font already added: #{family} #{style}")
45
+ end
46
+ i=@fonts.length+1
47
+ name.sub!(' ', '')
48
+ @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,
49
+ 'ut'=>40,'cw'=>cw,'CMap'=>cMap,'registry'=>registry}
50
+ end
51
+
52
+ def AddCIDFonts(family,name,cw,cMap,registry)
53
+ AddCIDFont(family,'',name,cw,cMap,registry)
54
+ AddCIDFont(family,'B',name+',Bold',cw,cMap,registry)
55
+ AddCIDFont(family,'I',name+',Italic',cw,cMap,registry)
56
+ AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)
57
+ end
58
+
59
+ def AddBig5Font(family='Big5',name='MSungStd-Light-Acro')
60
+ # Add Big5 font with proportional Latin
61
+ cw=Big5_widths
62
+ cMap='ETenms-B5-H'
63
+ registry={'ordering'=>'CNS1','supplement'=>0}
64
+ AddCIDFonts(family,name,cw,cMap,registry)
65
+ end
66
+
67
+ def AddBig5hwFont(family='Big5-hw',name='MSungStd-Light-Acro')
68
+ # Add Big5 font with half-width Latin
69
+ cw = {}
70
+ 32.upto(126) do |i|
71
+ cw[i.chr]=500
72
+ end
73
+ cMap='ETen-B5-H'
74
+ registry={'ordering'=>'CNS1','supplement'=>0}
75
+ AddCIDFonts(family,name,cw,cMap,registry)
76
+ end
77
+
78
+ def AddGBFont(family='GB',name='STSongStd-Light-Acro')
79
+ # Add GB font with proportional Latin
80
+ cw=GB_widths
81
+ cMap='GBKp-EUC-H'
82
+ registry={'ordering'=>'GB1','supplement'=>2}
83
+ AddCIDFonts(family,name,cw,cMap,registry)
84
+ end
85
+
86
+ def AddGBhwFont(family='GB-hw',name='STSongStd-Light-Acro')
87
+ # Add GB font with half-width Latin
88
+ 32.upto(126) do |i|
89
+ cw[i.chr]=500
90
+ end
91
+ cMap='GBK-EUC-H'
92
+ registry={'ordering'=>'GB1','supplement'=>2}
93
+ AddCIDFonts(family,name,cw,cMap,registry)
94
+ end
95
+
96
+ def GetStringWidth(s)
97
+ if @CurrentFont['type']=='Type0'
98
+ GetMBStringWidth(s)
99
+ else
100
+ super(s)
101
+ end
102
+ end
103
+
104
+ def GetMBStringWidth(s)
105
+ # Multi-byte version of GetStringWidth()
106
+ l=0
107
+ cw=@CurrentFont['cw']
108
+ nb=s.length
109
+ i=0
110
+ while i<nb
111
+ c=s[i]
112
+ if c.ord < 128
113
+ l += cw[c]
114
+ i += 1
115
+ else
116
+ l += 1000
117
+ i += 2
118
+ end
119
+ end
120
+ l*@FontSize/1000
121
+ end
122
+
123
+ def MultiCell(w,h,txt,border=0,align='L',fill=0)
124
+ if @CurrentFont['type']=='Type0'
125
+ MBMultiCell(w,h,txt,border,align,fill)
126
+ else
127
+ super(w,h,txt,border,align,fill)
128
+ end
129
+ end
130
+
131
+ def MBMultiCell(w,h,txt,border=0,align='L',fill=0)
132
+ # Multi-byte version of MultiCell()
133
+ cw=@CurrentFont['cw']
134
+ w=@w-@rMargin-@x if w==0
135
+ wmax=(w-2*@cMargin)*1000/@FontSize
136
+ txt.sub("\r", '')
137
+ nb=s.length
138
+ nb -= 1 if nb>0 and s[nb-1]=="\n"
139
+ b=0
140
+ if border
141
+ if border==1
142
+ border='LTRB'
143
+ b='LRT'
144
+ b2='LR'
145
+ else
146
+ b2=''
147
+ b2+='L' unless border.index('L').nil?
148
+ b2+='R' unless border.index('R').nil?
149
+ b = (border.index('T')) ? (b2+'T') : b2
150
+ end
151
+ end
152
+ sep=-1
153
+ i=0
154
+ j=0
155
+ l=0
156
+ nl=1
157
+ while i<nb
158
+ # Get next character
159
+ c=s[i]
160
+ # Check if ASCII or MB
161
+ ascii = false
162
+ if c < 128
163
+ ascii = true
164
+ end
165
+ if c.chr=="\n"
166
+ # Explicit line break
167
+ Cell(w,h,s[j..i-j],b,2,align,fill)
168
+ i+=1
169
+ sep=-1
170
+ j=i
171
+ l=0
172
+ nl+=1
173
+ if border and nl==2
174
+ b=b2
175
+ end
176
+ next
177
+ end
178
+ if not ascii
179
+ sep=i
180
+ ls=l
181
+ elsif c.chr==' '
182
+ sep=i
183
+ ls=l
184
+ end
185
+ if ascii
186
+ l += cw[c.chr]
187
+ else
188
+ l += 1000
189
+ end
190
+ if l>wmax
191
+ # Automatic line break
192
+ if sep==-1 or i==j
193
+ i += ascii ? 1 : 2 if i==j
194
+ Cell(w,h,s[j..i-j],b,2,align,fill)
195
+ else
196
+ Cell(w,h,s[j..sep-j],b,2,align,fill)
197
+ i=(s[sep]==' ') ? sep+1 : sep
198
+ end
199
+ sep=-1
200
+ j=i
201
+ l=0
202
+ nl+=1
203
+ if border and nl==2
204
+ b=b2
205
+ end
206
+ else
207
+ i+=$ascii ? 1 : 2
208
+ end
209
+ end
210
+
211
+ # Last chunk
212
+ b += 'B' if border and not border.index('B').nil?
213
+ Cell(w,h,s[i..i-j],b,2,align,fill)
214
+ @x=@lMargin
215
+ end
216
+
217
+ def Write(h,txt,link='')
218
+ if @CurrentFont['type']=='Type0'
219
+ MBWrite(h,txt,link)
220
+ else
221
+ super(h,txt,link)
222
+ end
223
+ end
224
+
225
+ def MBWrite(h,txt,link)
226
+ # Multi-byte version of Write()
227
+ cw=@CurrentFont['cw']
228
+ w=@w-@rMargin-@x
229
+ wmax=(w-2*@cMargin)*1000/@FontSize
230
+ s=txt.sub("\r", ' ')
231
+ nb=s.length
232
+ sep=-1
233
+ i=0
234
+ j=0
235
+ l=0
236
+ nl=1
237
+ while i<nb
238
+ # Get next character
239
+ c=s[i]
240
+ # Check if ASCII or MB
241
+ ascii = false
242
+ if c < 128
243
+ ascii = true
244
+ end
245
+ if c.chr=="\n"
246
+ #Explicit line break
247
+ Cell(w,h,s[j..i-j],0,2,'',0,link)
248
+ i+=1
249
+ sep=-1
250
+ j=i
251
+ l=0
252
+ if nl==1
253
+ @x=@lMargin
254
+ w=@w-@rMargin-@x
255
+ wmax=(w-2*@cMargin)*1000/@FontSize
256
+ end
257
+ nl+=1
258
+ next
259
+ end
260
+ sep=i if not ascii or c.chr==' '
261
+ if ascii
262
+ l += cw[c.chr]
263
+ else
264
+ l += 1000
265
+ end
266
+ if l>wmax
267
+ # Automatic line break
268
+ if sep==-1 or i==j
269
+ if @x>@lMargin
270
+ # Move to next line
271
+ @x=@lMargin
272
+ @y+=h
273
+ w=@w-@rMargin-@x
274
+ wmax=(w-2*@cMargin)*1000/@FontSize
275
+ i+=1
276
+ nl+=1
277
+ next
278
+ end
279
+ i+=ascii ? 1 : 2 if i==j
280
+ Cell(w,h,s[j..i-j],0,2,'',0,link)
281
+ else
282
+ Cell(w,h,s[j..sep-j],0,2,'',0,link)
283
+ i=(s[sep]==' ') ? sep+1 : sep
284
+ end
285
+ sep=-1
286
+ j=i
287
+ l=0
288
+ if nl==1
289
+ @x=@lMargin
290
+ w=@w-@rMargin-@x
291
+ wmax=(w-2*@cMargin)*1000/@FontSize
292
+ end
293
+ nl+=1
294
+ else
295
+ i+=ascii ? 1 : 2
296
+ end
297
+ end
298
+
299
+ #Last chunk
300
+ if i!=j
301
+ Cell(l/1000*@FontSize,h,s[j..i-j],0,0,'',0,link)
302
+ end
303
+ end
304
+
305
+ private
306
+
307
+ def putfonts
308
+ nf=@n
309
+ @diffs.each do |diff|
310
+ # Encodings
311
+ newobj
312
+ out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding '+
313
+ '/Differences ['+diff+']>>')
314
+ out('endobj')
315
+ end
316
+ @FontFiles.each_pair do |file, info|
317
+ # Font file embedding
318
+ newobj
319
+ @FontFiles[file]['n']=@n
320
+
321
+ if self.class.const_defined? 'FPDF_FONTPATH'
322
+ if FPDF_FONTPATH[-1,1] == '/'
323
+ file = FPDF_FONTPATH + file
324
+ else
325
+ file = FPDF_FONTPATH + '/' + file
326
+ end
327
+ end
328
+ size = File.size(file)
329
+ unless File.exists?(file)
330
+ Error('Font file not found')
331
+ end
332
+ out('<</Length '+size.to_s)
333
+ if file[-2]=='.z'
334
+ out('/Filter /FlateDecode')
335
+ end
336
+ out('/Length1 '+info['length1'])
337
+ if info['length2']
338
+ out('/Length2 '+info['length2']+' /Length3 0')
339
+ end
340
+ out('>>')
341
+ putstream(IO.read(file))
342
+ out('endobj')
343
+ end
344
+
345
+ @fonts.each_pair do |k, font|
346
+ # Font objects
347
+ newobj
348
+ @fonts[k]['n']=@n
349
+ out('<</Type /Font')
350
+ if font['type']=='Type0'
351
+ putType0(font)
352
+ else
353
+ name=font['name']
354
+ out('/BaseFont /'+name)
355
+ if font['type']=='core'
356
+ #Standard font
357
+ out('/Subtype /Type1')
358
+ if name!='Symbol' and name!='ZapfDingbats'
359
+ out('/Encoding /WinAnsiEncoding')
360
+ end
361
+ else
362
+ # Additional font
363
+ out('/Subtype /' + font['type'])
364
+ out('/FirstChar 32')
365
+ out('/LastChar 255')
366
+ out('/Widths '+(@n+1).to_s+' 0 R')
367
+ out('/FontDescriptor '+(@n+2).to_s+' 0 R')
368
+ if font['enc']
369
+ if font['diff']
370
+ out('/Encoding '+(nf+font['diff']).to_s+' 0 R')
371
+ else
372
+ out('/Encoding /WinAnsiEncoding')
373
+ end
374
+ end
375
+ end
376
+ out('>>')
377
+ out('endobj')
378
+ if font['type']!='core'
379
+ # Widths
380
+ newobj
381
+ cw=font['cw']
382
+ s='['
383
+ 32.upto(255) do |i|
384
+ s+=cw[i.chr].to_s+' '
385
+ end
386
+ out(s+']')
387
+ out('endobj')
388
+ # Descriptor
389
+ newobj
390
+ s='<</Type /FontDescriptor /FontName /'+name
391
+ font['desc'].each_pair do |k, v|
392
+ s+=' /'+k+' '+v
393
+ end
394
+ file=font['file']
395
+ if file
396
+ s+=' /FontFile'+((font['type']=='Type1') ? '' : '2')+
397
+ ' '+@FontFiles[file]['n']+' 0 R'
398
+ end
399
+ out(s+'>>')
400
+ out('endobj')
401
+ end
402
+ end
403
+ end
404
+ end
405
+
406
+ def putType0(font)
407
+ # Type0
408
+ out('/Subtype /Type0')
409
+ out('/BaseFont /'+font['name']+'-'+font['CMap'])
410
+ out('/Encoding /'+font['CMap'])
411
+ out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
412
+ out('>>')
413
+ out('endobj')
414
+ # CIDFont
415
+ newobj
416
+ out('<</Type /Font')
417
+ out('/Subtype /CIDFontType0')
418
+ out('/BaseFont /'+font['name'])
419
+ out('/CIDSystemInfo <</Registry '+textstring('Adobe')+' /Ordering '+
420
+ textstring(font['registry']['ordering'])+' /Supplement '+
421
+ font['registry']['supplement'].to_s+'>>')
422
+ out('/FontDescriptor '+(@n+1).to_s+' 0 R')
423
+ w='1 ['+font['cw'].values.join(' ')+']'
424
+ if font['CMap']=='ETen-B5-H'
425
+ w='13648 13742 500'
426
+ elsif(font['CMap']=='GBK-EUC-H')
427
+ w='814 907 500 7716 [500]'
428
+ end
429
+ out('/W ['+w+']>>')
430
+ out('endobj')
431
+ # Font descriptor
432
+ newobj
433
+ out('<</Type /FontDescriptor')
434
+ out('/FontName /'+font['name'])
435
+ out('/Flags 6')
436
+ out('/FontBBox [0 -200 1000 900]')
437
+ out('/ItalicAngle 0')
438
+ out('/Ascent 800')
439
+ out('/Descent -200')
440
+ out('/CapHeight 800')
441
+ out('/StemV 50')
442
+ out('>>')
443
+ out('endobj')
444
+ end
445
+ end