PageRenderTime 26ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/plugins/rfpdf/lib/rfpdf/korean.rb

https://github.com/andreacampi/redmine
Ruby | 436 lines | 398 code | 2 blank | 36 comment | 0 complexity | 61d6e8e3bc2a549b1adf12c8e5148019 MD5 | raw file
  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(@CurrentFont['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=@CurrentFont['cw']
  91. nb=s.length
  92. i=0
  93. while(i<nb)
  94. c=s[i]
  95. if(c<128)
  96. l+=cw[c.chr]
  97. i+=1
  98. else
  99. l+=1000
  100. i+=2
  101. end
  102. end
  103. return l*@FontSize/1000
  104. end
  105. def MultiCell(w,h,txt,border=0,align='L',fill=0)
  106. if(@CurrentFont['type']=='Type0')
  107. MBMultiCell(w,h,txt,border,align,fill)
  108. else
  109. super(w,h,txt,border,align,fill)
  110. end
  111. end
  112. def MBMultiCell(w,h,txt,border=0,align='L',fill=0)
  113. #Multi-byte version of MultiCell()
  114. cw=@CurrentFont['cw']
  115. if(w==0)
  116. w=@w-@rMargin-@x
  117. end
  118. wmax=(w-2*@cMargin)*1000/@FontSize
  119. s=txt.gsub("\r",'')
  120. nb=s.length
  121. if(nb>0 and s[nb-1]=="\n")
  122. nb-=1
  123. end
  124. b=0
  125. if(border)
  126. if(border==1)
  127. border='LTRB'
  128. b='LRT'
  129. b2='LR'
  130. else
  131. b2=''
  132. if(border.to_s.index('L').nil?)
  133. b2+='L'
  134. end
  135. if(border.to_s.index('R').nil?)
  136. b2+='R'
  137. end
  138. b=border.to_s.index('T').nil? ? b2+'T' : b2
  139. end
  140. end
  141. sep=-1
  142. i=0
  143. j=0
  144. l=0
  145. nl=1
  146. while(i<nb)
  147. #Get next character
  148. c=s[i]
  149. #Check if ASCII or MB
  150. ascii=(c<128)
  151. if(c=="\n")
  152. #Explicit line break
  153. Cell(w,h,s[j,i-j],b,2,align,fill)
  154. i+=1
  155. sep=-1
  156. j=i
  157. l=0
  158. nl+=1
  159. if(border and nl==2)
  160. b=b2
  161. end
  162. next
  163. end
  164. if(!ascii)
  165. sep=i
  166. ls=l
  167. elsif(c==' ')
  168. sep=i
  169. ls=l
  170. end
  171. l+=(ascii ? cw[c.chr] : 1000) || 0
  172. if(l>wmax)
  173. #Automatic line break
  174. if(sep==-1 or i==j)
  175. if(i==j)
  176. i+=ascii ? 1 : 2
  177. end
  178. Cell(w,h,s[j,i-j],b,2,align,fill)
  179. else
  180. Cell(w,h,s[j,sep-j],b,2,align,fill)
  181. i=(s[sep]==' ') ? sep+1 : sep
  182. end
  183. sep=-1
  184. j=i
  185. l=0
  186. nl+=1
  187. if(border and nl==2)
  188. b=b2
  189. end
  190. else
  191. i+=ascii ? 1 : 2
  192. end
  193. end
  194. #Last chunk
  195. if(border and not border.to_s.index('B').nil?)
  196. b+='B'
  197. end
  198. Cell(w,h,s[j,i-j],b,2,align,fill)
  199. @x=@lMargin
  200. end
  201. def Write(h,txt,link='')
  202. if(@CurrentFont['type']=='Type0')
  203. MBWrite(h,txt,link)
  204. else
  205. super(h,txt,link)
  206. end
  207. end
  208. def MBWrite(h,txt,link)
  209. #Multi-byte version of Write()
  210. cw=@CurrentFont['cw']
  211. w=@w-@rMargin-@x
  212. wmax=(w-2*@cMargin)*1000/@FontSize
  213. s=txt.gsub("\r",'')
  214. nb=s.length
  215. sep=-1
  216. i=0
  217. j=0
  218. l=0
  219. nl=1
  220. while(i<nb)
  221. #Get next character
  222. c=s[i]
  223. #Check if ASCII or MB
  224. ascii=(c<128)
  225. if(c=="\n")
  226. #Explicit line break
  227. Cell(w,h,s[j,i-j],0,2,'',0,link)
  228. i+=1
  229. sep=-1
  230. j=i
  231. l=0
  232. if(nl==1)
  233. @x=@lMargin
  234. w=@w-@rMargin-@x
  235. wmax=(w-2*@cMargin)*1000/@FontSize
  236. end
  237. nl+=1
  238. next
  239. end
  240. if(!ascii or c==' ')
  241. sep=i
  242. end
  243. l+=ascii ? cw[c.chr] : 1000
  244. if(l>wmax)
  245. #Automatic line break
  246. if(sep==-1 or i==j)
  247. if(@x>@lMargin)
  248. #Move to next line
  249. @x=@lMargin
  250. @y+=h
  251. w=@w-@rMargin-@x
  252. wmax=(w-2*@cMargin)*1000/@FontSize
  253. i+=1
  254. nl+=1
  255. next
  256. end
  257. if(i==j)
  258. i+=ascii ? 1 : 2
  259. end
  260. Cell(w,h,s[j,i-j],0,2,'',0,link)
  261. else
  262. Cell(w,h,s[j,sep-j],0,2,'',0,link)
  263. i=(s[sep]==' ') ? sep+1 : sep
  264. end
  265. sep=-1
  266. j=i
  267. l=0
  268. if(nl==1)
  269. @x=@lMargin
  270. w=@w-@rMargin-@x
  271. wmax=(w-2*@cMargin)*1000/@FontSize
  272. end
  273. nl+=1
  274. else
  275. i+=ascii ? 1 : 2
  276. end
  277. end
  278. #Last chunk
  279. if(i!=j)
  280. Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link)
  281. end
  282. end
  283. private
  284. def putfonts()
  285. nf=@n
  286. @diffs.each do |diff|
  287. #Encodings
  288. newobj()
  289. out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')
  290. out('endobj')
  291. end
  292. # mqr=get_magic_quotes_runtime()
  293. # set_magic_quotes_runtime(0)
  294. @FontFiles.each_pair do |file, info|
  295. #Font file embedding
  296. newobj()
  297. @FontFiles[file]['n']=@n
  298. if(defined('FPDF_FONTPATH'))
  299. file=FPDF_FONTPATH+file
  300. end
  301. size=filesize(file)
  302. if(!size)
  303. Error('Font file not found')
  304. end
  305. out('<</Length '+size)
  306. if(file[-2]=='.z')
  307. out('/Filter /FlateDecode')
  308. end
  309. out('/Length1 '+info['length1'])
  310. if(not info['length2'].nil?)
  311. out('/Length2 '+info['length2']+' /Length3 0')
  312. end
  313. out('>>')
  314. f=fopen(file,'rb')
  315. putstream(fread(f,size))
  316. fclose(f)
  317. out('endobj')
  318. end
  319. # set_magic_quotes_runtime(mqr)
  320. @fonts.each_pair do |k, font|
  321. #Font objects
  322. newobj()
  323. @fonts[k]['n']=@n
  324. out('<</Type /Font')
  325. if(font['type']=='Type0')
  326. putType0(font)
  327. else
  328. name=font['name']
  329. out('/BaseFont /'+name)
  330. if(font['type']=='core')
  331. #Standard font
  332. out('/Subtype /Type1')
  333. if(name!='Symbol' and name!='ZapfDingbats')
  334. out('/Encoding /WinAnsiEncoding')
  335. end
  336. else
  337. #Additional font
  338. out('/Subtype /'+font['type'])
  339. out('/FirstChar 32')
  340. out('/LastChar 255')
  341. out('/Widths '+(@n+1)+' 0 R')
  342. out('/FontDescriptor '+(@n+2)+' 0 R')
  343. if(font['enc'])
  344. if(not font['diff'].nil?)
  345. out('/Encoding '+(nf+font['diff'])+' 0 R')
  346. else
  347. out('/Encoding /WinAnsiEncoding')
  348. end
  349. end
  350. end
  351. out('>>')
  352. out('endobj')
  353. if(font['type']!='core')
  354. #Widths
  355. newobj()
  356. cw=font['cw']
  357. s='['
  358. 32.upto(255) do |i|
  359. s+=cw[i.chr]+' '
  360. end
  361. out(s+']')
  362. out('endobj')
  363. #Descriptor
  364. newobj()
  365. s='<</Type /FontDescriptor /FontName /'+name
  366. font['desc'].each_pair do |k, v|
  367. s+=' /'+k+' '+v
  368. end
  369. file=font['file']
  370. if(file)
  371. s+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@FontFiles[file]['n']+' 0 R'
  372. end
  373. out(s+'>>')
  374. out('endobj')
  375. end
  376. end
  377. end
  378. end
  379. def putType0(font)
  380. #Type0
  381. out('/Subtype /Type0')
  382. out('/BaseFont /'+font['name']+'-'+font['CMap'])
  383. out('/Encoding /'+font['CMap'])
  384. out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
  385. out('>>')
  386. out('endobj')
  387. #CIDFont
  388. newobj()
  389. out('<</Type /Font')
  390. out('/Subtype /CIDFontType0')
  391. out('/BaseFont /'+font['name'])
  392. out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')
  393. out('/FontDescriptor '+(@n+1).to_s+' 0 R')
  394. if(font['CMap']=='KSCms-UHC-HW-H')
  395. w='8094 8190 500'
  396. else
  397. w='1 ['
  398. font['cw'].keys.sort.each {|key|
  399. w+=font['cw'][key].to_s + " "
  400. # ActionController::Base::logger.debug key.to_s
  401. # ActionController::Base::logger.debug font['cw'][key].to_s
  402. }
  403. w +=']'
  404. end
  405. out('/W ['+w+']>>')
  406. out('endobj')
  407. #Font descriptor
  408. newobj()
  409. out('<</Type /FontDescriptor')
  410. out('/FontName /'+font['name'])
  411. out('/Flags 6')
  412. out('/FontBBox [0 -200 1000 900]')
  413. out('/ItalicAngle 0')
  414. out('/Ascent 800')
  415. out('/Descent -200')
  416. out('/CapHeight 800')
  417. out('/StemV 50')
  418. out('>>')
  419. out('endobj')
  420. end
  421. end