missing rfpdf in the repository...

git-svn-id: http://redmine.rubyforge.org/svn/trunk@49 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang 2006-11-21 18:34:04 +00:00
parent f7df1b7d55
commit 5e9e01bf7f
16 changed files with 5544 additions and 0 deletions

13
redmine/vendor/plugins/rfpdf/CHANGELOG vendored Normal file
View File

@ -0,0 +1,13 @@
1.00 Added view template functionality
1.10 Added Chinese support
1.11 Added Japanese support
1.12 Added Korean support
1.13 Updated to fpdf.rb 1.53d.
Added makefont and fpdf_eps.
Handle \n at the beginning of a string in MultiCell.
Tried to fix clipping issue in MultiCell - still needs some work.
1.14 2006-09-26
* Added support for @options_for_rfpdf hash for configuration:
* Added :filename option in this hash
If you're using the same settings for @options_for_rfpdf often, you might want to
put your assignment in a before_filter (perhaps overriding :filename, etc in your actions).

View File

@ -0,0 +1,20 @@
Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOa AND
NONINFRINGEMENT. IN NO EVENT SaALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

99
redmine/vendor/plugins/rfpdf/README vendored Normal file
View File

@ -0,0 +1,99 @@
= RFPDF Template Plugin
A template plugin allowing the inclusion of ERB-enabled RFPDF template files.
== Example .rb method Usage
In the controller, something like:
def mypdf
pdf = FPDF.new()
#
# Chinese
#
pdf.extend(PDF_Chinese)
pdf.AddPage
pdf.AddBig5Font
pdf.SetFont('Big5','',18)
pdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %')
icBig5 = Iconv.new('Big5', 'UTF-8')
pdf.Write(15, icBig5.iconv("宋体 should be working"))
send_data pdf.Output, :filename => "something.pdf", :type => "application/pdf"
end
== Example .rfdf Usage
In the controller, something like:
def mypdf
@options_for_rfpdf ||= {}
@options_for_rfpdf[:file_name] = "nice_looking.pdf"
end
In the layout (make sure this is the only item in the layout):
<%= @content_for_layout %>
In the view (mypdf.rfpdf):
<%
pdf = FPDF.new()
#
# Chinese
#
pdf.extend(PDF_Chinese)
pdf.AddPage
pdf.AddBig5Font
pdf.SetFont('Big5','',18)
pdf.Write(5, '²{®É®ð·Å 18 C Àã«× 83 %')
icBig5 = Iconv.new('Big5', 'UTF-8')
pdf.Write(15, icBig5.iconv("宋体 should be working"))
#
# Japanese
#
pdf.extend(PDF_Japanese)
pdf.AddSJISFont();
pdf.AddPage();
pdf.SetFont('SJIS','',18);
pdf.Write(5,'9ÉñåéÇÃåˆäJÉeÉXÉgÇåoǃPHP 3.0ÇÕ1998îN6åéÇ…åˆéÆÇ…ÉäÉäÅ[ÉXÇ≥ÇÍÇǵÇΩÅB');
icSJIS = Iconv.new('SJIS', 'UTF-8')
pdf.Write(15, icSJIS.iconv("これはテキストである should be working"))
#
# Korean
#
pdf.extend(PDF_Korean)
pdf.AddUHCFont();
pdf.AddPage();
pdf.SetFont('UHC','',18);
pdf.Write(5,'PHP 3.0Àº 1998³â 6¿ù¿¡ °ø½ÄÀûÀ¸·Î ¸±¸®ÁîµÇ¾ú´Ù. °ø°³ÀûÀÎ Å×½ºÆ® ÀÌÈľà 9°³¿ù¸¸À̾ú´Ù.');
icUHC = Iconv.new('UHC', 'UTF-8')
pdf.Write(15, icUHC.iconv("이것은 원본 이다"))
#
# English
#
pdf.AddPage();
pdf.SetFont('Arial', '', 10)
pdf.Write(5, "should be working")
%>
<%= pdf.Output() %>
== Configuring
You can configure Rfpdf by using an @options_for_rfpdf hash in your controllers.
Here are a few options:
:filename (default: action_name.pdf)
Filename of PDF to generate
Note: If you're using the same settings for @options_for_rfpdf often, you might want to
put your assignment in a before_filter (perhaps overriding :filename, etc in your actions).
== Problems
Layouts and partials are currently not supported; just need
to wrap the PDF generation differently.

3
redmine/vendor/plugins/rfpdf/init.rb vendored Normal file
View File

@ -0,0 +1,3 @@
require 'rfpdf'
ActionView::Base::register_template_handler 'rfpdf', RFPDF::View

View File

@ -0,0 +1,31 @@
# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>
#
# The MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
$LOAD_PATH.unshift(File.dirname(__FILE__))
require 'rfpdf/errors'
require 'rfpdf/view'
require 'rfpdf/fpdf'
require 'rfpdf/rfpdf'
require 'rfpdf/chinese'
require 'rfpdf/japanese'
require 'rfpdf/korean'

View File

