Module: CombinePDF

Defined in:
lib/combine_pdf.rb,
lib/combine_pdf/api.rb,
lib/combine_pdf/fonts.rb,
lib/combine_pdf/fonts.rb,
lib/combine_pdf/filter.rb,
lib/combine_pdf/parser.rb,
lib/combine_pdf/decrypt.rb,
lib/combine_pdf/version.rb,
lib/combine_pdf/renderer.rb,
lib/combine_pdf/exceptions.rb,
lib/combine_pdf/pdf_public.rb,
lib/combine_pdf/basic_writer.rb,
lib/combine_pdf/page_methods.rb,
lib/combine_pdf/pdf_protected.rb

Overview

Thoughts from reading the ISO 32000-1:2008 this file is part of the CombinePDF library and the code is subject to the same license.

Defined Under Namespace

Modules: PDFFilter, Page_Methods, Renderer Classes: EncryptionError, PDF, PDFDecrypt, PDFParser, PDFWriter

Constant Summary collapse

ParsingError =
Class.new(StandardError)
VERSION =
'1.0.23'.freeze

Class Method Summary collapse

Class Method Details

.calc_ctm(parameters) ⇒ Object

calculate a CTM value for a specific transformation.

this could be used to apply transformation in #textbox and to convert visual rotation values into actual rotation transformation.

this method accepts a Hash containing any of the following parameters:

deg

the clockwise rotation to be applied, in degrees

tx

the x translation to be applied.

ty

the y translation to be applied.

sx

the x scaling to be applied.

sy

the y scaling to be applied.

  • scaling will be applied after the transformation is applied.



120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/combine_pdf/api.rb', line 120

def calc_ctm(parameters)
  p = { deg: 0, tx: 0, ty: 0, sx: 1, sy: 1 }.merge parameters
  r = p[:deg] * Math::PI / 180
  s = Math.sin(r)
  c = Math.cos(r)
  # start with tranlation matrix
  m = Matrix[[1, 0, 0], [0, 1, 0], [p[:tx], p[:ty], 1]]
  # then rotate
  m *= Matrix[[c, s, 0], [-s, c, 0], [0, 0, 1]] if parameters[:deg]
  # then scale
  m *= Matrix[[p[:sx], 0, 0], [0, p[:sy], 0], [0, 0, 1]] if parameters[:sx] || parameters[:sy]
  # flaten array and round to 6 digits
  m.to_a.flatten.values_at(0, 1, 3, 4, 6, 7).map! { |f| f.round 6 }
end

.create_page(mediabox = [0, 0, 612.0, 792.0]) ⇒ Object

makes a PDFWriter object

PDFWriter objects reresent an empty page and have the method “textbox” that adds content to that page.

PDFWriter objects are used internally for numbering pages (by creating a PDF page with the page number and “stamping” it over the existing page).

::mediabox an Array representing the size of the PDF document. defaults to: [0.0, 0.0, 612.0, 792.0] (US Letter)

if the page is PDFWriter object as a stamp, the final size will be that of the original page.



54
55
56
# File 'lib/combine_pdf/api.rb', line 54

def create_page(mediabox = [0, 0, 612.0, 792.0])
  PDFWriter.new mediabox
end

.create_table(options = {}) ⇒ Object

makes a PDF object containing a table

all the pages in this PDF object are PDFWriter objects and are writable using the texbox function (should you wish to add a title, or more info)

the main intended use of this method is to create indexes (a table of contents) for merged data.

example:

pdf = CombinePDF.create_table headers: ["header 1", "another header"], table_data: [ ["this is one row", "with two columns"] , ["this is another row", "also two columns", "the third will be ignored"] ]
pdf.save "table_file.pdf"

accepts a Hash with any of the following keys as well as any of the Page_Methods#textbox options:

headers

an Array of strings with the headers (will be repeated every page).

table_data

as Array of Arrays, each containing a string for each column. the first row sets the number of columns. extra columns will be ignored.

font

a registered or standard font name (see Page_Methods). defaults to nil (:Helvetica).

header_font

a registered or standard font name for the headers (see Page_Methods). defaults to nil (the font for all the table rows).

max_font_size

the maximum font size. if the string doesn’t fit, it will be resized. defaults to 14.

column_widths

an array of relative column widths ([1,2] will display only the first two columns, the second twice as big as the first). defaults to nil (even widths).

header_color

the header color. defaults to [0.8, 0.8, 0.8] (light gray).

main_color

main row color. defaults to nil (transparent / white).

alternate_color

alternate row color. defaults to [0.95, 0.95, 0.95] (very light gray).

font_color

font color. defaults to [0,0,0] (black).

border_color

border color. defaults to [0,0,0] (black).

border_width

border width in PDF units. defaults to 1.

header_align

the header text alignment within each column (:right, :left, :center). defaults to :center.

row_align

the row text alignment within each column. defaults to :left (:right for RTL table).

direction

the table’s writing direction (:ltr or :rtl). this reffers to the direction of the columns and doesn’t effect text (rtl text is automatically recognized). defaults to :ltr.

max_rows

the number of rows per page, INCLUDING the header row. deafults to 25.

page_size

the size of the page in PDF points. defaults to [0, 0, 595.3, 841.9] (A4).



87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/combine_pdf/api.rb', line 87

