Chris@909: # Copyright (c) 2006 4ssoM LLC Chris@909: # 1.12 contributed by Ed Moss. Chris@909: # Chris@909: # The MIT License Chris@909: # Chris@909: # Permission is hereby granted, free of charge, to any person obtaining a copy Chris@909: # of this software and associated documentation files (the "Software"), to deal Chris@909: # in the Software without restriction, including without limitation the rights Chris@909: # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell Chris@909: # copies of the Software, and to permit persons to whom the Software is Chris@909: # furnished to do so, subject to the following conditions: Chris@909: # Chris@909: # The above copyright notice and this permission notice shall be included in Chris@909: # all copies or substantial portions of the Software. Chris@909: # Chris@909: # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR Chris@909: # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, Chris@909: # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE Chris@909: # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER Chris@909: # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, Chris@909: # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN Chris@909: # THE SOFTWARE. Chris@909: # Chris@909: # This is direct port of chinese.php Chris@909: # Chris@909: # Chinese PDF support. Chris@909: # Chris@909: # Usage is as follows: Chris@909: # Chris@909: # require 'fpdf' Chris@909: # require 'chinese' Chris@909: # pdf = FPDF.new Chris@909: # pdf.extend(PDF_Chinese) Chris@909: # Chris@909: # This allows it to be combined with other extensions, such as the bookmark Chris@909: # module. Chris@909: Chris@909: module PDF_Chinese Chris@909: Chris@909: Big5_widths={' '=>250,'!'=>250,'"'=>408,'#'=>668,'$'=>490,'%'=>875,'&'=>698,'\''=>250, Chris@909: '('=>240,')'=>240,'*'=>417,'+'=>667,','=>250,'-'=>313,'.'=>250,'/'=>520,'0'=>500,'1'=>500, Chris@909: '2'=>500,'3'=>500,'4'=>500,'5'=>500,'6'=>500,'7'=>500,'8'=>500,'9'=>500,':'=>250,';'=>250, Chris@909: '<'=>667,'='=>667,'>'=>667,'?'=>396,'@'=>921,'A'=>677,'B'=>615,'C'=>719,'D'=>760,'E'=>625, Chris@909: 'F'=>552,'G'=>771,'H'=>802,'I'=>354,'J'=>354,'K'=>781,'L'=>604,'M'=>927,'N'=>750,'O'=>823, Chris@909: 'P'=>563,'Q'=>823,'R'=>729,'S'=>542,'T'=>698,'U'=>771,'V'=>729,'W'=>948,'X'=>771,'Y'=>677, Chris@909: 'Z'=>635,'['=>344,'\\'=>520,']'=>344,'^'=>469,'_'=>500,'`'=>250,'a'=>469,'b'=>521,'c'=>427, Chris@909: 'd'=>521,'e'=>438,'f'=>271,'g'=>469,'h'=>531,'i'=>250,'j'=>250,'k'=>458,'l'=>240,'m'=>802, Chris@909: 'n'=>531,'o'=>500,'p'=>521,'q'=>521,'r'=>365,'s'=>333,'t'=>292,'u'=>521,'v'=>458,'w'=>677, Chris@909: 'x'=>479,'y'=>458,'z'=>427,'{'=>480,'|'=>496,'}'=>480,'~'=>667} Chris@909: Chris@909: GB_widths={' '=>207,'!'=>270,'"'=>342,'#'=>467,'$'=>462,'%'=>797,'&'=>710,'\''=>239, Chris@909: '('=>374,')'=>374,'*'=>423,'+'=>605,','=>238,'-'=>375,'.'=>238,'/'=>334,'0'=>462,'1'=>462, Chris@909: '2'=>462,'3'=>462,'4'=>462,'5'=>462,'6'=>462,'7'=>462,'8'=>462,'9'=>462,':'=>238,';'=>238, Chris@909: '<'=>605,'='=>605,'>'=>605,'?'=>344,'@'=>748,'A'=>684,'B'=>560,'C'=>695,'D'=>739,'E'=>563, Chris@909: 'F'=>511,'G'=>729,'H'=>793,'I'=>318,'J'=>312,'K'=>666,'L'=>526,'M'=>896,'N'=>758,'O'=>772, Chris@909: 'P'=>544,'Q'=>772,'R'=>628,'S'=>465,'T'=>607,'U'=>753,'V'=>711,'W'=>972,'X'=>647,'Y'=>620, Chris@909: 'Z'=>607,'['=>374,'\\'=>333,']'=>374,'^'=>606,'_'=>500,'`'=>239,'a'=>417,'b'=>503,'c'=>427, Chris@909: 'd'=>529,'e'=>415,'f'=>264,'g'=>444,'h'=>518,'i'=>241,'j'=>230,'k'=>495,'l'=>228,'m'=>793, Chris@909: 'n'=>527,'o'=>524,'p'=>524,'q'=>504,'r'=>338,'s'=>336,'t'=>277,'u'=>517,'v'=>450,'w'=>652, Chris@909: 'x'=>466,'y'=>452,'z'=>407,'{'=>370,'|'=>258,'}'=>370,'~'=>605} Chris@909: Chris@909: def AddCIDFont(family,style,name,cw,cMap,registry) Chris@909: #ActionController::Base::logger.debug registry.to_a.join(":").to_s Chris@909: fontkey=family.downcase+style.upcase Chris@909: unless @fonts[fontkey].nil? Chris@909: Error("Font already added: family style") Chris@909: end Chris@909: i=@fonts.length+1 Chris@909: name=name.gsub(' ','') Chris@909: @fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw, 'CMap'=>cMap,'registry'=>registry} Chris@909: end Chris@909: Chris@909: def AddCIDFonts(family,name,cw,cMap,registry) Chris@909: AddCIDFont(family,'',name,cw,cMap,registry) Chris@909: AddCIDFont(family,'B',name+',Bold',cw,cMap,registry) Chris@909: AddCIDFont(family,'I',name+',Italic',cw,cMap,registry) Chris@909: AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry) Chris@909: end Chris@909: Chris@909: def AddBig5Font(family='Big5',name='MSungStd-Light-Acro') Chris@909: #Add Big5 font with proportional Latin Chris@909: cw=Big5_widths Chris@909: cMap='ETenms-B5-H' Chris@909: registry={'ordering'=>'CNS1','supplement'=>0} Chris@909: #ActionController::Base::logger.debug registry.to_a.join(":").to_s Chris@909: AddCIDFonts(family,name,cw,cMap,registry) Chris@909: end Chris@909: Chris@909: def AddBig5hwFont(family='Big5-hw',name='MSungStd-Light-Acro') Chris@909: #Add Big5 font with half-witdh Latin Chris@909: cw = {} Chris@909: 32.upto(126) do |i| Chris@909: cw[i.chr]=500 Chris@909: end Chris@909: cMap='ETen-B5-H' Chris@909: registry={'ordering'=>'CNS1','supplement'=>0} Chris@909: AddCIDFonts(family,name,cw,cMap,registry) Chris@909: end Chris@909: Chris@909: def AddGBFont(family='GB',name='STSongStd-Light-Acro') Chris@909: #Add GB font with proportional Latin Chris@909: cw=GB_widths Chris@909: cMap='GBKp-EUC-H' Chris@909: registry={'ordering'=>'GB1','supplement'=>2} Chris@909: AddCIDFonts(family,name,cw,cMap,registry) Chris@909: end Chris@909: Chris@909: def AddGBhwFont(family='GB-hw',name='STSongStd-Light-Acro') Chris@909: #Add GB font with half-width Latin Chris@909: 32.upto(126) do |i| Chris@909: cw[i.chr]=500 Chris@909: end Chris@909: cMap='GBK-EUC-H' Chris@909: registry={'ordering'=>'GB1','supplement'=>2} Chris@909: AddCIDFonts(family,name,cw,cMap,registry) Chris@909: end Chris@909: Chris@909: def GetStringWidth(s) Chris@909: if(@current_font['type']=='Type0') Chris@909: return GetMBStringWidth(s) Chris@909: else Chris@909: return super(s) Chris@909: end Chris@909: end Chris@909: Chris@909: def GetMBStringWidth(s) Chris@909: #Multi-byte version of GetStringWidth() Chris@909: l=0 Chris@909: cw=@current_font['cw'] Chris@909: nb=s.length Chris@909: i=0 Chris@909: while(i0 and s[nb-1]=="\n") Chris@909: nb-=1 Chris@909: end Chris@909: b=0 Chris@909: if(border) Chris@909: if(border==1) Chris@909: border='LTRB' Chris@909: b='LRT' Chris@909: b2='LR' Chris@909: else Chris@909: b2='' Chris@909: b2='L' unless border.to_s.index('L').nil? Chris@909: b2=b2+'R' unless border.to_s.index('R').nil? Chris@909: b=(border.to_s.index('T')) ? (b2+'T') : b2 Chris@909: end Chris@909: end Chris@909: sep=-1 Chris@909: i=0 Chris@909: j=0 Chris@909: l=0 Chris@909: nl=1 Chris@909: while(iwmax) Chris@909: #Automatic line break Chris@909: if(sep==-1 or i==j) Chris@909: if(i==j) Chris@909: i+=ascii ? 1 : 2 Chris@909: end Chris@909: Cell(w,h,s[j,i-j],b,2,align,fill) Chris@909: else Chris@909: Cell(w,h,s[j,sep-j],b,2,align,fill) Chris@909: i=(s[sep].chr==' ') ? sep+1 : sep Chris@909: end Chris@909: sep=-1 Chris@909: j=i Chris@909: l=0 Chris@909: nl+=1 Chris@909: if(border and nl==2) Chris@909: b=b2 Chris@909: end Chris@909: else Chris@909: i+=ascii ? 1 : 2 Chris@909: end Chris@909: end Chris@909: #Last chunk Chris@909: if(border and not border.to_s.index('B').nil?) Chris@909: b+='B' Chris@909: end Chris@909: Cell(w,h,s[j,i-j],b,2,align,fill) Chris@909: Chris@909: # move cursor to specified position Chris@909: if (ln == 1) Chris@909: # go to the beginning of the next line Chris@909: @x=@l_margin Chris@909: elsif (ln == 0) Chris@909: # go to the top-right of the cell Chris@909: @y = prevy; Chris@909: @x = prevx + w; Chris@909: elsif (ln == 2) Chris@909: # go to the bottom-left of the cell Chris@909: @x = prevx; Chris@909: end Chris@909: end Chris@909: Chris@909: def Write(h,txt,link='',fill=0) Chris@909: if(@current_font['type']=='Type0') Chris@909: MBWrite(h,txt,link,fill) Chris@909: else Chris@909: super(h,txt,link,fill) Chris@909: end Chris@909: end Chris@909: Chris@909: def MBWrite(h,txt,link,fill=0) Chris@909: #Multi-byte version of Write() Chris@909: cw=@current_font['cw'] Chris@909: w=@w-@r_margin-@x Chris@909: wmax=(w-2*@c_margin)*1000/@font_size Chris@909: s=txt.gsub("\r",'') Chris@909: nb=s.length Chris@909: sep=-1 Chris@909: i=0 Chris@909: j=0 Chris@909: l=0 Chris@909: nl=1 Chris@909: while(iwmax) Chris@909: #Automatic line break Chris@909: if(sep==-1 or i==j) Chris@909: if(@x>@l_margin) Chris@909: #Move to next line Chris@909: @x=@l_margin Chris@909: @y+=h Chris@909: w=@w-@r_margin-@x Chris@909: wmax=(w-2*@c_margin)*1000/@font_size Chris@909: i+=1 Chris@909: nl+=1 Chris@909: next Chris@909: end Chris@909: if(i==j) Chris@909: i+=ascii ? 1 : 2 Chris@909: end Chris@909: Cell(w,h,s[j,i-j],0,2,'',fill,link) Chris@909: else Chris@909: Cell(w,h,s[j,sep-j],0,2,'',fill,link) Chris@909: i=(s[sep].chr==' ') ? sep+1 : sep Chris@909: end Chris@909: sep=-1 Chris@909: j=i Chris@909: l=0 Chris@909: if(nl==1) Chris@909: @x=@l_margin Chris@909: w=@w-@r_margin-@x Chris@909: wmax=(w-2*@c_margin)*1000/@font_size Chris@909: end Chris@909: nl+=1 Chris@909: else Chris@909: i+=ascii ? 1 : 2 Chris@909: end Chris@909: end Chris@909: #Last chunk Chris@909: if(i!=j) Chris@909: Cell(l*@font_size/1000.0,h,s[j,i-j],0,0,'',fill,link) Chris@909: end Chris@909: end Chris@909: Chris@909: private Chris@909: Chris@909: def putfonts() Chris@909: nf=@n Chris@909: @diffs.each do |diff| Chris@909: #Encodings Chris@909: newobj() Chris@909: out('<>') Chris@909: out('endobj') Chris@909: end Chris@909: # mqr=get_magic_quotes_runtime() Chris@909: # set_magic_quotes_runtime(0) Chris@909: @font_files.each_pair do |file, info| Chris@909: #Font file embedding Chris@909: newobj() Chris@909: @font_files[file]['n']=@n Chris@909: if(defined('FPDF_FONTPATH')) Chris@909: file=FPDF_FONTPATH+file Chris@909: end Chris@909: size=filesize(file) Chris@909: if(!size) Chris@909: Error('Font file not found') Chris@909: end Chris@909: out('<>') Chris@909: f=fopen(file,'rb') Chris@909: putstream(fread(f,size)) Chris@909: fclose(f) Chris@909: out('endobj') Chris@909: end Chris@909: # Chris@909: # set_magic_quotes_runtime(mqr) Chris@909: # Chris@909: @fonts.each_pair do |k, font| Chris@909: #Font objects Chris@909: newobj() Chris@909: @fonts[k]['n']=@n Chris@909: out('<>') Chris@909: out('endobj') Chris@909: if(font['type']!='core') Chris@909: #Widths Chris@909: newobj() Chris@909: cw=font['cw'] Chris@909: s='[' Chris@909: 32.upto(255) do |i| Chris@909: s+=cw[i.chr]+' ' Chris@909: end Chris@909: out(s+']') Chris@909: out('endobj') Chris@909: #Descriptor Chris@909: newobj() Chris@909: s='<>') Chris@909: out('endobj') Chris@909: end Chris@909: end Chris@909: end Chris@909: end Chris@909: Chris@909: def putType0(font) Chris@909: #Type0 Chris@909: out('/Subtype /Type0') Chris@909: out('/BaseFont /'+font['name']+'-'+font['CMap']) Chris@909: out('/Encoding /'+font['CMap']) Chris@909: out('/DescendantFonts ['+(@n+1).to_s+' 0 R]') Chris@909: out('>>') Chris@909: out('endobj') Chris@909: #CIDFont Chris@909: newobj() Chris@909: out('<>') Chris@909: out('/FontDescriptor '+(@n+1).to_s+' 0 R') Chris@909: if(font['CMap']=='ETen-B5-H') Chris@909: w='13648 13742 500' Chris@909: elsif(font['CMap']=='GBK-EUC-H') Chris@909: w='814 907 500 7716 [500]' Chris@909: else Chris@909: # ActionController::Base::logger.debug font['cw'].keys.sort.join(' ').to_s Chris@909: # ActionController::Base::logger.debug font['cw'].values.join(' ').to_s Chris@909: w='1 [' Chris@909: font['cw'].keys.sort.each {|key| Chris@909: w+=font['cw'][key].to_s + " " Chris@909: # ActionController::Base::logger.debug key.to_s Chris@909: # ActionController::Base::logger.debug font['cw'][key].to_s Chris@909: } Chris@909: w +=']' Chris@909: end Chris@909: out('/W ['+w+']>>') Chris@909: out('endobj') Chris@909: #Font descriptor Chris@909: newobj() Chris@909: out('<>') Chris@909: out('endobj') Chris@909: end Chris@909: end