pdf-core 0.8.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|