PageRenderTime 66ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/plugins/rfpdf/lib/fpdf/korean.rb

https://bitbucket.org/eimajenthat/redmine
Ruby | 449 lines | 411 code | 2 blank | 36 comment | 0 complexity | 96f8287f7ca5249d679e506be4d69c81 MD5 | raw file
Possible License(s): GPL-2.0
  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 korean.php
  25. #
  26. # Korean PDF support.
  27. #
  28. # Usage is as follows:
  29. #
  30. # require 'fpdf'
  31. # require 'chinese'
  32. # pdf = FPDF.new
  33. # pdf.extend(PDF_Korean)
  34. #
  35. # This allows it to be combined with other extensions, such as the bookmark
  36. # module.
  37. module PDF_Korean
  38. UHC_widths={' ' => 333, '!' => 416, '"' => 416, '#' => 833, '$' => 625, '%' => 916, '&' => 833, '\'' => 250,
  39. '(' => 500, ')' => 500, '*' => 500, '+' => 833, ',' => 291, '-' => 833, '.' => 291, '/' => 375, '0' => 625, '1' => 625,
  40. '2' => 625, '3' => 625, '4' => 625, '5' => 625, '6' => 625, '7' => 625, '8' => 625, '9' => 625, ':' => 333, ';' => 333,
  41. '<' => 833, '=' => 833, '>' => 916, '?' => 500, '@' => 1000, 'A' => 791, 'B' => 708, 'C' => 708, 'D' => 750, 'E' => 708,
  42. 'F' => 666, 'G' => 750, 'H' => 791, 'I' => 375, 'J' => 500, 'K' => 791, 'L' => 666, 'M' => 916, 'N' => 791, 'O' => 750,
  43. 'P' => 666, 'Q' => 750, 'R' => 708, 'S' => 666, 'T' => 791, 'U' => 791, 'V' => 750, 'W' => 1000, 'X' => 708, 'Y' => 708,
  44. 'Z' => 666, '[' => 500, '\\' => 375, ']' => 500, '^' => 500, '_' => 500, '`' => 333, 'a' => 541, 'b' => 583, 'c' => 541,
  45. 'd' => 583, 'e' => 583, 'f' => 375, 'g' => 583, 'h' => 583, 'i' => 291, 'j' => 333, 'k' => 583, 'l' => 291, 'm' => 875,
  46. 'n' => 583, 'o' => 583, 'p' => 583, 'q' => 583, 'r' => 458, 's' => 541, 't' => 375, 'u' => 583, 'v' => 583, 'w' => 833,
  47. 'x' => 625, 'y' => 625, 'z' => 500, '{' => 583, '|' => 583, '}' => 583, '~' => 750}
  48. def AddCIDFont(family,style,name,cw,cMap,registry)
  49. fontkey=family.downcase+style.upcase
  50. unless @fonts[fontkey].nil?
  51. Error("Font already added: family style")
  52. end
  53. i=@fonts.length+1
  54. name=name.gsub(' ','')
  55. @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw,
  56. 'CMap'=>cMap,'registry'=>registry}
  57. end
  58. def AddCIDFonts(family,name,cw,cMap,registry)
  59. AddCIDFont(family,'',name,cw,cMap,registry)
  60. AddCIDFont(family,'B',name+',Bold',cw,cMap,registry)
  61. AddCIDFont(family,'I',name+',Italic',cw,cMap,registry)
  62. AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)
  63. end
  64. def AddUHCFont(family='UHC',name='HYSMyeongJoStd-Medium-Acro')
  65. #Add UHC font with proportional Latin
  66. cw=UHC_widths
  67. cMap='KSCms-UHC-H'
  68. registry={'ordering'=>'Korea1','supplement'=>1}
  69. AddCIDFonts(family,name,cw,cMap,registry)
  70. end
  71. def AddUHChwFont(family='UHC-hw',name='HYSMyeongJoStd-Medium-Acro')
  72. #Add UHC font with half-witdh Latin
  73. 32.upto(126) do |i|
  74. cw[i.chr]=500
  75. end
  76. cMap='KSCms-UHC-HW-H'
  77. registry={'ordering'=>'Korea1','supplement'=>1}
  78. AddCIDFonts(family,name,cw,cMap,registry)
  79. end
  80. def GetStringWidth(s)
  81. if(@current_font['type']=='Type0')
  82. return GetMBStringWidth(s)
  83. else
  84. return super(s)
  85. end
  86. end
  87. def GetMBStringWidth(s)
  88. #Multi-byte version of GetStringWidth()
  89. l=0
  90. cw=@current_font['cw']
  91. nb=s.length
  92. i=0
  93. while(i<nb)
  94. c = s[i].is_a?(String) ? s[i].ord : s[i]
  95. if(c<128)
  96. l+=cw[c.chr] if cw[c.chr]
  97. i+=1
  98. else
  99. l+=1000
  100. i+=2
  101. end
  102. end
  103. return l*@font_size/1000
  104. end
  105. def MultiCell(w,h,txt,border=0,align='L',fill=0,ln=1)
  106. if(@current_font['type']=='Type0')
  107. MBMultiCell(w,h,txt,border,align,fill,ln)
  108. else
  109. super(w,h,txt,border,align,fill,ln)
  110. end
  111. end
  112. def MBMultiCell(w,h,txt,border=0,align='L',fill=0,ln=1)
  113. # save current position
  114. prevx = @x;
  115. prevy = @y;
  116. #Multi-byte version of MultiCell()
  117. cw=@current_font['cw']
  118. if(w==0)
  119. w=@w-@r_margin-@x
  120. end
  121. wmax=(w-2*@c_margin)*1000/@font_size
  122. s=txt.gsub("\r",'')
  123. nb=s.length
  124. if(nb>0 and s[nb-1]=="\n")
  125. nb-=1
  126. end
  127. b=0
  128. if(border)
  129. if(border==1)
  130. border='LTRB'
  131. b='LRT'
  132. b2='LR'
  133. else
  134. b2=''
  135. b2='L' unless border.to_s.index('L').nil?
  136. b2=b2+'R' unless border.to_s.index('R').nil?
  137. b=(border.to_s.index('T')) ? (b2+'T') : b2
  138. end
  139. end
  140. sep=-1
  141. i=0
  142. j=0
  143. l=0
  144. nl=1
  145. while(i<nb)
  146. #Get next character
  147. c = s[i].is_a?(String) ? s[i].ord : s[i]
  148. #Check if ASCII or MB
  149. ascii=(c<128)
  150. if(c.chr=="\n")
  151. #Explicit line break
  152. Cell(w,h,s[j,i-j],b,2,align,fill)
  153. i+=1
  154. sep=-1
  155. j=i
  156. l=0
  157. nl+=1
  158. if(border and nl==2)
  159. b=b2
  160. end
  161. next
  162. end
  163. if(!ascii)
  164. sep=i
  165. ls=l
  166. elsif(c.chr==' ')
  167. sep=i
  168. ls=l
  169. end
  170. l+=(ascii ? cw[c.chr] : 1000) || 0
  171. if(l>wmax)
  172. #Automatic line break
  173. if(sep==-1 or i==j)
  174. if(i==j)
  175. i+=ascii ? 1 : 2
  176. end
  177. Cell(w,h,s[j,i-j],b,2,align,fill)
  178. else
  179. Cell(w,h,s[j,sep-j],b,2,align,fill)
  180. i=(s[sep].chr==' ') ? sep+1 : sep
  181. end
  182. sep=-1
  183. j=i
  184. l=0
  185. nl+=1
  186. if(border and nl==2)
  187. b=b2
  188. end
  189. else
  190. i+=ascii ? 1 : 2
  191. end
  192. end
  193. #Last chunk
  194. if(border and not border.to_s.index('B').nil?)
  195. b+='B'
  196. end
  197. Cell(w,h,s[j,i-j],b,2,align,fill)
  198. # move cursor to specified position
  199. if (ln == 1)
  200. # go to the beginning of the next line
  201. @x=@l_margin
  202. elsif (ln == 0)
  203. # go to the top-right of the cell
  204. @y = prevy;
  205. @x = prevx + w;
  206. elsif (ln == 2)
  207. # go to the bottom-left of the cell
  208. @x = prevx;
  209. end
  210. end
  211. def Write(h,txt,link='',fill=0)
  212. if(@current_font['type']=='Type0')
  213. MBWrite(h,txt,link,fill)
  214. else
  215. super(h,txt,link,fill)
  216. end
  217. end
  218. def MBWrite(h,txt,link,fill=0)
  219. #Multi-byte version of Write()
  220. cw=@current_font['cw']
  221. w=@w-@r_margin-@x
  222. wmax=(w-2*@c_margin)*1000/@font_size
  223. s=txt.gsub("\r",'')
  224. nb=s.length
  225. sep=-1
  226. i=0
  227. j=0
  228. l=0
  229. nl=1
  230. while(i<nb)
  231. #Get next character
  232. c = s[i].is_a?(String) ? s[i].ord : s[i]
  233. #Check if ASCII or MB
  234. ascii=(c<128)
  235. if(c.chr=="\n")
  236. #Explicit line break
  237. Cell(w,h,s[j,i-j],0,2,'',fill,link)
  238. i+=1
  239. sep=-1
  240. j=i
  241. l=0
  242. if(nl==1)
  243. @x=@l_margin
  244. w=@w-@r_margin-@x
  245. wmax=(w-2*@c_margin)*1000/@font_size
  246. end
  247. nl+=1
  248. next
  249. end
  250. if(!ascii or c.chr==' ')
  251. sep=i
  252. end
  253. l+=(ascii ? cw[c.chr] : 1000) || 0
  254. if(l>wmax)
  255. #Automatic line break
  256. if(sep==-1 or i==j)
  257. if(@x>@l_margin)
  258. #Move to next line
  259. @x=@l_margin
  260. @y+=h
  261. w=@w-@r_margin-@x
  262. wmax=(w-2*@c_margin)*1000/@font_size
  263. i+=1
  264. nl+=1
  265. next
  266. end
  267. if(i==j)
  268. i+=ascii ? 1 : 2
  269. end
  270. Cell(w,h,s[j,i-j],0,2,'',fill,link)
  271. else
  272. Cell(w,h,s[j,sep-j],0,2,'',fill,link)
  273. i=(s[sep].chr==' ') ? sep+1 : sep
  274. end
  275. sep=-1
  276. j=i
  277. l=0
  278. if(nl==1)
  279. @x=@l_margin
  280. w=@w-@r_margin-@x
  281. wmax=(w-2*@c_margin)*1000/@font_size
  282. end
  283. nl+=1
  284. else
  285. i+=ascii ? 1 : 2
  286. end
  287. end
  288. #Last chunk
  289. if(i!=j)
  290. Cell(l*@font_size/1000.0,h,s[j,i-j],0,0,'',fill,link)
  291. end
  292. end
  293. private
  294. def putfonts()
  295. nf=@n
  296. @diffs.each do |diff|
  297. #Encodings
  298. newobj()
  299. out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')
  300. out('endobj')
  301. end
  302. # mqr=get_magic_quotes_runtime()
  303. # set_magic_quotes_runtime(0)
  304. @font_files.each_pair do |file, info|
  305. #Font file embedding
  306. newobj()
  307. @font_files[file]['n']=@n
  308. if(defined('FPDF_FONTPATH'))
  309. file=FPDF_FONTPATH+file
  310. end
  311. size=filesize(file)
  312. if(!size)
  313. Error('Font file not found')
  314. end
  315. out('<</Length '+size)
  316. if(file[-2]=='.z')
  317. out('/Filter /FlateDecode')
  318. end
  319. out('/Length1 '+info['length1'])
  320. if(not info['length2'].nil?)
  321. out('/Length2 '+info['length2']+' /Length3 0')
  322. end
  323. out('>>')
  324. f=fopen(file,'rb')
  325. putstream(fread(f,size))
  326. fclose(f)
  327. out('endobj')
  328. end
  329. # set_magic_quotes_runtime(mqr)
  330. @fonts.each_pair do |k, font|
  331. #Font objects
  332. newobj()
  333. @fonts[k]['n']=@n
  334. out('<</Type /Font')
  335. if(font['type']=='Type0')
  336. putType0(font)
  337. else
  338. name=font['name']
  339. out('/BaseFont /'+name)
  340. if(font['type']=='core')
  341. #Standard font
  342. out('/Subtype /Type1')
  343. if(name!='Symbol' and name!='ZapfDingbats')
  344. out('/Encoding /WinAnsiEncoding')
  345. end
  346. else
  347. #Additional font
  348. out('/Subtype /'+font['type'])
  349. out('/FirstChar 32')
  350. out('/LastChar 255')
  351. out('/Widths '+(@n+1)+' 0 R')
  352. out('/FontDescriptor '+(@n+2)+' 0 R')
  353. if(font['enc'])
  354. if(not font['diff'].nil?)
  355. out('/Encoding '+(nf+font['diff'])+' 0 R')
  356. else
  357. out('/Encoding /WinAnsiEncoding')
  358. end
  359. end
  360. end
  361. out('>>')
  362. out('endobj')
  363. if(font['type']!='core')
  364. #Widths
  365. newobj()
  366. cw=font['cw']
  367. s='['
  368. 32.upto(255) do |i|
  369. s+=cw[i.chr]+' '
  370. end
  371. out(s+']')
  372. out('endobj')
  373. #Descriptor
  374. newobj()
  375. s='<</Type /FontDescriptor /FontName /'+name
  376. font['desc'].each_pair do |k, v|
  377. s+=' /'+k+' '+v
  378. end
  379. file=font['file']
  380. if(file)
  381. s+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@font_files[file]['n']+' 0 R'
  382. end
  383. out(s+'>>')
  384. out('endobj')
  385. end
  386. end
  387. end
  388. end
  389. def putType0(font)
  390. #Type0
  391. out('/Subtype /Type0')
  392. out('/BaseFont /'+font['name']+'-'+font['CMap'])
  393. out('/Encoding /'+font['CMap'])
  394. out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
  395. out('>>')
  396. out('endobj')
  397. #CIDFont
  398. newobj()
  399. out('<</Type /Font')
  400. out('/Subtype /CIDFontType0')
  401. out('/BaseFont /'+font['name'])
  402. out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')
  403. out('/FontDescriptor '+(@n+1).to_s+' 0 R')
  404. if(font['CMap']=='KSCms-UHC-HW-H')
  405. w='8094 8190 500'
  406. else
  407. w='1 ['
  408. font['cw'].keys.sort.each {|key|
  409. w+=font['cw'][key].to_s + " "
  410. # ActionController::Base::logger.debug key.to_s
  411. # ActionController::Base::logger.debug font['cw'][key].to_s
  412. }
  413. w +=']'
  414. end
  415. out('/W ['+w+']>>')
  416. out('endobj')
  417. #Font descriptor
  418. newobj()
  419. out('<</Type /FontDescriptor')
  420. out('/FontName /'+font['name'])
  421. out('/Flags 6')
  422. out('/FontBBox [0 -200 1000 900]')
  423. out('/ItalicAngle 0')
  424. out('/Ascent 800')
  425. out('/Descent -200')
  426. out('/CapHeight 800')
  427. out('/StemV 50')
  428. out('>>')
  429. out('endobj')
  430. end
  431. end