@ -0,0 +1,99 @@
# Translation of the bookmark class from the PHP FPDF script from Olivier Plathey
# Translated by Sylvain Lafleur and ?? with the help of Brian Ollenberger
#
# First added in 1.53b
#
# Usage is as follows:
#
# require 'fpdf'
# require 'bookmark'
# pdf = FPDF.new
# pdf.extend(PDF_Bookmark)
#
# This allows it to be combined with other extensions, such as the Chinese
# module.
module PDF_Bookmark
def PDF_Bookmark.extend_object(o)
o.instance_eval('@outlines,@OutlineRoot=[],0')
super(o)
end
def Bookmark(txt,level=0,y=0)
y=self.GetY() if y==-1
@outlines.push({'t'=>txt,'l'=>level,'y'=>y,'p'=>self.PageNo()})
end
def putbookmarks
@nb=@outlines.size
return if @nb==0
lru=[]
level=0
@outlines.each_index do |i|
o=@outlines[i]
if o['l']>0
parent=lru[o['l']-1]
# Set parent and last pointers
@outlines[i]['parent']=parent
@outlines[parent]['last']=i
if o['l']>level
# Level increasing: set first pointer
@outlines[parent]['first']=i
end
else
@outlines[i]['parent']=@nb
end
if o['l']<=level and i>0
# Set prev and next pointers
prev=lru[o['l']]
@outlines[prev]['next']=i
@outlines[i]['prev']=prev
end
lru[o['l']]=i
level=o['l']
end
# Outline items
n=@n+1
@outlines.each_index do |i|
o=@outlines[i]
newobj
out('<</Title '+(textstring(o['t'])))
out('/Parent '+(n+o['parent']).to_s+' 0 R')
if o['prev']
out('/Prev '+(n+o['prev']).to_s+' 0 R')
end
if o['next']
out('/Next '+(n+o['next']).to_s+' 0 R')
end
if o['first']
out('/First '+(n+o['first']).to_s+' 0 R')
end
if o['last']
out('/Last '+(n+o['last']).to_s+' 0 R')
end
out(sprintf('/Dest [%d 0 R /XYZ 0 %.2f
null]',1+2*o['p'],(@h-o['y'])*@k))
out('/Count 0>>')
out('endobj')
end
# Outline root
newobj
@OutlineRoot=@n
out('<</Type /Outlines /First '+n.to_s+' 0 R')
out('/Last '+(n+lru[0]).to_s+' 0 R>>')
out('endobj')
end
def putresources
super
putbookmarks
end
def putcatalog
super
if not @outlines.empty?
out('/Outlines '+@OutlineRoot.to_s+' 0 R')
out('/PageMode /UseOutlines')
end
end
end

View File

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

View File

@ -0,0 +1,4 @@
module RFPDF
class GenerationError < StandardError #:nodoc:
end
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
# Information
#
# PDF_EPS class from Valentin Schmidt ported to ruby by Thiago Jackiw (tjackiw@gmail.com)
# working for Mingle LLC (www.mingle.com)
# Release Date: July 13th, 2006
#
# Description
#
# This script allows to embed vector-based Adobe Illustrator (AI) or AI-compatible EPS files.
# Only vector drawing is supported, not text or bitmap. Although the script was successfully
# tested with various AI format versions, best results are probably achieved with files that
# were exported in the AI3 format (tested with Illustrator CS2, Freehand MX and Photoshop CS2).
#
# ImageEps(string file, float x, float y [, float w [, float h [, string link [, boolean useBoundingBox]]]])
#
# Same parameters as for regular FPDF::Image() method, with an additional one:
#
# useBoundingBox: specifies whether to position the bounding box (true) or the complete canvas (false)
# at location (x,y). Default value is true.
#
# First added to the Ruby FPDF distribution in 1.53c
#
# Usage is as follows:
#
# require 'fpdf'
# require 'fpdf_eps'
# pdf = FPDF.new
# pdf.extend(PDF_EPS)
# pdf.ImageEps(...)
#
# This allows it to be combined with other extensions, such as the bookmark
# module.
module PDF_EPS
def ImageEps(file, x, y, w=0, h=0, link='', use_bounding_box=true)
data = nil
if File.exists?(file)
File.open(file, 'rb') do |f|
data = f.read()
end
else
Error('EPS file not found: '+file)
end
# Find BoundingBox param
regs = data.scan(/%%BoundingBox: [^\r\n]*/m)
regs << regs[0].gsub(/%%BoundingBox: /, '')
if regs.size > 1
tmp = regs[1].to_s.split(' ')
@x1 = tmp[0].to_i
@y1 = tmp[1].to_i
@x2 = tmp[2].to_i
@y2 = tmp[3].to_i
else
Error('No BoundingBox found in EPS file: '+file)
end
f_start = data.index('%%EndSetup')
f_start = data.index('%%EndProlog') if f_start === false
f_start = data.index('%%BoundingBox') if f_start === false
data = data.slice(f_start, data.length)
f_end = data.index('%%PageTrailer')
f_end = data.index('showpage') if f_end === false
data = data.slice(0, f_end) if f_end
# save the current graphic state
out('q')
k = @k
# Translate
if use_bounding_box
dx = x*k-@x1
dy = @hPt-@y2-y*k
else
dx = x*k
dy = -y*k
end
tm = [1,0,0,1,dx,dy]
out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm',
tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]))
if w > 0
scale_x = w/((@x2-@x1)/k)
if h > 0
scale_y = h/((@y2-@y1)/k)
else
scale_y = scale_x
h = (@y2-@y1)/k * scale_y
end
else
if h > 0
scale_y = $h/((@y2-@y1)/$k)
scale_x = scale_y
w = (@x2-@x1)/k * scale_x
else
w = (@x2-@x1)/k
h = (@y2-@y1)/k
end
end
if !scale_x.nil?
# Scale
tm = [scale_x,0,0,scale_y,0,@hPt*(1-scale_y)]
out(sprintf('%.3f %.3f %.3f %.3f %.3f %.3f cm',
tm[0], tm[1], tm[2], tm[3], tm[4], tm[5]))
end
data.split(/\r\n|[\r\n]/).each do |line|
next if line == '' || line[0,1] == '%'
len = line.length
# next if (len > 2 && line[len-2,len] != ' ')
cmd = line[len-2,len].strip
case cmd
when 'm', 'l', 'v', 'y', 'c', 'k', 'K', 'g', 'G', 's', 'S', 'J', 'j', 'w', 'M', 'd':
out(line)
when 'L':
line[len-1,len]='l'
out(line)
when 'C':
line[len-1,len]='c'
out(line)
when 'f', 'F':
out('f*')
when 'b', 'B':
out(cmd + '*')
end
end
# restore previous graphic state
out('Q')
Link(x,y,w,h,link) if link
end
end

View File

