combine_pdf 0.1.23 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +8 -8
- data/combine_pdf.gemspec +1 -1
- data/lib/combine_pdf.rb +22 -19
- data/lib/combine_pdf/{combine_pdf_methods.rb → api.rb} +16 -83
- data/lib/combine_pdf/basic_writer.rb +62 -0
- data/lib/combine_pdf/{combine_pdf_decrypt.rb → decrypt.rb} +35 -2
- data/lib/combine_pdf/{combine_pdf_filter.rb → filter.rb} +0 -0
- data/lib/combine_pdf/{combine_pdf_fonts.rb → fonts.rb} +19 -8
- data/lib/combine_pdf/{combine_pdf_operations.rb → operations.rb} +1 -10
- data/lib/combine_pdf/{combine_pdf_page.rb → page_methods.rb} +284 -23
- data/lib/combine_pdf/{combine_pdf_parser.rb → parser.rb} +200 -15
- data/lib/combine_pdf/pdf_protected.rb +141 -0
- data/lib/combine_pdf/pdf_public.rb +402 -0
- data/lib/combine_pdf/renderer.rb +168 -0
- data/lib/combine_pdf/version.rb +1 -1
- metadata +15 -13
- data/lib/combine_pdf/combine_pdf_basic_writer.rb +0 -451
- data/lib/combine_pdf/combine_pdf_pdf.rb +0 -724
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4bac3486fb9fc968d2ca625eb4ad9c0f9423cc7
|
4
|
+
data.tar.gz: 5d7d3b20987af05c2cf71c2513bf09418125cae3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cb03d4476aa78f13d783142c9f91263814d5c9dce299ceb5728dddc79cac0253f4d45ea048953dc69b04fa4ad8416926cd09f05c124ba3b6f3169b827fed86be
|
7
|
+
data.tar.gz: c3dbbfc3716b9caa49ffc1b98282a266d20ebf66a126d2cd7d8a06699ed196a97491a51ad425e1d0d4dcc940eb87721e5114b9aed3d2511b4f0ae33ec05ebb6a
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,18 @@
|
|
2
2
|
|
3
3
|
***
|
4
4
|
|
5
|
+
Change log v.0.2.0
|
6
|
+
|
7
|
+
Refractoring of code and API overhall.
|
8
|
+
|
9
|
+
Any code relying on inner/advanced API calls might be broken.
|
10
|
+
|
11
|
+
**fix**: fixed an object numbering issue introduced by duplicating pages. The issue didn't seem to effect readers nor performance.
|
12
|
+
|
13
|
+
**fix**: combine_pdf will now properly raise an error when Optional Content Groups (OCG's) are implemented in a PDF file. Page extraction isn't supported for PDF files with OCG's.
|
14
|
+
|
15
|
+
***
|
16
|
+
|
5
17
|
Change log v.0.1.23
|
6
18
|
|
7
19
|
**fix**: @kruszczynski fixed an issue with CombinePDF::PDF#number_pages where the page numbering margines were ignored and only the default values were used. Thank you @kruszczynski .
|
data/README.md
CHANGED
@@ -15,15 +15,15 @@ To combine PDF files (or data):
|
|
15
15
|
|
16
16
|
```ruby
|
17
17
|
pdf = CombinePDF.new
|
18
|
-
pdf << CombinePDF.
|
19
|
-
pdf << CombinePDF.
|
18
|
+
pdf << CombinePDF.load("file1.pdf") # one way to combine, very fast.
|
19
|
+
pdf << CombinePDF.load("file2.pdf")
|
20
20
|
pdf.save "combined.pdf"
|
21
21
|
```
|
22
22
|
|
23
23
|
Or even a one liner:
|
24
24
|
|
25
25
|
```ruby
|
26
|
-
(CombinePDF.
|
26
|
+
(CombinePDF.load("file1.pdf") << CombinePDF.load("file2.pdf") << CombinePDF.load("file3.pdf")).save("combined.pdf")
|
27
27
|
```
|
28
28
|
|
29
29
|
you can also add just odd or even pages:
|
@@ -31,7 +31,7 @@ you can also add just odd or even pages:
|
|
31
31
|
```ruby
|
32
32
|
pdf = CombinePDF.new
|
33
33
|
i = 0
|
34
|
-
CombinePDF.
|
34
|
+
CombinePDF.load("file.pdf").pages.each do |page|
|
35
35
|
i += 1
|
36
36
|
pdf << page if i.even?
|
37
37
|
end
|
@@ -46,8 +46,8 @@ To add content to existing PDF pages, first import the new content from an exist
|
|
46
46
|
In this example, we will add a company logo to each page:
|
47
47
|
|
48
48
|
```ruby
|
49
|
-
company_logo = CombinePDF.
|
50
|
-
pdf = CombinePDF.
|
49
|
+
company_logo = CombinePDF.load("company_logo.pdf").pages[0]
|
50
|
+
pdf = CombinePDF.load "content_file.pdf"
|
51
51
|
pdf.pages.each {|page| page << company_logo} # notice the << operator is on a page and not a PDF object.
|
52
52
|
pdf.save "content_with_logo.pdf"
|
53
53
|
```
|
@@ -65,7 +65,7 @@ pdf.pages(nil, false).each {|page| page << stamp_page}
|
|
65
65
|
adding page numbers to a PDF object or file is as simple as can be:
|
66
66
|
|
67
67
|
```ruby
|
68
|
-
pdf = CombinePDF.
|
68
|
+
pdf = CombinePDF.load "file_to_number.pdf"
|
69
69
|
pdf.number_pages
|
70
70
|
pdf.save "file_with_numbering.pdf"
|
71
71
|
```
|
@@ -79,7 +79,7 @@ Loading PDF data can be done from file system or directly from the memory.
|
|
79
79
|
Loading data from a file is easy:
|
80
80
|
|
81
81
|
```ruby
|
82
|
-
pdf = CombinePDF.
|
82
|
+
pdf = CombinePDF.load("file.pdf")
|
83
83
|
```
|
84
84
|
|
85
85
|
you can also parse PDF files from memory:
|
data/combine_pdf.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Boaz Segev"]
|
10
10
|
spec.email = ["boaz@2be.co.il"]
|
11
11
|
spec.summary = %q{Combine, stamp and watermark PDF files in pure Ruby.}
|
12
|
-
spec.description = %q{A nifty gem, in pure Ruby, to parse PDF files and combine (merge) them with other PDF files, number the pages, watermark them or stamp them, create tables
|
12
|
+
spec.description = %q{A nifty gem, in pure Ruby, to parse PDF files and combine (merge) them with other PDF files, number the pages, watermark them or stamp them, create tables, add basic text objects etc` (all using the PDF file format).}
|
13
13
|
spec.homepage = "https://github.com/boazsegev/combine_pdf"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
data/lib/combine_pdf.rb
CHANGED
@@ -9,17 +9,20 @@ require 'matrix'
|
|
9
9
|
require 'rc4'
|
10
10
|
|
11
11
|
|
12
|
-
load "combine_pdf/
|
13
|
-
load "combine_pdf/
|
14
|
-
load "combine_pdf/
|
15
|
-
load "combine_pdf/
|
16
|
-
load "combine_pdf/
|
17
|
-
load "combine_pdf/
|
18
|
-
load "combine_pdf/
|
19
|
-
load "combine_pdf/
|
20
|
-
|
12
|
+
load "combine_pdf/api.rb"
|
13
|
+
load "combine_pdf/renderer.rb"
|
14
|
+
load "combine_pdf/page_methods.rb"
|
15
|
+
load "combine_pdf/basic_writer.rb"
|
16
|
+
load "combine_pdf/decrypt.rb"
|
17
|
+
load "combine_pdf/fonts.rb"
|
18
|
+
load "combine_pdf/filter.rb"
|
19
|
+
load "combine_pdf/parser.rb"
|
20
|
+
load "combine_pdf/pdf_public.rb"
|
21
|
+
load "combine_pdf/pdf_protected.rb"
|
21
22
|
|
22
|
-
load "combine_pdf/
|
23
|
+
# load "combine_pdf/operations.rb"
|
24
|
+
|
25
|
+
load "combine_pdf/version.rb"
|
23
26
|
|
24
27
|
|
25
28
|
# This is a pure ruby library to combine/merge, stmap/overlay and number PDF files - as well as to create tables (ment for indexing combined files).
|
@@ -33,22 +36,22 @@ load "combine_pdf/combine_pdf_methods.rb"
|
|
33
36
|
# Loading PDF data can be done from file system or directly from the memory.
|
34
37
|
#
|
35
38
|
# Load data from a file:
|
36
|
-
# pdf = CombinePDF.
|
39
|
+
# pdf = CombinePDF.load("file.pdf")
|
37
40
|
# parse PDF files from memory:
|
38
41
|
# pdf = CombinePDF.parse(pdf_data)
|
39
42
|
#
|
40
43
|
# == Combine/Merge PDF files or Pages
|
41
44
|
# To combine PDF files (or data):
|
42
45
|
# pdf = CombinePDF.new
|
43
|
-
# pdf << CombinePDF.
|
44
|
-
# pdf << CombinePDF.
|
46
|
+
# pdf << CombinePDF.load("file1.pdf")
|
47
|
+
# pdf << CombinePDF.load("file2.pdf")
|
45
48
|
# pdf.save "combined.pdf"
|
46
49
|
#
|
47
50
|
# It is possible to add only specific pages.
|
48
51
|
# in this example, only even pages will be added:
|
49
52
|
# pdf = CombinePDF.new
|
50
53
|
# i = 0
|
51
|
-
# CombinePDF.
|
54
|
+
# CombinePDF.load("file.pdf").pages.each do |page|
|
52
55
|
# i += 1
|
53
56
|
# pdf << page if i.even?
|
54
57
|
# end
|
@@ -56,14 +59,14 @@ load "combine_pdf/combine_pdf_methods.rb"
|
|
56
59
|
# Notice that adding the whole file is faster then adding each page seperately.
|
57
60
|
# == Add content to existing pages (Stamp / Watermark)
|
58
61
|
# It is possible "stamp" one PDF page using another PDF page. In this example, a company logo will be stamped over each page:
|
59
|
-
# company_logo = CombinePDF.
|
60
|
-
# pdf = CombinePDF.
|
62
|
+
# company_logo = CombinePDF.load("company_logo.pdf").pages[0]
|
63
|
+
# pdf = CombinePDF.load "content_file.pdf"
|
61
64
|
# pdf.pages.each {|page| page << company_logo}
|
62
65
|
# pdf.save "content_with_logo.pdf"
|
63
66
|
# Notice the << operator is on a page and not a PDF object. The << operator acts differently on PDF objects and on Pages.
|
64
67
|
# == Page Numbering
|
65
68
|
# It is possible to number the pages. in this example we will add very simple numbering:
|
66
|
-
# pdf = CombinePDF.
|
69
|
+
# pdf = CombinePDF.load "file_to_number.pdf"
|
67
70
|
# pdf.number_pages
|
68
71
|
# pdf.save "file_with_numbering.pdf"
|
69
72
|
#
|
@@ -73,13 +76,13 @@ load "combine_pdf/combine_pdf_methods.rb"
|
|
73
76
|
#
|
74
77
|
# in this example, all the PDF pages will be stamped, along the top, with a red box, with blue text, stating "Draft, page #".
|
75
78
|
# here is the easy way (we can even use "number_pages" without page numbers, if we wish):
|
76
|
-
# pdf = CombinePDF.
|
79
|
+
# pdf = CombinePDF.load "file_to_stamp.pdf"
|
77
80
|
# pdf.number_pages number_format: " - Draft, page %d - ", number_location: [:top], font_color: [0,0,1], box_color: [0.4,0,0], opacity: 0.75, font_size:16
|
78
81
|
# pdf.save "draft.pdf"
|
79
82
|
#
|
80
83
|
# in this example we will add a first page with the word "Draft", in red over a colored background:
|
81
84
|
#
|
82
|
-
# pdf = CombinePDF.
|
85
|
+
# pdf = CombinePDF.load "file.pdf"
|
83
86
|
# pdf_first_page = pdf.pages[0]
|
84
87
|
# mediabox = page[:CropBox] || page[:MediaBox] #copy page size
|
85
88
|
# title_page = CombinePDF.create_page mediabox #make title page same size as first page
|
@@ -10,12 +10,22 @@ module CombinePDF
|
|
10
10
|
# Create an empty PDF object or create a PDF object from a file (parsing the file).
|
11
11
|
# file_name:: is the name of a file to be parsed.
|
12
12
|
def load(file_name = "")
|
13
|
-
raise TypeError, "couldn't parse
|
13
|
+
raise TypeError, "couldn't parse data, expecting type String" unless file_name.is_a?(String) || file_name.is_a?(Pathname)
|
14
14
|
return PDF.new() if file_name == ''
|
15
15
|
PDF.new( PDFParser.new( IO.read(file_name, mode: 'rb').force_encoding(Encoding::ASCII_8BIT) ) )
|
16
16
|
end
|
17
|
-
|
18
|
-
|
17
|
+
# creats a new PDF object.
|
18
|
+
#
|
19
|
+
# Combine PDF will check to see if `string` is a filename.
|
20
|
+
# 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`.
|
21
|
+
#
|
22
|
+
# If the string is empty it will return a new PDF object (the same as parse).
|
23
|
+
#
|
24
|
+
# For both performance and code readability reasons, `CombinePDF.load` and `CombinePDF.parse` should be preffered unless creating a new PDF object.
|
25
|
+
def new(string = false)
|
26
|
+
return PDF.new unless string
|
27
|
+
raise TypeError, "couldn't create PDF object, expecting type String" unless string.is_a?(String) || string.is_a?(Pathname)
|
28
|
+
(File.file? string rescue false) ? load(string) : parse(string)
|
19
29
|
end
|
20
30
|
|
21
31
|
# Create a PDF object from a raw PDF data (parsing the data).
|
@@ -50,11 +60,11 @@ module CombinePDF
|
|
50
60
|
# 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"] ]
|
51
61
|
# pdf.save "table_file.pdf"
|
52
62
|
#
|
53
|
-
# accepts a Hash with any of the following keys as well as any of the
|
63
|
+
# accepts a Hash with any of the following keys as well as any of the Page_Methods#textbox options:
|
54
64
|
# headers:: an Array of strings with the headers (will be repeated every page).
|
55
65
|
# 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.
|
56
|
-
# font:: a registered or standard font name (see
|
57
|
-
# header_font:: a registered or standard font name for the headers (see
|
66
|
+
# font:: a registered or standard font name (see Page_Methods). defaults to nil (:Helvetica).
|
67
|
+
# header_font:: a registered or standard font name for the headers (see Page_Methods). defaults to nil (the font for all the table rows).
|
58
68
|
# max_font_size:: the maximum font size. if the string doesn't fit, it will be resized. defaults to 14.
|
59
69
|
# 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).
|
60
70
|
# header_color:: the header color. defaults to [0.8, 0.8, 0.8] (light gray).
|
@@ -80,83 +90,6 @@ module CombinePDF
|
|
80
90
|
table << page
|
81
91
|
end
|
82
92
|
table
|
83
|
-
|
84
|
-
# defaults = {
|
85
|
-
# headers: nil,
|
86
|
-
# table_data: [[]],
|
87
|
-
# font: nil,
|
88
|
-
# header_font: nil,
|
89
|
-
# max_font_size: 14,
|
90
|
-
# column_widths: nil,
|
91
|
-
# header_color: [0.8, 0.8, 0.8],
|
92
|
-
# main_color: nil,
|
93
|
-
# alternate_color: [0.95, 0.95, 0.95],
|
94
|
-
# font_color: [0,0,0],
|
95
|
-
# border_color: [0,0,0],
|
96
|
-
# border_width: 1,
|
97
|
-
# header_align: :center,
|
98
|
-
# row_align: nil,
|
99
|
-
# direction: :ltr,
|
100
|
-
# rows_per_page: 25,
|
101
|
-
# page_size: [0, 0, 595.3, 841.9] #A4
|
102
|
-
# }
|
103
|
-
# options = defaults.merge options
|
104
|
-
# options[:header_font] = options[:font] unless options[:header_font]
|
105
|
-
# options[:row_align] ||= ( (options[:direction] == :rtl) ? :right : :left )
|
106
|
-
# # assert table_data is an array of arrays
|
107
|
-
# return false unless (options[:table_data].select {|r| !r.is_a?(Array) }).empty?
|
108
|
-
# # compute sizes
|
109
|
-
# page_size = options[:page_size]
|
110
|
-
# top = page_size[3] * 0.9
|
111
|
-
# height = page_size[3] * 0.8 / options[:rows_per_page]
|
112
|
-
# from_side = page_size[2] * 0.1
|
113
|
-
# width = page_size[2] * 0.8
|
114
|
-
# columns = options[:table_data][0].length
|
115
|
-
# column_widths = []
|
116
|
-
# columns.times {|i| column_widths << (width/columns) }
|
117
|
-
# if options[:column_widths]
|
118
|
-
# scale = 0
|
119
|
-
# options[:column_widths].each {|w| scale += w}
|
120
|
-
# column_widths = []
|
121
|
-
# options[:column_widths].each { |w| column_widths << (width*w/scale) }
|
122
|
-
# end
|
123
|
-
# column_widths = column_widths.reverse if options[:direction] == :rtl
|
124
|
-
# # set pdf object and start writing the data
|
125
|
-
# table = PDF.new()
|
126
|
-
# page = nil
|
127
|
-
# rows_per_page = options[:rows_per_page]
|
128
|
-
# row_number = rows_per_page + 1
|
129
|
-
|
130
|
-
# options[:table_data].each do |row_data|
|
131
|
-
# if row_number > rows_per_page
|
132
|
-
# page = create_page page_size
|
133
|
-
# table << page
|
134
|
-
# row_number = 1
|
135
|
-
# # add headers
|
136
|
-
# if options[:headers]
|
137
|
-
# x = from_side
|
138
|
-
# headers = options[:headers]
|
139
|
-
# headers = headers.reverse if options[:direction] == :rtl
|
140
|
-
# column_widths.each_index do |i|
|
141
|
-
# text = headers[i].to_s
|
142
|
-
# page.textbox text, {x: x, y: (top - (height*row_number)), width: column_widths[i], height: height, box_color: options[:header_color], text_align: options[:header_align] }.merge(options).merge({font: options[:header_font]})
|
143
|
-
# x += column_widths[i]
|
144
|
-
# end
|
145
|
-
# row_number += 1
|
146
|
-
# end
|
147
|
-
# end
|
148
|
-
# x = from_side
|
149
|
-
# row_data = row_data.reverse if options[:direction] == :rtl
|
150
|
-
# column_widths.each_index do |i|
|
151
|
-
# text = row_data[i].to_s
|
152
|
-
# box_color = options[:main_color]
|
153
|
-
# box_color = options[:alternate_color] if options[:alternate_color] && row_number.odd?
|
154
|
-
# page.textbox text, {x: x, y: (top - (height*row_number)), width: column_widths[i], height: height, box_color: box_color, text_align: options[:row_align]}.merge(options)
|
155
|
-
# x += column_widths[i]
|
156
|
-
# end
|
157
|
-
# row_number += 1
|
158
|
-
# end
|
159
|
-
# table
|
160
93
|
end
|
161
94
|
def new_table(options = {})
|
162
95
|
create_table options
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
########################################################
|
3
|
+
## Thoughts from reading the ISO 32000-1:2008
|
4
|
+
## this file is part of the CombinePDF library and the code
|
5
|
+
## is subject to the same license.
|
6
|
+
########################################################
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
module CombinePDF
|
12
|
+
|
13
|
+
# Limited Unicode Support (font dependent)!
|
14
|
+
#
|
15
|
+
# The PDFWriter class is a subclass of Hash and represents a PDF Page object.
|
16
|
+
#
|
17
|
+
# Writing on this Page is done using the textbox function.
|
18
|
+
#
|
19
|
+
# Setting the page dimensions can be either at the new or using the mediabox method. New pages default to size A4, which is: [0, 0, 595.3, 841.9].
|
20
|
+
#
|
21
|
+
# Once the Page is completed (the last text box was added),
|
22
|
+
# we can insert the page to a CombinePDF object.
|
23
|
+
#
|
24
|
+
# We can either insert the PDFWriter as a new page:
|
25
|
+
# pdf = CombinePDF.new
|
26
|
+
# new_page = CombinePDF.create_page # => PDFWriter object
|
27
|
+
# new_page.textbox "some text"
|
28
|
+
# pdf << new_page
|
29
|
+
# pdf.save "file_with_new_page.pdf"
|
30
|
+
#
|
31
|
+
# Or we can use the Page_Methods methods to write an overlay (stamp / watermark) over existing pages:
|
32
|
+
# pdf = CombinePDF.new
|
33
|
+
# new_page = PDFWriter.new "some_file.pdf"
|
34
|
+
# pdf.pages.each {|page| page.textbox "Draft", opacity: 0.4 }
|
35
|
+
# pdf.save "stamped_file.pdf"
|
36
|
+
class PDFWriter < Hash
|
37
|
+
|
38
|
+
# create a new PDFWriter object.
|
39
|
+
#
|
40
|
+
# mediabox:: the PDF page size in PDF points. defaults to [0, 0, 595.3, 841.9] (A4)
|
41
|
+
def initialize(mediabox = [0, 0, 595.3, 841.9])
|
42
|
+
# indirect_reference_id, :indirect_generation_number
|
43
|
+
@contents = ""
|
44
|
+
@base_font_name = "Writer" + SecureRandom.hex(7) + "PDF"
|
45
|
+
self[:Type] = :Page
|
46
|
+
self[:indirect_reference_id] = 0
|
47
|
+
self[:Resources] = {}
|
48
|
+
self[:Contents] = { is_reference_only: true , referenced_object: {indirect_reference_id: 0, raw_stream_content: @contents} }
|
49
|
+
self[:MediaBox] = mediabox
|
50
|
+
end
|
51
|
+
|
52
|
+
# includes the PDF Page_Methods module, including all page methods (textbox etc').
|
53
|
+
include Page_Methods
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
|
@@ -34,7 +34,7 @@ module CombinePDF
|
|
34
34
|
0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A ]
|
35
35
|
@key_crypt_first_iv_store = nil
|
36
36
|
@encryption_iv = nil
|
37
|
-
|
37
|
+
change_references_to_actual_values @encryption_dictionary
|
38
38
|
end
|
39
39
|
|
40
40
|
# call this to start the decryption.
|
@@ -142,6 +142,9 @@ module CombinePDF
|
|
142
142
|
cipher.padding = 0
|
143
143
|
(cipher.update(encrypted) + cipher.final).unpack("C*")
|
144
144
|
end
|
145
|
+
|
146
|
+
protected
|
147
|
+
|
145
148
|
def _perform_decrypt_proc_ (object, decrypt_proc, encrypted_id = nil, encrypted_generation = nil, encrypted_filter = nil)
|
146
149
|
case
|
147
150
|
when object.is_a?(Array)
|
@@ -153,7 +156,7 @@ module CombinePDF
|
|
153
156
|
if object[:raw_stream_content]
|
154
157
|
stream_length = object[:Length]
|
155
158
|
if stream_length.is_a?(Hash) && stream_length[:is_reference_only]
|
156
|
-
stream_length =
|
159
|
+
stream_length = get_refernced_object(stream_length)[:indirect_without_dictionary]
|
157
160
|
end
|
158
161
|
actual_length = object[:raw_stream_content].length
|
159
162
|
warn "Stream registeded length was #{object[:Length].to_s} and the actual length was #{actual_length}." if actual_length < stream_length
|
@@ -174,6 +177,36 @@ module CombinePDF
|
|
174
177
|
warn "Data raising exception:\n #{object.to_s.split(',').join("\n")}"
|
175
178
|
raise "File is encrypted - not supported."
|
176
179
|
end
|
180
|
+
|
181
|
+
def change_references_to_actual_values(hash_with_references = {})
|
182
|
+
hash_with_references.each do |k,v|
|
183
|
+
if v.is_a?(Hash) && v[:is_reference_only]
|
184
|
+
hash_with_references[k] = get_refernced_object(v)
|
185
|
+
hash_with_references[k] = hash_with_references[k][:indirect_without_dictionary] if hash_with_references[k].is_a?(Hash) && hash_with_references[k][:indirect_without_dictionary]
|
186
|
+
warn "Couldn't connect all values from references - didn't find reference #{hash_with_references}!!!" if hash_with_references[k] == nil
|
187
|
+
hash_with_references[k] = v unless hash_with_references[k]
|
188
|
+
end
|
189
|
+
end
|
190
|
+
hash_with_references
|
191
|
+
end
|
192
|
+
def get_refernced_object(reference_hash = {})
|
193
|
+
@objects.each do |stored_object|
|
194
|
+
return stored_object if ( stored_object.is_a?(Hash) &&
|
195
|
+
reference_hash[:indirect_reference_id] == stored_object[:indirect_reference_id] &&
|
196
|
+
reference_hash[:indirect_generation_number] == stored_object[:indirect_generation_number] )
|
197
|
+
end
|
198
|
+
warn "didn't find reference #{reference_hash}"
|
199
|
+
nil
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
# # returns the PDF Object Hash holding the acutal data (if exists) or the original hash (if it wasn't a reference)
|
204
|
+
# #
|
205
|
+
# # works only AFTER references have been connected.
|
206
|
+
# def get_referenced object
|
207
|
+
# object[:referenced_object] || object
|
208
|
+
# end
|
209
|
+
|
177
210
|
end
|
178
211
|
#####################################################
|
179
212
|
## The following isn't my code!!!!
|
File without changes
|
@@ -18,6 +18,7 @@ module CombinePDF
|
|
18
18
|
|
19
19
|
|
20
20
|
module Fonts
|
21
|
+
extend Renderer
|
21
22
|
|
22
23
|
protected
|
23
24
|
|
@@ -53,7 +54,7 @@ module CombinePDF
|
|
53
54
|
# This function translate a unicode string, to a character glyph ID stream.
|
54
55
|
def encode text
|
55
56
|
# FixMe: embed RTL text convertion
|
56
|
-
return
|
57
|
+
return format_string_to_pdf(text) unless self.cmap
|
57
58
|
coded_array = text.chars.map do |c|
|
58
59
|
if self.cmap[c]
|
59
60
|
self.cmap[c]
|
@@ -91,14 +92,24 @@ module CombinePDF
|
|
91
92
|
FONTS_LIBRARY.keys
|
92
93
|
end
|
93
94
|
|
94
|
-
# gets
|
95
|
-
def
|
95
|
+
# gets the original font object from the fonts library (this allows you to edit the font).
|
96
|
+
def get_original_font(name = :Helvetica)
|
96
97
|
initiate_library
|
97
98
|
FONTS_LIBRARY[name]
|
98
99
|
end
|
99
100
|
|
101
|
+
# gets a copy of the font object from the fonts library (this allows you to use the font as an object is a PDF file, without altering the original registered font).
|
102
|
+
def get_font(name = :Helvetica)
|
103
|
+
initiate_library
|
104
|
+
font = FONTS_LIBRARY[name]
|
105
|
+
return nil unless font
|
106
|
+
font = font.dup
|
107
|
+
font[:referenced_object] = font[:referenced_object].dup if font[:referenced_object]
|
108
|
+
font
|
109
|
+
end
|
110
|
+
|
100
111
|
# adds a correctly formatted font object to the font library.
|
101
|
-
# font_name:: a Symbol with the name of the font. if the fonts exists,
|
112
|
+
# font_name:: a Symbol with the name of the font. if the fonts name exists, the font will be overwritten!
|
102
113
|
# font_metrics:: a Hash of ont metrics, of the format char => {wx: char_width, boundingbox: [left_x, buttom_y, right_x, top_y]} where i == character code (i.e. 32 for space). The Hash should contain a special value :missing for the metrics of missing characters. an optional :wy will be supported in the future, for up to down fonts.
|
103
114
|
# font_pdf_object:: a Hash in the internal format recognized by CombinePDF, that represents the font object.
|
104
115
|
# font_cmap:: a CMap dictionary Hash) which maps unicode characters to the hex CID for the font (i.e. {"a" => "61", "z" => "7a" }).
|
@@ -125,9 +136,9 @@ module CombinePDF
|
|
125
136
|
merged_metrics = {}
|
126
137
|
# merge the metrics last to first (so that important fonts override secondary fonts)
|
127
138
|
fonts.length.downto(1).each do |i|
|
128
|
-
f =
|
139
|
+
f = get_original_font(fonts[i-1])
|
129
140
|
if f && f.metrics
|
130
|
-
merged_metrics.update(
|
141
|
+
merged_metrics.update( get_original_font(fonts[i-1]).metrics)
|
131
142
|
else
|
132
143
|
warn "metrics of font not found!"
|
133
144
|
end
|
@@ -212,7 +223,7 @@ module CombinePDF
|
|
212
223
|
to_unicode = font_object[:ToUnicode]
|
213
224
|
to_unicode = to_unicode[:referenced_object] if to_unicode[:is_reference_only]
|
214
225
|
# deflate the cmap file stream before parsing
|
215
|
-
to_unicode =
|
226
|
+
to_unicode = create_deep_copy to_unicode
|
216
227
|
CombinePDF::PDFFilter.inflate_object to_unicode
|
217
228
|
# parse the deflated stream
|
218
229
|
cmap = self.parse_cmap to_unicode[:raw_stream_content]
|
@@ -241,7 +252,7 @@ module CombinePDF
|
|
241
252
|
if old_widths[:W]
|
242
253
|
old_widths = old_widths[:W]
|
243
254
|
old_widths = old_widths[:referenced_object][:indirect_without_dictionary] if old_widths[:is_reference_only]
|
244
|
-
old_widths =
|
255
|
+
old_widths = create_deep_copy old_widths
|
245
256
|
while old_widths[0] do
|
246
257
|
a = old_widths.shift
|
247
258
|
b = old_widths.shift
|