pdf-core 0.8.1 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/lib/pdf/core/annotations.rb +51 -13
- data/lib/pdf/core/byte_string.rb +3 -2
- data/lib/pdf/core/destinations.rb +64 -24
- data/lib/pdf/core/document_state.rb +100 -17
- data/lib/pdf/core/filter_list.rb +44 -5
- data/lib/pdf/core/filters.rb +26 -7
- data/lib/pdf/core/graphics_state.rb +74 -30
- data/lib/pdf/core/literal_string.rb +9 -10
- data/lib/pdf/core/name_tree.rb +76 -16
- data/lib/pdf/core/object_store.rb +69 -19
- data/lib/pdf/core/outline_item.rb +53 -5
- data/lib/pdf/core/outline_root.rb +18 -2
- data/lib/pdf/core/page.rb +158 -32
- data/lib/pdf/core/page_geometry.rb +4 -58
- data/lib/pdf/core/pdf_object.rb +62 -37
- data/lib/pdf/core/reference.rb +58 -15
- data/lib/pdf/core/renderer.rb +116 -47
- data/lib/pdf/core/stream.rb +43 -7
- data/lib/pdf/core/text.rb +255 -106
- data/lib/pdf/core/utils.rb +10 -1
- data/lib/pdf/core.rb +26 -16
- data/pdf-core.gemspec +31 -27
- data.tar.gz.sig +0 -0
- metadata +36 -101
- metadata.gz.sig +2 -1
- data/Gemfile +0 -5
- data/Rakefile +0 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 23799dd91a7e3063a84724ecbdea6989de1b7131f1727bc6923c76b1637f0a87
|
4
|
+
data.tar.gz: 73538fe3357a195e9c3a39f7dfb1e498d0c3a49fc3c8cc6b4b0e72cc054dbd54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e90a4a8303c8633452743ad491b21c57034551beb284458da03c0c69d135c41bcfe349027ed7ded6bf55e71f8f7dee0997898342cea7f4ed8725bdb1de1182fc
|
7
|
+
data.tar.gz: 5d048fdd3adf42181118c0340a2df17ec60e9c32e92f4699bc7e2929d508ee70d5d7888ce7d9a8b12ec06aae8423158ff184321f87aa10449f8ddc721b239f22
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data/lib/pdf/core/annotations.rb
CHANGED
@@ -10,10 +10,43 @@ module PDF
|
|
10
10
|
module Core
|
11
11
|
# Provides very low-level support for annotations.
|
12
12
|
#
|
13
|
-
|
14
|
-
|
15
|
-
#
|
13
|
+
# @api private
|
14
|
+
module Annotations
|
15
|
+
# Adds a new annotation (section *8.4 Annotations* in PDF 1.7 spec) to the
|
16
|
+
# current page.
|
16
17
|
#
|
18
|
+
# @param options [Hash] Annotation options. This is basically an `Annot`
|
19
|
+
# dict as decribed in the PDF spec.
|
20
|
+
# @option options [Symbol<:Text, :Link, :FreeText, :Line, :Square,
|
21
|
+
# :Circle, :Polygon, :PolyLine, :Highlight, :Underline, :Squiggly,
|
22
|
+
# :StrikeOut, :Stamp, :Caret, :Ink, :Popup, :FileAttachment, :Sound,
|
23
|
+
# :Movie, :Widget, :Screen, :PrinterMark, :TrapNet, :Watermark, :3D>]
|
24
|
+
# :Subtype The type of annotation
|
25
|
+
# @option options [Array<Numeric, 4>] :Rect The annotation rectangle
|
26
|
+
# @option options [String] :Contents Text to be displayed for the
|
27
|
+
# annotation or, if this type of annotation does not display text, an
|
28
|
+
# alternate description of the annotation's contents in human-readable
|
29
|
+
# form.
|
30
|
+
# @option options [PDF::Core::Reference] :P An indirect reference to the
|
31
|
+
# page object with which this annotation is associated.
|
32
|
+
# @option options [String] :NM The annotation name, a text string uniquely
|
33
|
+
# identifying it among all the annotations on its page.
|
34
|
+
# @option options [Date, Time, String] :M The date and time when the
|
35
|
+
# annotation was most recently modified
|
36
|
+
# @option options [Integer] :F A set of flags specifying various
|
37
|
+
# characteristics of the annotation
|
38
|
+
# @option options [Hash] :AP An appearance dictionary specifying how the
|
39
|
+
# annotation is presented visually on the page
|
40
|
+
# @option options [Symbol] :AS The annotation's appearance state
|
41
|
+
# @option options [Array<(Numeric, Array<Numeric>)>] :Border the
|
42
|
+
# characteristics of the annotation's border
|
43
|
+
# @option options [Array<Float>] :C Color
|
44
|
+
# @option options [Integer] :StructParent The integer key of the
|
45
|
+
# annotation's entry in the structural parent tree
|
46
|
+
# @option options [Hash] :OC An optional content group or optional content
|
47
|
+
# membership dictionary
|
48
|
+
#
|
49
|
+
# @return [options]
|
17
50
|
def annotate(options)
|
18
51
|
state.page.dictionary.data[:Annots] ||= []
|
19
52
|
options = sanitize_annotation_hash(options)
|
@@ -21,23 +54,28 @@ module PDF
|
|
21
54
|
options
|
22
55
|
end
|
23
56
|
|
24
|
-
# A convenience method for creating Text annotations.
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
57
|
+
# A convenience method for creating `Text` annotations.
|
58
|
+
#
|
59
|
+
# @param rect [Array<Numeric>] An array of four numbers,
|
60
|
+
# describing the bounds of the annotation.
|
61
|
+
# @param contents [String] Contents of the annotation
|
28
62
|
#
|
63
|
+
# @return [Hash] Annotation dictionary
|
29
64
|
def text_annotation(rect, contents, options = {})
|
30
65
|
options = options.merge(Subtype: :Text, Rect: rect, Contents: contents)
|
31
66
|
annotate(options)
|
32
67
|
end
|
33
68
|
|
34
|
-
# A convenience method for creating Link annotations.
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
69
|
+
# A convenience method for creating `Link` annotations.
|
70
|
+
#
|
71
|
+
# @param rect [Array<Numeric>] An array of four numbers,
|
72
|
+
# describing the bounds of the annotation.
|
73
|
+
# @param options [Hash] Should include either `:Dest` (describing the target
|
74
|
+
# destination, usually as a string that has been recorded in the
|
75
|
+
# document's `Dests` tree), or `:A` (describing an action to perform on
|
76
|
+
# clicking the link), or `:PA` (for describing a URL to link to).
|
40
77
|
#
|
78
|
+
# @return [Hash] Annotation dictionary
|
41
79
|
def link_annotation(rect, options = {})
|
42
80
|
options = options.merge(Subtype: :Link, Rect: rect)
|
43
81
|
annotate(options)
|
data/lib/pdf/core/byte_string.rb
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
-
|
2
1
|
# frozen_string_literal: true
|
3
2
|
|
4
3
|
module PDF
|
5
4
|
module Core
|
6
5
|
# This is used to differentiate strings that must be encoded as
|
7
6
|
# a byte string, such as binary data from encrypted strings.
|
8
|
-
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class ByteString < String
|
9
10
|
end
|
10
11
|
end
|
11
12
|
end
|
@@ -1,90 +1,130 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# Implements destination support for PDF
|
4
|
-
#
|
5
|
-
# Copyright November 2008, Jamis Buck. All Rights Reserved.
|
6
|
-
#
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
-
|
9
3
|
module PDF
|
10
4
|
module Core
|
11
|
-
|
5
|
+
# Implements destination support for PDF
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
module Destinations
|
12
9
|
# The maximum number of children to fit into a single node in the Dests
|
13
10
|
# tree.
|
14
|
-
|
11
|
+
#
|
12
|
+
# @private
|
13
|
+
NAME_TREE_CHILDREN_LIMIT = 20
|
15
14
|
|
16
|
-
# The Dests name tree in the Name dictionary
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# 3.8.4 in the PDF spec.)
|
15
|
+
# The `:Dests` name tree in the Name dictionary. This name tree is used to
|
16
|
+
# store named destinations (PDF 1.7 spec 8.2.1). (For more on name trees,
|
17
|
+
# see section 3.8.5 in the PDF 1.7 spec.)
|
20
18
|
#
|
19
|
+
# @return [PDF::Core::Reference<PDF::Core::NameTree::Node>]
|
20
|
+
# @see Prawn::Document::Internal#names
|
21
21
|
def dests
|
22
22
|
names.data[:Dests] ||= ref!(
|
23
|
-
PDF::Core::NameTree::Node.new(self, NAME_TREE_CHILDREN_LIMIT)
|
23
|
+
PDF::Core::NameTree::Node.new(self, NAME_TREE_CHILDREN_LIMIT),
|
24
24
|
)
|
25
25
|
end
|
26
26
|
|
27
|
-
# Adds a new destination to the
|
28
|
-
# +reference+ parameter will be converted into a PDF::Core::Reference if
|
29
|
-
# it is not already one.
|
27
|
+
# Adds a new destination to the Dests name tree.
|
30
28
|
#
|
29
|
+
# @param name [Symbol] Destination name
|
30
|
+
# @param reference [PDF::Core::Reference, Array, Hash] Destination
|
31
|
+
# definition, will be converted into a {PDF::Core::Reference} if it is
|
32
|
+
# not already one.
|
33
|
+
# @return [void]
|
34
|
+
# @see #dests
|
31
35
|
def add_dest(name, reference)
|
32
36
|
reference = ref!(reference) unless reference.is_a?(PDF::Core::Reference)
|
33
37
|
dests.data.add(name, reference)
|
34
38
|
end
|
35
39
|
|
36
|
-
#
|
40
|
+
# Builds a Dest specification for a specific location (and optional zoom
|
37
41
|
# level).
|
38
42
|
#
|
43
|
+
# @param left [Numeric]
|
44
|
+
# @param top [Numeric]
|
45
|
+
# @param zoom [Numeric]
|
46
|
+
# @param dest_page [PDF::Core::Page]
|
47
|
+
# @return [Array(PDF::Core::Reference, :XYZ, Numeric, Numeric, [Numeric, null])] a Dest
|
48
|
+
# specification for a specific location
|
39
49
|
def dest_xyz(left, top, zoom = nil, dest_page = page)
|
40
50
|
[dest_page.dictionary, :XYZ, left, top, zoom]
|
41
51
|
end
|
42
52
|
|
43
|
-
#
|
53
|
+
# builds a Dest specification that will fit the given page into the
|
44
54
|
# viewport.
|
45
55
|
#
|
56
|
+
# @param dest_page [PDF::Core::Page]
|
57
|
+
# @return [Array(PDF::Core::Reference, :Fit)] a Dest specification for a page fitting
|
58
|
+
# viewport
|
46
59
|
def dest_fit(dest_page = page)
|
47
60
|
[dest_page.dictionary, :Fit]
|
48
61
|
end
|
49
62
|
|
50
|
-
#
|
63
|
+
# Builds a Dest specification that will fit the given page horizontally
|
51
64
|
# into the viewport, aligned vertically at the given top coordinate.
|
52
65
|
#
|
66
|
+
# @param top [Numeric]
|
67
|
+
# @param dest_page [PDF::Core::Page]
|
68
|
+
# @return [Array(PDF::Core::Reference, :FitH, Numeric)] a Dest specification for a page
|
69
|
+
# content fitting horizontally at a given top coordinate
|
53
70
|
def dest_fit_horizontally(top, dest_page = page)
|
54
71
|
[dest_page.dictionary, :FitH, top]
|
55
72
|
end
|
56
73
|
|
57
|
-
#
|
74
|
+
# Build a Dest specification that will fit the given page vertically
|
58
75
|
# into the viewport, aligned horizontally at the given left coordinate.
|
59
76
|
#
|
77
|
+
# @param left [Numeric]
|
78
|
+
# @param dest_page [PDF::Core::Page]
|
79
|
+
# @return [Array(Hash, :FitV, Numeric)] a Dest specification for a page
|
80
|
+
# content fitting vertically at a given left coordinate
|
60
81
|
def dest_fit_vertically(left, dest_page = page)
|
61
82
|
[dest_page.dictionary, :FitV, left]
|
62
83
|
end
|
63
84
|
|
64
|
-
#
|
85
|
+
# Builds a Dest specification that will fit the given rectangle into the
|
65
86
|
# viewport, for the given page.
|
66
87
|
#
|
88
|
+
# @param left [Numeric]
|
89
|
+
# @param bottom [Numeric]
|
90
|
+
# @param right [Numeric]
|
91
|
+
# @param top [Numeric]
|
92
|
+
# @param dest_page [PDF::Core::Page]
|
93
|
+
# @return [Array(Hash, :FitR, Numeric, Numeric, Numeric, Numeric)]
|
94
|
+
# a Dest specification for a page fitting the given rectangle in the
|
95
|
+
# viewport
|
67
96
|
def dest_fit_rect(left, bottom, right, top, dest_page = page)
|
68
97
|
[dest_page.dictionary, :FitR, left, bottom, right, top]
|
69
98
|
end
|
70
99
|
|
71
|
-
#
|
100
|
+
# Builds a Dest specification that will fit the given page's bounding box
|
72
101
|
# into the viewport.
|
73
102
|
#
|
103
|
+
# @param dest_page [PDF::Core::Page]
|
104
|
+
# @return [Array(PDF::Core::Reference, :FitB)] a Dest specification for a page fitting
|
105
|
+
# bounding box into viewport
|
74
106
|
def dest_fit_bounds(dest_page = page)
|
75
107
|
[dest_page.dictionary, :FitB]
|
76
108
|
end
|
77
109
|
|
78
|
-
# Same as #dest_fit_horizontally, but works on the page's bounding box
|
110
|
+
# Same as {#dest_fit_horizontally}, but works on the page's bounding box
|
79
111
|
# instead of the entire page.
|
80
112
|
#
|
113
|
+
# @param top [Numeric]
|
114
|
+
# @param dest_page [PDF::Core::Page]
|
115
|
+
# @return [Array(PDF::Core::Reference, :FitBH, Numeric)] a Dest specification for a page
|
116
|
+
# bounding box fitting horizontally at a given top coordinate
|
81
117
|
def dest_fit_bounds_horizontally(top, dest_page = page)
|
82
118
|
[dest_page.dictionary, :FitBH, top]
|
83
119
|
end
|
84
120
|
|
85
|
-
# Same as #dest_fit_vertically, but works on the page's bounding box
|
121
|
+
# Same as {#dest_fit_vertically}, but works on the page's bounding box
|
86
122
|
# instead of the entire page.
|
87
123
|
#
|
124
|
+
# @param left [Numeric]
|
125
|
+
# @param dest_page [PDF::Core::Page]
|
126
|
+
# @return [Array(PDF::Core::Reference, :FitBV, Numeric)] a Dest specification for a page
|
127
|
+
# bounding box fitting vertically at a given top coordinate
|
88
128
|
def dest_fit_bounds_vertically(left, dest_page = page)
|
89
129
|
[dest_page.dictionary, :FitBV, left]
|
90
130
|
end
|
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
module PDF
|
4
4
|
module Core
|
5
|
-
|
5
|
+
# Low-level PDF document representation mostly for keeping intermediate
|
6
|
+
# state while document is being constructed.
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
class DocumentState
|
10
|
+
# @param options [Hash<Symbol, any>]
|
11
|
+
# @option options :info [Hash] Document's information dictionary
|
12
|
+
# @option options :print_scaling [:none, nil] Viewr preference for
|
13
|
+
# printing scaling
|
14
|
+
# @option options :trailer [Hash] ({}) File trailer
|
15
|
+
# @option options :compress [Boolean] (false) Whether to compress streams
|
16
|
+
# @option options :encrypt [Boolean] (false) Whether to encrypt the
|
17
|
+
# document
|
18
|
+
# @option options :encryption_key [String] (nil) Encryption key. Must be
|
19
|
+
# provided if `:encrypt` is `true`
|
6
20
|
def initialize(options)
|
7
21
|
normalize_metadata(options)
|
8
22
|
|
@@ -10,38 +24,87 @@ module PDF
|
|
10
24
|
if options[:print_scaling]
|
11
25
|
PDF::Core::ObjectStore.new(
|
12
26
|
info: options[:info],
|
13
|
-
print_scaling: options[:print_scaling]
|
27
|
+
print_scaling: options[:print_scaling],
|
14
28
|
)
|
15
29
|
else
|
16
30
|
PDF::Core::ObjectStore.new(info: options[:info])
|
17
31
|
end
|
18
32
|
|
19
|
-
@version
|
20
|
-
@pages
|
21
|
-
@page
|
22
|
-
@trailer
|
23
|
-
@compress
|
24
|
-
@encrypt
|
25
|
-
@encryption_key
|
26
|
-
@skip_encoding
|
33
|
+
@version = 1.3
|
34
|
+
@pages = []
|
35
|
+
@page = nil
|
36
|
+
@trailer = options.fetch(:trailer, {})
|
37
|
+
@compress = options.fetch(:compress, false)
|
38
|
+
@encrypt = options.fetch(:encrypt, false)
|
39
|
+
@encryption_key = options[:encryption_key]
|
40
|
+
@skip_encoding = options.fetch(:skip_encoding, false)
|
27
41
|
@before_render_callbacks = []
|
28
42
|
@on_page_create_callback = nil
|
29
43
|
end
|
30
44
|
|
31
|
-
|
32
|
-
|
33
|
-
|
45
|
+
# Object store
|
46
|
+
# @return [PDF::Core::ObjectStore]
|
47
|
+
attr_accessor :store
|
34
48
|
|
49
|
+
# PDF version used in this document
|
50
|
+
# @return [Float]
|
51
|
+
attr_accessor :version
|
52
|
+
|
53
|
+
# Document pages
|
54
|
+
# @return [Array<PDF::Core::Page>]
|
55
|
+
attr_accessor :pages
|
56
|
+
|
57
|
+
# Current page
|
58
|
+
# @return [PDF::Core::Page]
|
59
|
+
attr_accessor :page
|
60
|
+
|
61
|
+
# Document trailer dict
|
62
|
+
# @return [Hash]
|
63
|
+
attr_accessor :trailer
|
64
|
+
|
65
|
+
# Whether to compress streams
|
66
|
+
# @return [Boolean]
|
67
|
+
attr_accessor :compress
|
68
|
+
|
69
|
+
# Whether to encrypt document
|
70
|
+
# @return [Boolean]
|
71
|
+
attr_accessor :encrypt
|
72
|
+
|
73
|
+
# Encryption key
|
74
|
+
# @return [String, nil]
|
75
|
+
attr_accessor :encryption_key
|
76
|
+
|
77
|
+
# @deprecated Unused
|
78
|
+
attr_accessor :skip_encoding
|
79
|
+
|
80
|
+
# Before render callbacks
|
81
|
+
# @return [Array<Proc>]
|
82
|
+
attr_accessor :before_render_callbacks
|
83
|
+
|
84
|
+
# A block to call when a new page is created
|
85
|
+
# @return [Proc, nil]
|
86
|
+
attr_accessor :on_page_create_callback
|
87
|
+
|
88
|
+
# Loads pages from object store. Only does it when there are no pages
|
89
|
+
# loaded and there are some pages in the store.
|
90
|
+
#
|
91
|
+
# @return [0] if no pages were loaded
|
92
|
+
# @return [Array<PDF::Core::Page>] if pages were laded
|
35
93
|
def populate_pages_from_store(document)
|
36
94
|
return 0 if @store.page_count <= 0 || !@pages.empty?
|
37
95
|
|
38
96
|
count = (1..@store.page_count)
|
39
|
-
@pages =
|
40
|
-
|
41
|
-
|
42
|
-
|
97
|
+
@pages =
|
98
|
+
count.map { |index|
|
99
|
+
orig_dict_id = @store.object_id_for_page(index)
|
100
|
+
PDF::Core::Page.new(document, object_id: orig_dict_id)
|
101
|
+
}
|
43
102
|
end
|
44
103
|
|
104
|
+
# Adds Prawn metadata to document info
|
105
|
+
#
|
106
|
+
# @param options [Hash]
|
107
|
+
# @return [Hash] Document `info` hash
|
45
108
|
def normalize_metadata(options)
|
46
109
|
options[:info] ||= {}
|
47
110
|
options[:info][:Creator] ||= 'Prawn'
|
@@ -50,24 +113,44 @@ module PDF
|
|
50
113
|
options[:info]
|
51
114
|
end
|
52
115
|
|
116
|
+
# Insert a page at the specified position.
|
117
|
+
#
|
118
|
+
# @param page [PDF::Core::Page]
|
119
|
+
# @param page_number [Integer]
|
120
|
+
# @return [void]
|
53
121
|
def insert_page(page, page_number)
|
54
122
|
pages.insert(page_number, page)
|
55
123
|
store.pages.data[:Kids].insert(page_number, page.dictionary)
|
56
124
|
store.pages.data[:Count] += 1
|
57
125
|
end
|
58
126
|
|
127
|
+
# Execute page creation callback if one is defined
|
128
|
+
#
|
129
|
+
# @param doc [Prawn::Document]
|
130
|
+
# @return [void]
|
59
131
|
def on_page_create_action(doc)
|
60
132
|
on_page_create_callback[doc] if on_page_create_callback
|
61
133
|
end
|
62
134
|
|
135
|
+
# Executes before render callbacks
|
136
|
+
#
|
137
|
+
# @param _doc [Prawn::Document] Unused
|
138
|
+
# @return [void]
|
63
139
|
def before_render_actions(_doc)
|
64
140
|
before_render_callbacks.each { |c| c.call(self) }
|
65
141
|
end
|
66
142
|
|
143
|
+
# Number of pages in the document
|
144
|
+
#
|
145
|
+
# @return [Integer]
|
67
146
|
def page_count
|
68
147
|
pages.length
|
69
148
|
end
|
70
149
|
|
150
|
+
# Renders document body to the output
|
151
|
+
#
|
152
|
+
# @param output [#<<]
|
153
|
+
# @return [void]
|
71
154
|
def render_body(output)
|
72
155
|
store.each do |ref|
|
73
156
|
ref.offset = output.size
|
data/lib/pdf/core/filter_list.rb
CHANGED
@@ -2,11 +2,35 @@
|
|
2
2
|
|
3
3
|
module PDF
|
4
4
|
module Core
|
5
|
+
# A representation of a list of filters applied to a stream.
|
5
6
|
class FilterList
|
7
|
+
# An exception one can expect when adding something to filter list that
|
8
|
+
# can not be interpreted as a filter.
|
9
|
+
class NotFilter < StandardError
|
10
|
+
# Generic default error message
|
11
|
+
DEFAULT_MESSAGE = 'Can not interpret input as a filter'
|
12
|
+
|
13
|
+
# Error message template with more details
|
14
|
+
MESSAGE_WITH_FILTER = 'Can not interpret input as a filter: %<filter>s'
|
15
|
+
|
16
|
+
def initialize(message = DEFAULT_MESSAGE, filter: nil)
|
17
|
+
if filter
|
18
|
+
super(format(MESSAGE_WITH_FILTER, filter: filter))
|
19
|
+
else
|
20
|
+
super(message)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
6
25
|
def initialize
|
7
26
|
@list = []
|
8
27
|
end
|
9
28
|
|
29
|
+
# Appends a filter to the list
|
30
|
+
#
|
31
|
+
# @param filter [Symbol, Hash] a filter to append
|
32
|
+
# @return [self]
|
33
|
+
# @raise [NotFilter]
|
10
34
|
def <<(filter)
|
11
35
|
case filter
|
12
36
|
when Symbol
|
@@ -16,37 +40,52 @@ module PDF
|
|
16
40
|
@list << [name, params]
|
17
41
|
end
|
18
42
|
else
|
19
|
-
raise
|
43
|
+
raise NotFilter.new(filter: filter)
|
20
44
|
end
|
21
45
|
|
22
46
|
self
|
23
47
|
end
|
24
48
|
|
49
|
+
# A normalized representation of the filter list
|
50
|
+
#
|
51
|
+
# @return [Array<Array<(Symbol, [Hash, nil])>>]
|
25
52
|
def normalized
|
26
53
|
@list
|
27
54
|
end
|
28
55
|
alias to_a normalized
|
29
56
|
|
57
|
+
# Names of filters in the list
|
58
|
+
#
|
59
|
+
# @return [Array<Symbol>]
|
30
60
|
def names
|
31
61
|
@list.map do |(name, _)|
|
32
62
|
name
|
33
63
|
end
|
34
64
|
end
|
35
65
|
|
66
|
+
# Parameters of filters
|
67
|
+
#
|
68
|
+
# @return [Array<[Hash, nil]>]
|
36
69
|
def decode_params
|
37
70
|
@list.map do |(_, params)|
|
38
71
|
params
|
39
72
|
end
|
40
73
|
end
|
41
74
|
|
75
|
+
# @return [String]
|
42
76
|
def inspect
|
43
77
|
@list.inspect
|
44
78
|
end
|
45
79
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
80
|
+
# Iterates over filters
|
81
|
+
#
|
82
|
+
# @yield [(name, decode_params)] an array of filter name and decode
|
83
|
+
# parameters
|
84
|
+
# @yieldparam name [Symbol] filter name
|
85
|
+
# @yieldparam decode_params [Hash, nil] decode params
|
86
|
+
# @return [Array<Array<(Symbol, [Hash, nil])>>] normalized filter list
|
87
|
+
def each(&block)
|
88
|
+
@list.each(&block)
|
50
89
|
end
|
51
90
|
end
|
52
91
|
end
|
data/lib/pdf/core/filters.rb
CHANGED
@@ -1,32 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# prawn/core/filters.rb : Implements stream filters
|
4
|
-
#
|
5
|
-
# Copyright February 2013, Alexander Mankuta. All Rights Reserved.
|
6
|
-
#
|
7
|
-
# This is free software. Please see the LICENSE and COPYING files for details.
|
8
|
-
|
9
3
|
require 'zlib'
|
10
4
|
|
11
5
|
module PDF
|
12
6
|
module Core
|
7
|
+
# Stream filters
|
13
8
|
module Filters
|
9
|
+
# zlib/deflate compression
|
14
10
|
module FlateDecode
|
11
|
+
# Encode stream data
|
12
|
+
#
|
13
|
+
# @param stream [String] stream data
|
14
|
+
# @param _params [nil] unused, here for API compatibility
|
15
|
+
# @return [String]
|
15
16
|
def self.encode(stream, _params = nil)
|
16
17
|
Zlib::Deflate.deflate(stream)
|
17
18
|
end
|
18
19
|
|
20
|
+
# Decode stream data
|
21
|
+
#
|
22
|
+
# @param stream [String] stream data
|
23
|
+
# @param _params [nil] unused, here for API compatibility
|
24
|
+
# @return [String]
|
19
25
|
def self.decode(stream, _params = nil)
|
20
26
|
Zlib::Inflate.inflate(stream)
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
24
|
-
#
|
30
|
+
# Data encoding using DCT (discrete cosine transform) technique based on
|
31
|
+
# the JPEG standard.
|
32
|
+
#
|
33
|
+
# Pass through stub.
|
25
34
|
module DCTDecode
|
35
|
+
# Encode stream data
|
36
|
+
#
|
37
|
+
# @param stream [String] stream data
|
38
|
+
# @param _params [nil] unused, here for API compatibility
|
39
|
+
# @return [String]
|
26
40
|
def self.encode(stream, _params = nil)
|
27
41
|
stream
|
28
42
|
end
|
29
43
|
|
44
|
+
# Decode stream data
|
45
|
+
#
|
46
|
+
# @param stream [String] stream data
|
47
|
+
# @param _params [nil] unused, here for API compatibility
|
48
|
+
# @return [String]
|
30
49
|
def self.decode(stream, _params = nil)
|
31
50
|
stream
|
32
51
|
end
|