@ -0,0 +1,468 @@
# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>
# 1.12 contributed by Ed Moss.
#
# The MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# This is direct port of japanese.php
#
# Japanese PDF support.
#
# Usage is as follows:
#
# require 'fpdf'
# require 'chinese'
# pdf = FPDF.new
# pdf.extend(PDF_Japanese)
#
# This allows it to be combined with other extensions, such as the bookmark
# module.
module PDF_Japanese
SJIS_widths={' ' => 278, '!' => 299, '"' => 353, '#' => 614, '$' => 614, '%' => 721, '&' => 735, '\'' => 216,
'(' => 323, ')' => 323, '*' => 449, '+' => 529, ',' => 219, '-' => 306, '.' => 219, '/' => 453, '0' => 614, '1' => 614,
'2' => 614, '3' => 614, '4' => 614, '5' => 614, '6' => 614, '7' => 614, '8' => 614, '9' => 614, ':' => 219, ';' => 219,
'<' => 529, '=' => 529, '>' => 529, '?' => 486, '@' => 744, 'A' => 646, 'B' => 604, 'C' => 617, 'D' => 681, 'E' => 567,
'F' => 537, 'G' => 647, 'H' => 738, 'I' => 320, 'J' => 433, 'K' => 637, 'L' => 566, 'M' => 904, 'N' => 710, 'O' => 716,
'P' => 605, 'Q' => 716, 'R' => 623, 'S' => 517, 'T' => 601, 'U' => 690, 'V' => 668, 'W' => 990, 'X' => 681, 'Y' => 634,
'Z' => 578, '[' => 316, '\\' => 614, ']' => 316, '^' => 529, '_' => 500, '`' => 387, 'a' => 509, 'b' => 566, 'c' => 478,
'd' => 565, 'e' => 503, 'f' => 337, 'g' => 549, 'h' => 580, 'i' => 275, 'j' => 266, 'k' => 544, 'l' => 276, 'm' => 854,
'n' => 579, 'o' => 550, 'p' => 578, 'q' => 566, 'r' => 410, 's' => 444, 't' => 340, 'u' => 575, 'v' => 512, 'w' => 760,
'x' => 503, 'y' => 529, 'z' => 453, '{' => 326, '|' => 380, '}' => 326, '~' => 387}
def AddCIDFont(family,style,name,cw,cMap,registry)
fontkey=family.downcase+style.upcase
unless @fonts[fontkey].nil?
Error("CID font already added: family style")
end
i=@fonts.length+1
@fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-120,'ut'=>40,'cw'=>cw,
'CMap'=>cMap,'registry'=>registry}
end
def AddCIDFonts(family,name,cw,cMap,registry)
AddCIDFont(family,'',name,cw,cMap,registry)
AddCIDFont(family,'B',name+',Bold',cw,cMap,registry)
AddCIDFont(family,'I',name+',Italic',cw,cMap,registry)
AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)
end
def AddSJISFont(family='SJIS')
#Add SJIS font with proportional Latin
name='KozMinPro-Regular-Acro'
cw=SJIS_widths
cMap='90msp-RKSJ-H'
registry={'ordering'=>'Japan1','supplement'=>2}
AddCIDFonts(family,name,cw,cMap,registry)
end
def AddSJIShwFont(family='SJIS-hw')
#Add SJIS font with half-width Latin
name='KozMinPro-Regular-Acro'
32.upto(126) do |i|
cw[i.chr]=500
end
cMap='90ms-RKSJ-H'
registry={'ordering'=>'Japan1','supplement'=>2}
AddCIDFonts(family,name,cw,cMap,registry)
end
def GetStringWidth(s)
if(@CurrentFont['type']=='Type0')
return GetSJISStringWidth(s)
else
return super(s)
end
end
def GetSJISStringWidth(s)
#SJIS version of GetStringWidth()
l=0
cw=@CurrentFont['cw']
nb=s.length
i=0
while(i<nb)
o=s[i]
if(o<128)
#ASCII
l+=cw[o.chr]
i+=1
elsif(o>=161 and o<=223)
#Half-width katakana
l+=500
i+=1
else
#Full-width character
l+=1000
i+=2
end
end
return l*@FontSize/1000
end
def MultiCell(w,h,txt,border=0,align='L',fill=0)
if(@CurrentFont['type']=='Type0')
SJISMultiCell(w,h,txt,border,align,fill)
else
super(w,h,txt,border,align,fill)
end
end
def SJISMultiCell(w,h,txt,border=0,align='L',fill=0)
#Output text with automatic or explicit line breaks
cw=@CurrentFont['cw']
if(w==0)
w=@w-@rMargin-@x
end
wmax=(w-2*@cMargin)*1000/@FontSize
s=txt.gsub("\r",'')
nb=s.length
if(nb>0 and s[nb-1]=="\n")
nb-=1
end
b=0
if(border)
if(border==1)
border='LTRB'
b='LRT'
b2='LR'
else
b2=''
if(border.index('L').nil?)
b2+='L'
end
if(border.index('R').nil?)
b2+='R'
end
b=border.index('T').nil? ? b2+'T' : b2
end
end
sep=-1
i=0
j=0
l=0
nl=1
while(i<nb)
#Get next character
c=s[i]
o=ord(c)
if(o==10)
#Explicit line break
Cell(w,h,s[j,i-j],b,2,align,fill)
i+=1
sep=-1
j=i
l=0
nl+=1
if(border and nl==2)
b=b2
end
next
end
if(o<128)
#ASCII
l+=cw[c.chr]
n=1
if(o==32)
sep=i
end
elsif(o>=161 and o<=223)
#Half-width katakana
l+=500
n=1
sep=i
else
#Full-width character
l+=1000
n=2
sep=i
end
if(l>wmax)
#Automatic line break
if(sep==-1 or i==j)
if(i==j)
i+=n
end
Cell(w,h,s[j,i-j],b,2,align,fill)
else
Cell(w,h,s[j,sep-j],b,2,align,fill)
i=(s[sep]==' ') ? sep+1 : sep
end
sep=-1
j=i
l=0
nl+=1
if(border and nl==2)
b=b2
end
else
i+=n
if(o>=128)
sep=i
end
end
end
#Last chunk
if(border and not border.index('B').nil?)
b+='B'
end
Cell(w,h,s[j,i-j],b,2,align,fill)
@x=@lMargin
end
def Write(h,txt,link='')
if(@CurrentFont['type']=='Type0')
SJISWrite(h,txt,link)
else
super(h,txt,link)
end
end
def SJISWrite(h,txt,link)
#SJIS version of Write()
cw=@CurrentFont['cw']
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
s=txt.gsub("\r",'')
nb=s.length
sep=-1
i=0
j=0
l=0
nl=1
while(i<nb)
#Get next character
c=s[i]
o=c
if(o==10)
#Explicit line break
Cell(w,h,s[j,i-j],0,2,'',0,link)
i+=1
sep=-1
j=i
l=0
if(nl==1)
#Go to left margin
@x=@lMargin
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
end
nl+=1
next
end
if(o<128)
#ASCII
l+=cw[c.chr]
n=1
if(o==32)
sep=i
end
elsif(o>=161 and o<=223)
#Half-width katakana
l+=500
n=1
sep=i
else
#Full-width character
l+=1000
n=2
sep=i
end
if(l>wmax)
#Automatic line break
if(sep==-1 or i==j)
if(@x>@lMargin)
#Move to next line
@x=@lMargin
@y+=h
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
i+=n
nl+=1
next
end
if(i==j)
i+=n
end
Cell(w,h,s[j,i-j],0,2,'',0,link)
else
Cell(w,h,s[j,sep-j],0,2,'',0,link)
i=(s[sep]==' ') ? sep+1 : sep
end
sep=-1
j=i
l=0
if(nl==1)
@x=@lMargin
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
end
nl+=1
else
i+=n
if(o>=128)
sep=i
end
end
end
#Last chunk
if(i!=j)
Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link)
end
end
private
def putfonts()
nf=@n
@diffs.each do |diff|
#Encodings
newobj()
out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')
out('endobj')
end
# mqr=get_magic_quotes_runtime()
# set_magic_quotes_runtime(0)
@FontFiles.each_pair do |file, info|
#Font file embedding
newobj()
@FontFiles[file]['n']=@n
if(defined('FPDF_FONTPATH'))
file=FPDF_FONTPATH+file
end
size=filesize(file)
if(!size)
Error('Font file not found')
end
out('<</Length '+size)
if(file[-2]=='.z')
out('/Filter /FlateDecode')
end
out('/Length1 '+info['length1'])
unless info['length2'].nil?
out('/Length2 '+info['length2']+' /Length3 0')
end
out('>>')
f=fopen(file,'rb')
putstream(fread(f,size))
fclose(f)
out('endobj')
end
# set_magic_quotes_runtime(mqr)
@fonts.each_pair do |k, font|
#Font objects
newobj()
@fonts[k]['n']=@n
out('<</Type /Font')
if(font['type']=='Type0')
putType0(font)
else
name=font['name']
out('/BaseFont /'+name)
if(font['type']=='core')
#Standard font
out('/Subtype /Type1')
if(name!='Symbol' and name!='ZapfDingbats')
out('/Encoding /WinAnsiEncoding')
end
else
#Additional font
out('/Subtype /'+font['type'])
out('/FirstChar 32')
out('/LastChar 255')
out('/Widths '+(@n+1)+' 0 R')
out('/FontDescriptor '+(@n+2)+' 0 R')
if(font['enc'])
if !font['diff'].nil?
out('/Encoding '+(nf+font['diff'])+' 0 R')
else
out('/Encoding /WinAnsiEncoding')
end
end
end
out('>>')
out('endobj')
if(font['type']!='core')
#Widths
newobj()
cw=font['cw']
s='['
32.upto(255) do |i|
s+=cw[i.chr]+' '
end
out(s+']')
out('endobj')
#Descriptor
newobj()
s='<</Type /FontDescriptor /FontName /'+name
font['desc'].each_pair do |k, v|
s+=' /'+k+' '+v
end
file=font['file']
if(file)
s+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@FontFiles[file]['n']+' 0 R'
end
out(s+'>>')
out('endobj')
end
end
end
end
def putType0(font)
#Type0
out('/Subtype /Type0')
out('/BaseFont /'+font['name']+'-'+font['CMap'])
out('/Encoding /'+font['CMap'])
out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
out('>>')
out('endobj')
#CIDFont
newobj()
out('<</Type /Font')
out('/Subtype /CIDFontType0')
out('/BaseFont /'+font['name'])
out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')
out('/FontDescriptor '+(@n+1).to_s+' 0 R')
w='/W [1 ['
font['cw'].keys.sort.each {|key|
w+=font['cw'][key].to_s + " "
# ActionController::Base::logger.debug key.to_s
# ActionController::Base::logger.debug font['cw'][key].to_s
}
out(w+'] 231 325 500 631 [500] 326 389 500]')
out('>>')
out('endobj')
#Font descriptor
newobj()
out('<</Type /FontDescriptor')
out('/FontName /'+font['name'])
out('/Flags 6')
out('/FontBBox [0 -200 1000 900]')
out('/ItalicAngle 0')
out('/Ascent 800')
out('/Descent -200')
out('/CapHeight 800')
out('/StemV 60')
out('>>')
out('endobj')
end
end

