fpdf 1.53

Sign up to get free protection for your applications and to get access to all the features.
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