OSDN Git Service

add Redmine trunk rev 3089
[redminele/redminele.git] / redmine / vendor / plugins / rfpdf / lib / rfpdf / japanese.rb
1 # Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>
2 # 1.12 contributed by Ed Moss.
3 #
4 # The MIT License
5 #
6 # Permission is hereby granted, free of charge, to any person obtaining a copy
7 # of this software and associated documentation files (the "Software"), to deal
8 # in the Software without restriction, including without limitation the rights
9 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 # copies of the Software, and to permit persons to whom the Software is
11 # furnished to do so, subject to the following conditions:
12 #
13 # The above copyright notice and this permission notice shall be included in
14 # all copies or substantial portions of the Software.
15 #
16 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
19 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 # THE SOFTWARE.
23 #
24 # This is direct port of japanese.php
25 #
26 # Japanese PDF support.
27 #
28 # Usage is as follows:
29 #
30 # require 'fpdf'
31 # require 'chinese'
32 # pdf = FPDF.new
33 # pdf.extend(PDF_Japanese)
34 #
35 # This allows it to be combined with other extensions, such as the bookmark
36 # module.
37
38 module PDF_Japanese
39
40   SJIS_widths={' ' => 278, '!' => 299, '"' => 353, '#' => 614, '$' => 614, '%' => 721, '&' => 735, '\'' => 216, 
41         '(' => 323, ')' => 323, '*' => 449, '+' => 529, ',' => 219, '-' => 306, '.' => 219, '/' => 453, '0' => 614, '1' => 614, 
42         '2' => 614, '3' => 614, '4' => 614, '5' => 614, '6' => 614, '7' => 614, '8' => 614, '9' => 614, ':' => 219, ';' => 219, 
43         '<' => 529, '=' => 529, '>' => 529, '?' => 486, '@' => 744, 'A' => 646, 'B' => 604, 'C' => 617, 'D' => 681, 'E' => 567, 
44         'F' => 537, 'G' => 647, 'H' => 738, 'I' => 320, 'J' => 433, 'K' => 637, 'L' => 566, 'M' => 904, 'N' => 710, 'O' => 716, 
45         'P' => 605, 'Q' => 716, 'R' => 623, 'S' => 517, 'T' => 601, 'U' => 690, 'V' => 668, 'W' => 990, 'X' => 681, 'Y' => 634, 
46         'Z' => 578, '[' => 316, '\\' => 614, ']' => 316, '^' => 529, '_' => 500, '`' => 387, 'a' => 509, 'b' => 566, 'c' => 478, 
47         'd' => 565, 'e' => 503, 'f' => 337, 'g' => 549, 'h' => 580, 'i' => 275, 'j' => 266, 'k' => 544, 'l' => 276, 'm' => 854, 
48         'n' => 579, 'o' => 550, 'p' => 578, 'q' => 566, 'r' => 410, 's' => 444, 't' => 340, 'u' => 575, 'v' => 512, 'w' => 760, 
49         'x' => 503, 'y' => 529, 'z' => 453, '{' => 326, '|' => 380, '}' => 326, '~' => 387}
50
51   def AddCIDFont(family,style,name,cw,cMap,registry)    
52     fontkey=family.downcase+style.upcase
53         unless @fonts[fontkey].nil?
54                 Error("CID font already added: family style")
55         end  
56         i=@fonts.length+1
57         @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-120,'ut'=>40,'cw'=>cw,
58           'CMap'=>cMap,'registry'=>registry}
59   end
60
61   def AddCIDFonts(family,name,cw,cMap,registry)
62         AddCIDFont(family,'',name,cw,cMap,registry)
63         AddCIDFont(family,'B',name+',Bold',cw,cMap,registry)
64         AddCIDFont(family,'I',name+',Italic',cw,cMap,registry)
65         AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)
66   end
67
68   def AddSJISFont(family='SJIS')
69         #Add SJIS font with proportional Latin
70         name='KozMinPro-Regular-Acro'
71         cw=SJIS_widths
72         cMap='90msp-RKSJ-H'
73         registry={'ordering'=>'Japan1','supplement'=>2}
74         AddCIDFonts(family,name,cw,cMap,registry)
75   end
76
77   def AddSJIShwFont(family='SJIS-hw')
78         #Add SJIS font with half-width Latin
79         name='KozMinPro-Regular-Acro'
80     32.upto(126) do |i|
81                 cw[i.chr]=500
82         end  
83         cMap='90ms-RKSJ-H'
84         registry={'ordering'=>'Japan1','supplement'=>2}
85         AddCIDFonts(family,name,cw,cMap,registry)
86   end
87
88   def GetStringWidth(s)
89         if(@CurrentFont['type']=='Type0')
90                 return GetSJISStringWidth(s)
91         else
92                 return super(s)
93         end  
94   end
95
96   def GetSJISStringWidth(s)
97         #SJIS version of GetStringWidth()
98         l=0
99         cw=@CurrentFont['cw']
100         nb=s.length
101         i=0
102         while(i<nb)
103                 o=s[i]
104                 if(o<128)
105                         #ASCII
106                         l+=cw[o.chr]
107                         i+=1
108                 elsif(o>=161 and o<=223)
109                         #Half-width katakana
110                         l+=500
111                         i+=1
112                 else
113                         #Full-width character
114                         l+=1000
115                         i+=2
116                 end
117         end
118         return l*@FontSize/1000
119   end
120
121   def MultiCell(w,h,txt,border=0,align='L',fill=0)
122         if(@CurrentFont['type']=='Type0')
123                 SJISMultiCell(w,h,txt,border,align,fill)
124         else
125                 super(w,h,txt,border,align,fill)
126         end  
127   end
128
129   def SJISMultiCell(w,h,txt,border=0,align='L',fill=0)
130         #Output text with automatic or explicit line breaks
131         cw=@CurrentFont['cw']
132         if(w==0)
133                 w=@w-@rMargin-@x
134         end  
135         wmax=(w-2*@cMargin)*1000/@FontSize
136         s=txt.gsub("\r",'')
137         nb=s.length
138         if(nb>0 and s[nb-1]=="\n")
139                 nb-=1
140         end  
141         b=0
142         if(border)
143                 if(border==1)
144                         border='LTRB'
145                         b='LRT'
146                         b2='LR'
147                 else
148                         b2=''
149                         if(border.to_s.index('L'))
150                                 b2+='L'
151         end  
152                         if(border.to_s.index('R'))
153                                 b2+='R'
154         end  
155                         b=border.to_s.index('T') ? b2+'T' : b2
156                 end
157         end
158         sep=-1
159         i=0
160         j=0
161         l=0
162         nl=1
163         while(i<nb)
164                 #Get next character
165                 c=s[i]
166                 o=c #o=ord(c)
167                 if(o==10)
168                         #Explicit line break
169                         Cell(w,h,s[j,i-j],b,2,align,fill)
170                         i+=1
171                         sep=-1
172                         j=i
173                         l=0
174                         nl+=1
175                         if(border and nl==2)
176                                 b=b2
177         end  
178                         next
179                 end
180                 if(o<128)
181                         #ASCII
182                         l+=cw[c.chr]
183                         n=1
184                         if(o==32)
185                                 sep=i
186         end  
187                 elsif(o>=161 and o<=223)
188                         #Half-width katakana
189                         l+=500
190                         n=1
191                         sep=i
192                 else
193                         #Full-width character
194                         l+=1000
195                         n=2
196                         sep=i
197                 end
198                 if(l>wmax)
199                         #Automatic line break
200                         if(sep==-1 or i==j)
201                                 if(i==j)
202                                         i+=n
203                 end  
204                                 Cell(w,h,s[j,i-j],b,2,align,fill)
205                         else
206                                 Cell(w,h,s[j,sep-j],b,2,align,fill)
207                                 i=(s[sep]==' ') ? sep+1 : sep
208                         end
209                         sep=-1
210                         j=i
211                         l=0
212                         nl+=1
213                         if(border and nl==2)
214                                 b=b2
215         end  
216                 else
217                         i+=n
218                         if(o>=128)
219                                 sep=i
220                         end
221                 end
222         end
223         #Last chunk
224         if(border and not border.to_s.index('B').nil?)
225                 b+='B'
226         end  
227         Cell(w,h,s[j,i-j],b,2,align,fill)
228         @x=@lMargin
229   end
230
231   def Write(h,txt,link='')
232         if(@CurrentFont['type']=='Type0')
233                 SJISWrite(h,txt,link)
234         else
235                 super(h,txt,link)
236         end  
237   end
238
239   def SJISWrite(h,txt,link)
240         #SJIS version of Write()
241         cw=@CurrentFont['cw']
242         w=@w-@rMargin-@x
243         wmax=(w-2*@cMargin)*1000/@FontSize
244         s=txt.gsub("\r",'')
245         nb=s.length
246         sep=-1
247         i=0
248         j=0
249         l=0
250         nl=1
251         while(i<nb)
252                 #Get next character
253                 c=s[i]
254                 o=c
255                 if(o==10)
256                         #Explicit line break
257                         Cell(w,h,s[j,i-j],0,2,'',0,link)
258                         i+=1
259                         sep=-1
260                         j=i
261                         l=0
262                         if(nl==1)
263                                 #Go to left margin
264                                 @x=@lMargin
265                                 w=@w-@rMargin-@x
266                                 wmax=(w-2*@cMargin)*1000/@FontSize
267                         end
268                         nl+=1
269                         next
270                 end
271                 if(o<128)
272                         #ASCII
273                         l+=cw[c.chr]
274                         n=1
275                         if(o==32)
276                                 sep=i
277         end  
278                 elsif(o>=161 and o<=223)
279                         #Half-width katakana
280                         l+=500
281                         n=1
282                         sep=i
283                 else
284                         #Full-width character
285                         l+=1000
286                         n=2
287                         sep=i
288                 end
289                 if(l>wmax)
290                         #Automatic line break
291                         if(sep==-1 or i==j)
292                                 if(@x>@lMargin)
293                                         #Move to next line
294                                         @x=@lMargin
295                                         @y+=h
296                                         w=@w-@rMargin-@x
297                                         wmax=(w-2*@cMargin)*1000/@FontSize
298                                         i+=n
299                                         nl+=1
300                                         next
301                                 end
302                                 if(i==j)
303                                         i+=n
304                 end  
305                                 Cell(w,h,s[j,i-j],0,2,'',0,link)
306                         else
307                                 Cell(w,h,s[j,sep-j],0,2,'',0,link)
308                                 i=(s[sep]==' ') ? sep+1 : sep
309                         end
310                         sep=-1
311                         j=i
312                         l=0
313                         if(nl==1)
314                                 @x=@lMargin
315                                 w=@w-@rMargin-@x
316                                 wmax=(w-2*@cMargin)*1000/@FontSize
317                         end
318                         nl+=1
319                 else
320                         i+=n
321                         if(o>=128)
322                                 sep=i
323         end  
324                 end
325         end
326         #Last chunk
327         if(i!=j)
328                 Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link)
329         end  
330   end
331   
332 private
333
334   def putfonts()
335         nf=@n
336     @diffs.each do |diff|
337                 #Encodings
338                 newobj()
339                 out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')
340                 out('endobj')
341         end
342         # mqr=get_magic_quotes_runtime()
343         # set_magic_quotes_runtime(0)
344     @FontFiles.each_pair do |file, info|
345                 #Font file embedding
346                 newobj()
347                 @FontFiles[file]['n']=@n
348                 if(defined('FPDF_FONTPATH'))
349                         file=FPDF_FONTPATH+file
350         end  
351                 size=filesize(file)
352                 if(!size)
353                         Error('Font file not found')
354         end  
355                 out('<</Length '+size)
356                 if(file[-2]=='.z')
357                         out('/Filter /FlateDecode')
358         end  
359                 out('/Length1 '+info['length1'])
360                 unless info['length2'].nil?
361                         out('/Length2 '+info['length2']+' /Length3 0')
362         end  
363                 out('>>')
364                 f=fopen(file,'rb')
365                 putstream(fread(f,size))
366                 fclose(f)
367                 out('endobj')
368         end
369         # set_magic_quotes_runtime(mqr)
370     @fonts.each_pair do |k, font|
371                 #Font objects
372                 newobj()
373                 @fonts[k]['n']=@n
374                 out('<</Type /Font')
375                 if(font['type']=='Type0')
376                         putType0(font)
377                 else
378                         name=font['name']
379                         out('/BaseFont /'+name)
380                         if(font['type']=='core')
381                                 #Standard font
382                                 out('/Subtype /Type1')
383                                 if(name!='Symbol' and name!='ZapfDingbats')
384                                         out('/Encoding /WinAnsiEncoding')
385                                 end
386                         else
387                                 #Additional font
388                                 out('/Subtype /'+font['type'])
389                                 out('/FirstChar 32')
390                                 out('/LastChar 255')
391                                 out('/Widths '+(@n+1)+' 0 R')
392                                 out('/FontDescriptor '+(@n+2)+' 0 R')
393                                 if(font['enc'])
394                                         if !font['diff'].nil?
395                                                 out('/Encoding '+(nf+font['diff'])+' 0 R')
396                                         else
397                                                 out('/Encoding /WinAnsiEncoding')
398                 end  
399                                 end
400                         end
401                         out('>>')
402                         out('endobj')
403                         if(font['type']!='core')
404                                 #Widths
405                                 newobj()
406                                 cw=font['cw']
407                                 s='['
408           32.upto(255) do |i|
409                                         s+=cw[i.chr]+' '
410                 end  
411                                 out(s+']')
412                                 out('endobj')
413                                 #Descriptor
414                                 newobj()
415                                 s='<</Type /FontDescriptor /FontName /'+name
416                                 font['desc'].each_pair do |k, v|
417                                         s+=' /'+k+' '+v
418                 end  
419                                 file=font['file']
420                                 if(file)
421                                         s+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@FontFiles[file]['n']+' 0 R'
422                 end  
423                                 out(s+'>>')
424                                 out('endobj')
425                         end
426                 end
427         end
428   end
429
430   def putType0(font)
431         #Type0
432         out('/Subtype /Type0')
433         out('/BaseFont /'+font['name']+'-'+font['CMap'])
434         out('/Encoding /'+font['CMap'])
435         out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
436         out('>>')
437         out('endobj')
438         #CIDFont
439         newobj()
440         out('<</Type /Font')
441         out('/Subtype /CIDFontType0')
442         out('/BaseFont /'+font['name'])
443         out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')
444         out('/FontDescriptor '+(@n+1).to_s+' 0 R')
445         w='/W [1 ['
446                 font['cw'].keys.sort.each {|key|
447                   w+=font['cw'][key].to_s + " "
448 # ActionController::Base::logger.debug key.to_s
449 # ActionController::Base::logger.debug font['cw'][key].to_s
450                 }
451         out(w+'] 231 325 500 631 [500] 326 389 500]')
452         out('>>')
453         out('endobj')
454         #Font descriptor
455         newobj()
456         out('<</Type /FontDescriptor')
457         out('/FontName /'+font['name'])
458         out('/Flags 6')
459         out('/FontBBox [0 -200 1000 900]')
460         out('/ItalicAngle 0')
461         out('/Ascent 800')
462         out('/Descent -200')
463         out('/CapHeight 800')
464         out('/StemV 60')
465         out('>>')
466         out('endobj')
467   end
468 end