View File

@ -0,0 +1,436 @@
# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>
# 1.12 contributed by Ed Moss.
#
# The MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# This is direct port of korean.php
#
# Korean PDF support.
#
# Usage is as follows:
#
# require 'fpdf'
# require 'chinese'
# pdf = FPDF.new
# pdf.extend(PDF_Korean)
#
# This allows it to be combined with other extensions, such as the bookmark
# module.
module PDF_Korean
UHC_widths={' ' => 333, '!' => 416, '"' => 416, '#' => 833, '$' => 625, '%' => 916, '&' => 833, '\'' => 250,
'(' => 500, ')' => 500, '*' => 500, '+' => 833, ',' => 291, '-' => 833, '.' => 291, '/' => 375, '0' => 625, '1' => 625,
'2' => 625, '3' => 625, '4' => 625, '5' => 625, '6' => 625, '7' => 625, '8' => 625, '9' => 625, ':' => 333, ';' => 333,
'<' => 833, '=' => 833, '>' => 916, '?' => 500, '@' => 1000, 'A' => 791, 'B' => 708, 'C' => 708, 'D' => 750, 'E' => 708,
'F' => 666, 'G' => 750, 'H' => 791, 'I' => 375, 'J' => 500, 'K' => 791, 'L' => 666, 'M' => 916, 'N' => 791, 'O' => 750,
'P' => 666, 'Q' => 750, 'R' => 708, 'S' => 666, 'T' => 791, 'U' => 791, 'V' => 750, 'W' => 1000, 'X' => 708, 'Y' => 708,
'Z' => 666, '[' => 500, '\\' => 375, ']' => 500, '^' => 500, '_' => 500, '`' => 333, 'a' => 541, 'b' => 583, 'c' => 541,
'd' => 583, 'e' => 583, 'f' => 375, 'g' => 583, 'h' => 583, 'i' => 291, 'j' => 333, 'k' => 583, 'l' => 291, 'm' => 875,
'n' => 583, 'o' => 583, 'p' => 583, 'q' => 583, 'r' => 458, 's' => 541, 't' => 375, 'u' => 583, 'v' => 583, 'w' => 833,
'x' => 625, 'y' => 625, 'z' => 500, '{' => 583, '|' => 583, '}' => 583, '~' => 750}
def AddCIDFont(family,style,name,cw,cMap,registry)
fontkey=family.downcase+style.upcase
unless @fonts[fontkey].nil?
Error("Font already added: family style")
end
i=@fonts.length+1
name=name.gsub(' ','')
@fonts[fontkey]={'i'=>i,'type'=>'Type0','name'=>name,'up'=>-130,'ut'=>40,'cw'=>cw,
'CMap'=>cMap,'registry'=>registry}
end
def AddCIDFonts(family,name,cw,cMap,registry)
AddCIDFont(family,'',name,cw,cMap,registry)
AddCIDFont(family,'B',name+',Bold',cw,cMap,registry)
AddCIDFont(family,'I',name+',Italic',cw,cMap,registry)
AddCIDFont(family,'BI',name+',BoldItalic',cw,cMap,registry)
end
def AddUHCFont(family='UHC',name='HYSMyeongJoStd-Medium-Acro')
#Add UHC font with proportional Latin
cw=UHC_widths
cMap='KSCms-UHC-H'
registry={'ordering'=>'Korea1','supplement'=>1}
AddCIDFonts(family,name,cw,cMap,registry)
end
def AddUHChwFont(family='UHC-hw',name='HYSMyeongJoStd-Medium-Acro')
#Add UHC font with half-witdh Latin
32.upto(126) do |i|
cw[i.chr]=500
end
cMap='KSCms-UHC-HW-H'
registry={'ordering'=>'Korea1','supplement'=>1}
AddCIDFonts(family,name,cw,cMap,registry)
end
def GetStringWidth(s)
if(@CurrentFont['type']=='Type0')
return GetMBStringWidth(s)
else
return super(s)
end
end
def GetMBStringWidth(s)
#Multi-byte version of GetStringWidth()
l=0
cw=@CurrentFont['cw']
nb=s.length
i=0
while(i<nb)
c=s[i]
if(c<128)
l+=cw[c.chr]
i+=1
else
l+=1000
i+=2
end
end
return l*@FontSize/1000
end
def MultiCell(w,h,txt,border=0,align='L',fill=0)
if(@CurrentFont['type']=='Type0')
MBMultiCell(w,h,txt,border,align,fill)
else
super(w,h,txt,border,align,fill)
end
end
def MBMultiCell(w,h,txt,border=0,align='L',fill=0)
#Multi-byte version of MultiCell()
cw=@CurrentFont['cw']
if(w==0)
w=@w-@rMargin-@x
end
wmax=(w-2*@cMargin)*1000/@FontSize
s=txt.gsub("\r",'')
nb=s.length
if(nb>0 and s[nb-1]=="\n")
nb-=1
end
b=0
if(border)
if(border==1)
border='LTRB'
b='LRT'
b2='LR'
else
b2=''
if(border.index('L').nil?)
b2+='L'
end
if(border.index('R').nil?)
b2+='R'
end
b=border.index('T').nil? ? b2+'T' : b2
end
end
sep=-1
i=0
j=0
l=0
nl=1
while(i<nb)
#Get next character
c=s[i]
#Check if ASCII or MB
ascii=(c<128)
if(c=="\n")
#Explicit line break
Cell(w,h,s[j,i-j],b,2,align,fill)
i+=1
sep=-1
j=i
l=0
nl+=1
if(border and nl==2)
b=b2
end
next
end
if(!ascii)
sep=i
ls=l
elsif(c==' ')
sep=i
ls=l
end
l+=ascii ? cw[c.chr] : 1000
if(l>wmax)
#Automatic line break
if(sep==-1 or i==j)
if(i==j)
i+=ascii ? 1 : 2
end
Cell(w,h,s[j,i-j],b,2,align,fill)
else
Cell(w,h,s[j,sep-j],b,2,align,fill)
i=(s[sep]==' ') ? sep+1 : sep
end
sep=-1
j=i
l=0
nl+=1
if(border and nl==2)
b=b2
end
else
i+=ascii ? 1 : 2
end
end
#Last chunk
if(border and not border.index('B').nil?)
b+='B'
end
Cell(w,h,s[j,i-j],b,2,align,fill)
@x=@lMargin
end
def Write(h,txt,link='')
if(@CurrentFont['type']=='Type0')
MBWrite(h,txt,link)
else
super(h,txt,link)
end
end
def MBWrite(h,txt,link)
#Multi-byte version of Write()
cw=@CurrentFont['cw']
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
s=txt.gsub("\r",'')
nb=s.length
sep=-1
i=0
j=0
l=0
nl=1
while(i<nb)
#Get next character
c=s[i]
#Check if ASCII or MB
ascii=(c<128)
if(c=="\n")
#Explicit line break
Cell(w,h,s[j,i-j],0,2,'',0,link)
i+=1
sep=-1
j=i
l=0
if(nl==1)
@x=@lMargin
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
end
nl+=1
next
end
if(!ascii or c==' ')
sep=i
end
l+=ascii ? cw[c.chr] : 1000
if(l>wmax)
#Automatic line break
if(sep==-1 or i==j)
if(@x>@lMargin)
#Move to next line
@x=@lMargin
@y+=h
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
i+=1
nl+=1
next
end
if(i==j)
i+=ascii ? 1 : 2
end
Cell(w,h,s[j,i-j],0,2,'',0,link)
else
Cell(w,h,s[j,sep-j],0,2,'',0,link)
i=(s[sep]==' ') ? sep+1 : sep
end
sep=-1
j=i
l=0
if(nl==1)
@x=@lMargin
w=@w-@rMargin-@x
wmax=(w-2*@cMargin)*1000/@FontSize
end
nl+=1
else
i+=ascii ? 1 : 2
end
end
#Last chunk
if(i!=j)
Cell(l/1000*@FontSize,h,s[j,i-j],0,0,'',0,link)
end
end
private
def putfonts()
nf=@n
@diffs.each do |diff|
#Encodings
newobj()
out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences ['+diff+']>>')
out('endobj')
end
# mqr=get_magic_quotes_runtime()
# set_magic_quotes_runtime(0)
@FontFiles.each_pair do |file, info|
#Font file embedding
newobj()
@FontFiles[file]['n']=@n
if(defined('FPDF_FONTPATH'))
file=FPDF_FONTPATH+file
end
size=filesize(file)
if(!size)
Error('Font file not found')
end
out('<</Length '+size)
if(file[-2]=='.z')
out('/Filter /FlateDecode')
end
out('/Length1 '+info['length1'])
if(not info['length2'].nil?)
out('/Length2 '+info['length2']+' /Length3 0')
end
out('>>')
f=fopen(file,'rb')
putstream(fread(f,size))
fclose(f)
out('endobj')
end
# set_magic_quotes_runtime(mqr)
@fonts.each_pair do |k, font|
#Font objects
newobj()
@fonts[k]['n']=@n
out('<</Type /Font')
if(font['type']=='Type0')
putType0(font)
else
name=font['name']
out('/BaseFont /'+name)
if(font['type']=='core')
#Standard font
out('/Subtype /Type1')
if(name!='Symbol' and name!='ZapfDingbats')
out('/Encoding /WinAnsiEncoding')
end
else
#Additional font
out('/Subtype /'+font['type'])
out('/FirstChar 32')
out('/LastChar 255')
out('/Widths '+(@n+1)+' 0 R')
out('/FontDescriptor '+(@n+2)+' 0 R')
if(font['enc'])
if(not font['diff'].nil?)
out('/Encoding '+(nf+font['diff'])+' 0 R')
else
out('/Encoding /WinAnsiEncoding')
end
end
end
out('>>')
out('endobj')
if(font['type']!='core')
#Widths
newobj()
cw=font['cw']
s='['
32.upto(255) do |i|
s+=cw[i.chr]+' '
end
out(s+']')
out('endobj')
#Descriptor
newobj()
s='<</Type /FontDescriptor /FontName /'+name
font['desc'].each_pair do |k, v|
s+=' /'+k+' '+v
end
file=font['file']
if(file)
s+=' /FontFile'+(font['type']=='Type1' ? '' : '2')+' '+@FontFiles[file]['n']+' 0 R'
end
out(s+'>>')
out('endobj')
end
end
end
end
def putType0(font)
#Type0
out('/Subtype /Type0')
out('/BaseFont /'+font['name']+'-'+font['CMap'])
out('/Encoding /'+font['CMap'])
out('/DescendantFonts ['+(@n+1).to_s+' 0 R]')
out('>>')
out('endobj')
#CIDFont
newobj()
out('<</Type /Font')
out('/Subtype /CIDFontType0')
out('/BaseFont /'+font['name'])
out('/CIDSystemInfo <</Registry (Adobe) /Ordering ('+font['registry']['ordering']+') /Supplement '+font['registry']['supplement'].to_s+'>>')
out('/FontDescriptor '+(@n+1).to_s+' 0 R')
if(font['CMap']=='KSCms-UHC-HW-H')
w='8094 8190 500'
else
w='1 ['
font['cw'].keys.sort.each {|key|
w+=font['cw'][key].to_s + " "
# ActionController::Base::logger.debug key.to_s
# ActionController::Base::logger.debug font['cw'][key].to_s
}
w +=']'
end
out('/W ['+w+']>>')
out('endobj')
#Font descriptor
newobj()
out('<</Type /FontDescriptor')
out('/FontName /'+font['name'])
out('/Flags 6')
out('/FontBBox [0 -200 1000 900]')
out('/ItalicAngle 0')
out('/Ascent 800')
out('/Descent -200')
out('/CapHeight 800')
out('/StemV 50')
out('>>')
out('endobj')
end
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,346 @@
module RFPDF
COLOR_PALETTE = {
:black => [0x00, 0x00, 0x00],
:white => [0xff, 0xff, 0xff],
}.freeze
# Draw a line from (<tt>x1, y1</tt>) to (<tt>x2, y2</tt>).
#
# Options are:
# * <tt>:line_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.
# * <tt>:line_width</tt> - Default value is <tt>0.5</tt>.
#
# Example:
#
# draw_line(x1, y1, x1, y1+h, :line_color => ReportHelper::COLOR_PALETTE[:dark_blue], :line_width => 1)
#
def draw_line(x1, y1, x2, y2, options = {})
options[:line_color] ||= COLOR_PALETTE[:black]
options[:line_width] ||= 0.5
set_draw_color(options[:line_color])
SetLineWidth(options[:line_width])
Line(x1, y1, x2, y2)
end
# Draw a string of <tt>text</tt> at (<tt>x, y</tt>).
#
# Options are:
# * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.
# * <tt>:font_size</tt> - Default value is <tt>10</tt>.
# * <tt>:font_style</tt> - Default value is nothing or <tt>''</tt>.
#
# Example:
#
# draw_text(x, y, header_left, :font_size => 10)
#
def draw_text(x, y, text, options = {})
options[:font_color] ||= COLOR_PALETTE[:black]
options[:font_size] ||= 10
options[:font_style] ||= ''
set_text_color(options[:font_color])
SetFont('Arial', options[:font_style], options[:font_size])
SetXY(x, y)
Write(options[:font_size] + 4, text)
end
# Draw a block of <tt>text</tt> at (<tt>x, y</tt>) bounded by <tt>left_margin</tt> and <tt>right_margin</tt>. Both
# margins are measured from their corresponding edge.
#
# Options are:
# * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.
# * <tt>:font_size</tt> - Default value is <tt>10</tt>.
# * <tt>:font_style</tt> - Default value is nothing or <tt>''</tt>.
#
# Example:
#
# draw_text_block(left_margin, 85, "question", left_margin, 280,
# :font_color => ReportHelper::COLOR_PALETTE[:dark_blue],
# :font_size => 12,
# :font_style => 'I')
#
def draw_text_block(x, y, text, left_margin, right_margin, options = {})
options[:font_color] ||= COLOR_PALETTE[:black]
options[:font_size] ||= 10
options[:font_style] ||= ''
set_text_color(options[:font_color])
SetFont('Arial', options[:font_style], options[:font_size])
SetXY(x, y)
SetLeftMargin(left_margin)
SetRightMargin(right_margin)
Write(options[:font_size] + 4, text)
SetMargins(0,0,0)
end
# Draw a box at (<tt>x, y</tt>), <tt>w</tt> wide and <tt>h</tt> high.
#
# Options are:
# * <tt>:border</tt> - Draw a border, 0 = no, 1 = yes? Default value is <tt>1</tt>.
# * <tt>:border_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.
# * <tt>:border_width</tt> - Default value is <tt>0.5</tt>.
# * <tt>:fill</tt> - Fill the box, 0 = no, 1 = yes? Default value is <tt>1</tt>.
# * <tt>:fill_color</tt> - Default value is nothing or <tt>COLOR_PALETTE[:white]</tt>.
#
# Example:
#
# draw_box(x, y - 1, 38, 22)
#
def draw_box(x, y, w, h, options = {})
options[:border] ||= 1
options[:border_color] ||= COLOR_PALETTE[:black]
options[:border_width] ||= 0.5
options[:fill] ||= 1
options[:fill_color] ||= COLOR_PALETTE[:white]
SetLineWidth(options[:border_width])
set_draw_color(options[:border_color])
set_fill_color(options[:fill_color])
fd = ""
fd = "D" if options[:border] == 1
fd += "F" if options[:fill] == 1
Rect(x, y, w, h, fd)
end
# Draw a string of <tt>text</tt> at (<tt>x, y</tt>) in a box <tt>w</tt> wide and <tt>h</tt> high.
#
# Options are:
# * <tt>:align</tt> - Vertical alignment 'C' = center, 'L' = left, 'R' = right. Default value is <tt>'C'</tt>.
# * <tt>:border</tt> - Draw a border, 0 = no, 1 = yes? Default value is <tt>0</tt>.
# * <tt>:border_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.
# * <tt>:border_width</tt> - Default value is <tt>0.5</tt>.
# * <tt>:fill</tt> - Fill the box, 0 = no, 1 = yes? Default value is <tt>1</tt>.
# * <tt>:fill_color</tt> - Default value is nothing or <tt>COLOR_PALETTE[:white]</tt>.
# * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.
# * <tt>:font_size</tt> - Default value is nothing or <tt>8</tt>.
# * <tt>:font_style</tt> - 'B' = bold, 'I' = italic, 'U' = underline. Default value is nothing <tt>''</tt>.
# * <tt>:padding</tt> - Default value is nothing or <tt>2</tt>.
# * <tt>:valign</tt> - 'M' = middle, 'T' = top, 'B' = bottom. Default value is nothing or <tt>'M'</tt>.
#
# Example:
#
# draw_text_box(x, y - 1, 38, 22,
# "your_score_title",
# :fill => 0,
# :font_color => ReportHelper::COLOR_PALETTE[:blue],
# :font_line_spacing => 0,
# :font_style => "B",
# :valign => "M")
#
def draw_text_box(x, y, w, h, text, options = {})
options[:align] ||= 'C'
options[:border] ||= 0
options[:border_color] ||= COLOR_PALETTE[:black]
options[:border_width] ||= 0.5
options[:fill] ||= 1
options[:fill_color] ||= COLOR_PALETTE[:white]
options[:font_color] ||= COLOR_PALETTE[:black]
options[:font_size] ||= 8
options[:font_line_spacing] ||= options[:font_size] * 0.3
options[:font_style] ||= ''
options[:padding] ||= 2
options[:valign] ||= "M"
if options[:fill] == 1 or options[:border] == 1
draw_box(x, y, w, h, options)
end
SetMargins(0,0,0)
set_text_color(options[:font_color])
font_size = options[:font_size]
SetFont('Arial', options[:font_style], font_size)
font_size += options[:font_line_spacing]
case options[:valign]
when "B"
y -= options[:padding]
text = "\n" + text if text["\n"].nil?
when "T"
y += options[:padding]
end
SetXY(x, y)
if GetStringWidth(text) > w or not text["\n"].nil? or options[:valign] == "T"
font_size += options[:font_size] * 0.1
#TODO 2006-07-21 Level=1 - this is assuming a 2 line text
SetXY(x, y + ((h - (font_size * 2)) / 2)) if options[:valign] == "M"
MultiCell(w, font_size, text, 0, options[:align])
else
Cell(w, h, text, 0, 0, options[:align])
end
end
# Draw a string of <tt>text</tt> at (<tt>x, y</tt>) as a title.
#
# Options are:
# * <tt>:font_color</tt> - Default value is <tt>COLOR_PALETTE[:black]</tt>.
# * <tt>:font_size</tt> - Default value is <tt>18</tt>.
# * <tt>:font_style</tt> - Default value is nothing or <tt>''</tt>.
#
# Example:
#
# draw_title(left_margin, 60,
# "title:",
# :font_color => ReportHelper::COLOR_PALETTE[:dark_blue])
#
def draw_title(x, y, title, options = {})
options[:font_color] ||= COLOR_PALETTE[:black]
options[:font_size] ||= 18
options[:font_style] ||= ''
set_text_color(options[:font_color])
SetFont('Arial', options[:font_style], options[:font_size])
SetXY(x, y)
Write(options[:font_size] + 2, title)
end
# Set the draw color. Default value is <tt>COLOR_PALETTE[:black]</tt>.
#
# Example:
#
# set_draw_color(ReportHelper::COLOR_PALETTE[:dark_blue])
#
def set_draw_color(color = COLOR_PALETTE[:black])
SetDrawColor(color[0], color[1], color[2])
end
# Set the fill color. Default value is <tt>COLOR_PALETTE[:white]</tt>.
#
# Example:
#
# set_fill_color(ReportHelper::COLOR_PALETTE[:dark_blue])
#
def set_fill_color(color = COLOR_PALETTE[:white])
SetFillColor(color[0], color[1], color[2])
end
# Set the text color. Default value is <tt>COLOR_PALETTE[:white]</tt>.
#
# Example:
#
# set_text_color(ReportHelper::COLOR_PALETTE[:dark_blue])
#
def set_text_color(color = COLOR_PALETTE[:black])
SetTextColor(color[0], color[1], color[2])
end
# Write a string containing html characters. Default value is <tt>COLOR_PALETTE[:white]</tt>.
#
# Options are:
# * <tt>:height</tt> - Line height. Default value is <tt>20</tt>.
#
# Example:
#
# write_html(html, :height => 12)
#
def write_html(html, options = {})
options[:height] ||= 20
#HTML parser
@href = nil
@style = {}
html.gsub!("\n",' ')
re = %r{ ( <!--.*?--> |
< (?:
[^<>"] +
|
" (?: \\. | [^\\"]+ ) * "
) *
>
) }xm
html.split(re).each do |value|
if "<" == value[0,1]
#Tag
if (value[1, 1] == '/')
close_tag(value[2..-2], options)
else
tag = value[1..-2]
open_tag(tag, options)
end
else
#Text
if @href
put_link(@href,value)
else
Write(options[:height], value)
end
end
end
end
def open_tag(tag, options = {}) #:nodoc:
#Opening tag
tag = tag.to_s.upcase
set_style(tag, true) if tag == 'B' or tag == 'I' or tag == 'U'
@href = options['HREF'] if tag == 'A'
Ln(options[:height]) if tag == 'BR'
end
def close_tag(tag, options = {}) #:nodoc:
#Closing tag
tag = tag.to_s.upcase
set_style(tag, false) if tag == 'B' or tag == 'I' or tag == 'U'
@href = '' if $tag == 'A'
end
def set_style(tag, enable = true) #:nodoc:
#Modify style and select corresponding font
style = ""
@style[tag] = enable
['B','I','U'].each do |s|
style += s if not @style[s].nil? and @style[s]
end
SetFont('', style)
end
def put_link(url, txt) #:nodoc:
#Put a hyperlink
SetTextColor(0,0,255)
set_style('U',true)
Write(5, txt, url)
set_style('U',false)
SetTextColor(0)
end
end
# class FPDF
# alias_method :set_margins , :SetMargins
# alias_method :set_left_margin , :SetLeftMargin
# alias_method :set_top_margin , :SetTopMargin
# alias_method :set_right_margin , :SetRightMargin
# alias_method :set_auto_pagebreak , :SetAutoPageBreak
# alias_method :set_display_mode , :SetDisplayMode
# alias_method :set_compression , :SetCompression
# alias_method :set_title , :SetTitle
# alias_method :set_subject , :SetSubject
# alias_method :set_author , :SetAuthor
# alias_method :set_keywords , :SetKeywords
# alias_method :set_creator , :SetCreator
# alias_method :set_draw_color , :SetDrawColor
# alias_method :set_fill_color , :SetFillColor
# alias_method :set_text_color , :SetTextColor
# alias_method :set_line_width , :SetLineWidth
# alias_method :set_font , :SetFont
# alias_method :set_font_size , :SetFontSize
# alias_method :set_link , :SetLink
# alias_method :set_y , :SetY
# alias_method :set_xy , :SetXY
# alias_method :get_string_width , :GetStringWidth
# alias_method :get_x , :GetX
# alias_method :set_x , :SetX
# alias_method :get_y , :GetY
# alias_method :accept_pagev_break , :AcceptPageBreak
# alias_method :add_font , :AddFont
# alias_method :add_link , :AddLink
# alias_method :add_page , :AddPage
# alias_method :alias_nb_pages , :AliasNbPages
# alias_method :cell , :Cell
# alias_method :close , :Close
# alias_method :error , :Error
# alias_method :footer , :Footer
# alias_method :header , :Header
# alias_method :image , :Image
# alias_method :line , :Line
# alias_method :link , :Link
# alias_method :ln , :Ln
# alias_method :multi_cell , :MultiCell
# alias_method :open , :Open
# alias_method :Open , :open
# alias_method :output , :Output
# alias_method :page_no , :PageNo
# alias_method :rect , :Rect
# alias_method :text , :Text
# alias_method :write , :Write
# end