def create_table(options = {})
  options[:max_rows] = options[:rows_per_page] if options[:rows_per_page]

  page_size = options[:page_size] || [0, 0, 595.3, 841.9]
  table = PDF.new
  page = nil
  until options[:table_data].empty?
    page = create_page page_size
    page.write_table options
    table << page
  end
  table
end

.eq_depth_limitObject

Gets the equality depth limit. This is the point at which CombinePDF will stop testing for nested items being equal.



172
173
174
# File 'lib/combine_pdf/api.rb', line 172

def eq_depth_limit
  @eq_depth_limit
end

.eq_depth_limit=(value) ⇒ Object

Sets the equality depth limit. This is the point at which CombinePDF will stop testing for nested items being equal.



176
177
178
# File 'lib/combine_pdf/api.rb', line 176

def eq_depth_limit= value
  @eq_depth_limit = value
end

.load(file_name = '', options = {}) ⇒ Object

Create an empty PDF object or create a PDF object from a file (parsing the file).

file_name

is the name of a file to be parsed.

Raises:

  • (TypeError)


8
9
10
11
12
# File 'lib/combine_pdf/api.rb', line 8

def load(file_name = '', options = {})
  raise TypeError, "couldn't parse data, expecting type String" unless file_name.is_a?(String) || file_name.is_a?(Pathname)
  return PDF.new if file_name == ''
  PDF.new(PDFParser.new(IO.read(file_name, mode: 'rb').force_encoding(Encoding::ASCII_8BIT), options))
end

.new(string = false) ⇒ Object

creats a new PDF object.

Combine PDF will check to see if ‘string` is a filename. If it’s a file name, it will attempt to load the PDF file using ‘CombinePDF.load`. Otherwise it will attempt parsing `string` using `CombinePDF.parse`.

If the string is empty it will return a new PDF object (the same as parse).

For both performance and code readability reasons, ‘CombinePDF.load` and `CombinePDF.parse` should be preffered unless creating a new PDF object.

Raises:

  • (TypeError)


22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/combine_pdf/api.rb', line 22

def new(string = false)
  return PDF.new unless string
  raise TypeError, "couldn't create PDF object, expecting type String" unless string.is_a?(String) || string.is_a?(Pathname)
  begin
    (begin
      File.file? string
    rescue
      false
    end) ? load(string) : parse(string)
  rescue => _e
    raise 'General PDF error - Use CombinePDF.load or CombinePDF.parse for a non-general error message (the requested file was not found OR the string received is not a valid PDF stream OR the file was found but not valid).'
  end
end

.new_table(options = {}) ⇒ Object



101
102
103
# File 'lib/combine_pdf/api.rb', line 101

def new_table(options = {})
  create_table options
end

.parse(data, options = {}) ⇒ Object

Create a PDF object from a raw PDF data (parsing the data).

data

is a string that represents the content of a PDF file.

Raises:

  • (TypeError)


38
39
40
41
# File 'lib/combine_pdf/api.rb', line 38

def parse(data, options = {})
  raise TypeError, "couldn't parse and data, expecting type String" unless data.is_a? String
  PDF.new(PDFParser.new(data, options))
end

.register_existing_font(font_name, font_object) ⇒ Object

adds an existing font (from any PDF Object) to the font library.

returns the font on success or false on failure.

example:

fonts = CombinePDF.new("japanese_fonts.pdf").fonts(true)
CombinePDF.register_font_from_pdf_object :david, fonts[0]

VERY LIMITTED SUPPORT:

  • at the moment it only imports Type0 fonts.

  • also, to extract the Hash of the actual font object you were looking for, is not a trivial matter. I do it on the console.

font_name

a Symbol with the name of the font registry. if the fonts exists in the library, it will be overwritten!

font_object

a Hash in the internal format recognized by CombinePDF, that represents the font object.



163
164
165
# File 'lib/combine_pdf/api.rb', line 163

def register_existing_font(font_name, font_object)
  Fonts.register_font_from_pdf_object font_name, font_object
end

.register_font(font_name, font_metrics, font_pdf_object, font_cmap = nil) ⇒ Object

adds a correctly formatted font object to the font library.

registered fonts will remain in the library and will only be embeded in PDF objects when they are used by PDFWriter objects (for example, for numbering pages).

this function enables plug-ins to expend the font functionality of CombinePDF.

font_name

a Symbol with the name of the font. if the fonts exists in the library, it will be overwritten!

font_metrics

a Hash of font metrics, of the format char => char_width, boundingbox: [left_x, bottom_y, right_x, top_y] where char == character itself (i.e. “ ” for space). The Hash should contain a special value :missing for the metrics of missing characters. an optional :wy might be supported in the future, for up to down fonts.

font_pdf_object

a Hash in the internal format recognized by CombinePDF, that represents the font object.

font_cmap

a CMap dictionary Hash) which maps unicode characters to the hex CID for the font (i.e. {“a” => “61”, “z” => “7a” }).



146
147
148
# File 'lib/combine_pdf/api.rb', line 146

def register_font(font_name, font_metrics, font_pdf_object, font_cmap = nil)
  Fonts.register_font font_name, font_metrics, font_pdf_object, font_cmap
end

.register_font_from_pdf_object(font_name, font_object) ⇒ Object



167
168
169
# File 'lib/combine_pdf/api.rb', line 167

def register_font_from_pdf_object(font_name, font_object)
  register_existing_font font_name, font_object
end