View File

@ -0,0 +1,75 @@
# Copyright (c) 2006 4ssoM LLC <www.4ssoM.com>
#
# The MIT License
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Thanks go out to Bruce Williams of codefluency who created RTex. This
# template handler is modification of his work.
#
# Example Registration
#
# ActionView::Base::register_template_handler 'rfpdf', RFpdfView
module RFPDF
class View
def initialize(action_view)
@action_view = action_view
# Override with @options_for_rfpdf Hash in your controller
@options = {
# Run through latex first? (for table of contents, etc)
:pre_process => false,
# Debugging mode; raises exception
:debug => false,
# Filename of pdf to generate
:file_name => "#{@action_view.controller.action_name}.pdf",
# Temporary Directory
:temp_dir => "#{File.expand_path(RAILS_ROOT)}/tmp"
}.merge(@action_view.controller.instance_eval{ @options_for_rfpdf } || {}).with_indifferent_access
end
def render(template, local_assigns = {})
@pdf_name = "Default.pdf" if @pdf_name.nil?
unless @action_view.controller.headers["Content-Type"] == 'application/pdf'
@generate = true
@action_view.controller.headers["Content-Type"] = 'application/pdf'
@action_view.controller.headers["Content-disposition:"] = "inline; filename=\"#{@options[:file_name]}\""
end
assigns = @action_view.assigns.dup
if content_for_layout = @action_view.instance_variable_get("@content_for_layout")
assigns['content_for_layout'] = content_for_layout
end
result = @action_view.instance_eval do
assigns.each do |key,val|
instance_variable_set "@#{key}", val
end
local_assigns.each do |key,val|
class << self; self; end.send(:define_method,key){ val }
end
ERB.new(template).result(binding)
end
end
end
end

View File

@ -0,0 +1 @@
#!/usr/bin/env ruby