hexapdf 0.2.0 → 0.3.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 +4 -4
- data/CHANGELOG.md +33 -1
- data/CONTRIBUTERS +1 -1
- data/LICENSE +1 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/hexapdf.rb +1 -1
- data/lib/hexapdf/cli.rb +19 -52
- data/lib/hexapdf/cli/command.rb +251 -0
- data/lib/hexapdf/cli/{extract.rb → files.rb} +19 -23
- data/lib/hexapdf/cli/images.rb +147 -0
- data/lib/hexapdf/cli/info.rb +5 -5
- data/lib/hexapdf/cli/inspect.rb +13 -12
- data/lib/hexapdf/cli/merge.rb +200 -0
- data/lib/hexapdf/cli/modify.rb +39 -242
- data/lib/hexapdf/cli/optimize.rb +104 -0
- data/lib/hexapdf/configuration.rb +1 -1
- data/lib/hexapdf/content.rb +1 -1
- data/lib/hexapdf/content/canvas.rb +1 -1
- data/lib/hexapdf/content/color_space.rb +1 -1
- data/lib/hexapdf/content/graphic_object.rb +1 -1
- data/lib/hexapdf/content/graphic_object/arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/content/graphics_state.rb +1 -1
- data/lib/hexapdf/content/operator.rb +1 -1
- data/lib/hexapdf/content/parser.rb +16 -15
- data/lib/hexapdf/content/processor.rb +1 -1
- data/lib/hexapdf/content/transformation_matrix.rb +1 -1
- data/lib/hexapdf/data_dir.rb +1 -1
- data/lib/hexapdf/dictionary.rb +1 -1
- data/lib/hexapdf/dictionary_fields.rb +1 -1
- data/lib/hexapdf/document.rb +1 -1
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +1 -1
- data/lib/hexapdf/document/images.rb +1 -1
- data/lib/hexapdf/document/pages.rb +1 -1
- data/lib/hexapdf/encryption.rb +1 -1
- data/lib/hexapdf/encryption/aes.rb +1 -1
- data/lib/hexapdf/encryption/arc4.rb +1 -1
- data/lib/hexapdf/encryption/fast_aes.rb +1 -1
- data/lib/hexapdf/encryption/fast_arc4.rb +1 -1
- data/lib/hexapdf/encryption/identity.rb +1 -1
- data/lib/hexapdf/encryption/ruby_aes.rb +1 -1
- data/lib/hexapdf/encryption/ruby_arc4.rb +1 -1
- data/lib/hexapdf/encryption/security_handler.rb +1 -1
- data/lib/hexapdf/encryption/standard_security_handler.rb +1 -1
- data/lib/hexapdf/error.rb +1 -1
- data/lib/hexapdf/filter.rb +1 -1
- data/lib/hexapdf/filter/ascii85_decode.rb +1 -1
- data/lib/hexapdf/filter/ascii_hex_decode.rb +1 -1
- data/lib/hexapdf/filter/dct_decode.rb +1 -1
- data/lib/hexapdf/filter/encryption.rb +1 -1
- data/lib/hexapdf/filter/flate_decode.rb +1 -1
- data/lib/hexapdf/filter/jpx_decode.rb +1 -1
- data/lib/hexapdf/filter/lzw_decode.rb +2 -3
- data/lib/hexapdf/filter/predictor.rb +11 -11
- data/lib/hexapdf/filter/run_length_decode.rb +1 -1
- data/lib/hexapdf/font/cmap.rb +1 -1
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/cmap/writer.rb +1 -1
- data/lib/hexapdf/font/encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/base.rb +1 -1
- data/lib/hexapdf/font/encoding/difference_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/glyph_list.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_expert_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/mac_roman_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/standard_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/symbol_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/win_ansi_encoding.rb +1 -1
- data/lib/hexapdf/font/encoding/zapf_dingbats_encoding.rb +1 -1
- data/lib/hexapdf/font/true_type.rb +2 -1
- data/lib/hexapdf/font/true_type/font.rb +1 -1
- data/lib/hexapdf/font/true_type/subsetter.rb +186 -0
- data/lib/hexapdf/font/true_type/table.rb +8 -4
- data/lib/hexapdf/font/true_type/table/cmap.rb +1 -1
- data/lib/hexapdf/font/true_type/table/cmap_subtable.rb +1 -1
- data/lib/hexapdf/font/true_type/table/directory.rb +1 -1
- data/lib/hexapdf/font/true_type/table/glyf.rb +6 -2
- data/lib/hexapdf/font/true_type/table/head.rb +2 -2
- data/lib/hexapdf/font/true_type/table/hhea.rb +1 -1
- data/lib/hexapdf/font/true_type/table/hmtx.rb +1 -1
- data/lib/hexapdf/font/true_type/table/loca.rb +1 -1
- data/lib/hexapdf/font/true_type/table/maxp.rb +1 -1
- data/lib/hexapdf/font/true_type/table/name.rb +1 -1
- data/lib/hexapdf/font/true_type/table/os2.rb +1 -1
- data/lib/hexapdf/font/true_type/table/post.rb +1 -1
- data/lib/hexapdf/font/true_type_wrapper.rb +56 -8
- data/lib/hexapdf/font/type1.rb +1 -1
- data/lib/hexapdf/font/type1/afm_parser.rb +1 -1
- data/lib/hexapdf/font/type1/character_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/font.rb +1 -1
- data/lib/hexapdf/font/type1/font_metrics.rb +1 -1
- data/lib/hexapdf/font/type1/pfb_parser.rb +1 -1
- data/lib/hexapdf/font/type1_wrapper.rb +1 -1
- data/lib/hexapdf/font_loader.rb +1 -1
- data/lib/hexapdf/font_loader/from_configuration.rb +6 -3
- data/lib/hexapdf/font_loader/standard14.rb +1 -1
- data/lib/hexapdf/image_loader.rb +1 -1
- data/lib/hexapdf/image_loader/jpeg.rb +1 -1
- data/lib/hexapdf/image_loader/pdf.rb +1 -1
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/importer.rb +1 -1
- data/lib/hexapdf/name_tree_node.rb +1 -1
- data/lib/hexapdf/number_tree_node.rb +1 -1
- data/lib/hexapdf/object.rb +1 -1
- data/lib/hexapdf/parser.rb +1 -1
- data/lib/hexapdf/rectangle.rb +1 -1
- data/lib/hexapdf/reference.rb +1 -1
- data/lib/hexapdf/revision.rb +1 -1
- data/lib/hexapdf/revisions.rb +13 -15
- data/lib/hexapdf/serializer.rb +7 -3
- data/lib/hexapdf/stream.rb +1 -1
- data/lib/hexapdf/task.rb +1 -1
- data/lib/hexapdf/task/dereference.rb +1 -1
- data/lib/hexapdf/task/optimize.rb +1 -1
- data/lib/hexapdf/tokenizer.rb +12 -12
- data/lib/hexapdf/type.rb +1 -1
- data/lib/hexapdf/type/catalog.rb +1 -1
- data/lib/hexapdf/type/embedded_file.rb +1 -1
- data/lib/hexapdf/type/file_specification.rb +1 -1
- data/lib/hexapdf/type/font.rb +1 -1
- data/lib/hexapdf/type/font_descriptor.rb +1 -1
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_true_type.rb +1 -1
- data/lib/hexapdf/type/font_type1.rb +1 -1
- data/lib/hexapdf/type/form.rb +1 -1
- data/lib/hexapdf/type/graphics_state_parameter.rb +1 -1
- data/lib/hexapdf/type/image.rb +187 -1
- data/lib/hexapdf/type/info.rb +1 -1
- data/lib/hexapdf/type/names.rb +1 -1
- data/lib/hexapdf/type/object_stream.rb +1 -1
- data/lib/hexapdf/type/page.rb +1 -1
- data/lib/hexapdf/type/page_tree_node.rb +6 -1
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +2 -2
- data/lib/hexapdf/type/viewer_preferences.rb +1 -1
- data/lib/hexapdf/type/xref_stream.rb +22 -18
- data/lib/hexapdf/utils/bit_field.rb +1 -1
- data/lib/hexapdf/utils/bit_stream.rb +16 -32
- data/lib/hexapdf/utils/lru_cache.rb +1 -1
- data/lib/hexapdf/utils/math_helpers.rb +1 -1
- data/lib/hexapdf/utils/object_hash.rb +1 -1
- data/lib/hexapdf/utils/pdf_doc_encoding.rb +1 -1
- data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
- data/lib/hexapdf/version.rb +2 -2
- data/lib/hexapdf/writer.rb +2 -1
- data/lib/hexapdf/xref_section.rb +6 -1
- data/man/man1/hexapdf.1 +194 -115
- data/test/data/images/greyscale-1bit.png +0 -0
- data/test/data/images/greyscale-2bit.png +0 -0
- data/test/data/images/greyscale-8bit.png +0 -0
- data/test/data/images/indexed-alpha-4bit.png +0 -0
- data/test/data/images/truecolour-8bit.png +0 -0
- data/test/hexapdf/content/test_operator.rb +8 -8
- data/test/hexapdf/content/test_processor.rb +1 -1
- data/test/hexapdf/encryption/test_security_handler.rb +1 -1
- data/test/hexapdf/font/test_true_type_wrapper.rb +89 -48
- data/test/hexapdf/font/true_type/table/test_glyf.rb +1 -0
- data/test/hexapdf/font/true_type/test_subsetter.rb +70 -0
- data/test/hexapdf/font/true_type/test_table.rb +16 -0
- data/test/hexapdf/font_loader/test_from_configuration.rb +7 -0
- data/test/hexapdf/test_document.rb +1 -1
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_revisions.rb +34 -8
- data/test/hexapdf/test_serializer.rb +3 -0
- data/test/hexapdf/test_writer.rb +11 -2
- data/test/hexapdf/test_xref_section.rb +15 -0
- data/test/hexapdf/type/test_image.rb +234 -0
- data/test/hexapdf/type/test_object_stream.rb +2 -2
- data/test/hexapdf/type/test_trailer.rb +4 -0
- data/test/hexapdf/utils/test_bit_stream.rb +69 -0
- metadata +14 -6
data/lib/hexapdf/object.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/parser.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/rectangle.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/reference.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/revision.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/revisions.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -62,24 +62,22 @@ module HexaPDF
|
|
|
62
62
|
|
|
63
63
|
parser = Parser.new(io, document)
|
|
64
64
|
object_loader = lambda {|xref_entry| parser.load_object(xref_entry)}
|
|
65
|
-
revision_loader = lambda do |offset|
|
|
66
|
-
xref_section, trailer = parser.load_revision(offset)
|
|
67
|
-
Revision.new(document.wrap(trailer, type: :XXTrailer), xref_section: xref_section,
|
|
68
|
-
loader: object_loader)
|
|
69
|
-
end
|
|
70
65
|
|
|
71
|
-
revisions = [
|
|
66
|
+
revisions = []
|
|
67
|
+
xref_section, trailer = parser.load_revision(parser.startxref_offset)
|
|
68
|
+
revisions << Revision.new(document.wrap(trailer, type: :XXTrailer),
|
|
69
|
+
xref_section: xref_section, loader: object_loader)
|
|
70
|
+
|
|
72
71
|
|
|
73
|
-
|
|
74
|
-
while i >= 0
|
|
72
|
+
while (prev = revisions[0].trailer.value[:Prev])
|
|
75
73
|
# PDF1.7 s7.5.5 states that :Prev needs to be indirect, Adobe's reference 3.4.4 says it
|
|
76
74
|
# should be direct. Adobe's POV is followed here. Same with :XRefStm.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
revisions.
|
|
82
|
-
|
|
75
|
+
xref_section, trailer = parser.load_revision(prev)
|
|
76
|
+
stm = revisions[0].trailer.value[:XRefStm]
|
|
77
|
+
stm_xref_section, = parser.load_revision(stm) if stm
|
|
78
|
+
xref_section.merge!(stm_xref_section) if stm
|
|
79
|
+
revisions.unshift(Revision.new(document.wrap(trailer, type: :XXTrailer),
|
|
80
|
+
xref_section: xref_section, loader: object_loader))
|
|
83
81
|
end
|
|
84
82
|
|
|
85
83
|
document.version = parser.file_header_version
|
data/lib/hexapdf/serializer.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -96,6 +96,7 @@ module HexaPDF
|
|
|
96
96
|
@encrypter = false
|
|
97
97
|
@io = nil
|
|
98
98
|
@object = nil
|
|
99
|
+
@in_object = false
|
|
99
100
|
end
|
|
100
101
|
|
|
101
102
|
# Returns the serialized form of the given object.
|
|
@@ -267,10 +268,13 @@ module HexaPDF
|
|
|
267
268
|
# Uses #serialize_hexapdf_reference if it is an indirect object, otherwise just serializes
|
|
268
269
|
# the objects value.
|
|
269
270
|
def serialize_hexapdf_object(obj)
|
|
270
|
-
if obj.indirect? && obj != @object
|
|
271
|
+
if obj.indirect? && (obj != @object || @in_object)
|
|
271
272
|
serialize_hexapdf_reference(obj)
|
|
272
273
|
else
|
|
273
|
-
|
|
274
|
+
@in_object ||= (obj == @object)
|
|
275
|
+
str = __serialize(obj.value)
|
|
276
|
+
@in_object = false if obj == @object
|
|
277
|
+
str
|
|
274
278
|
end
|
|
275
279
|
end
|
|
276
280
|
|
data/lib/hexapdf/stream.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/task.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/tokenizer.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -108,40 +108,40 @@ module HexaPDF
|
|
|
108
108
|
def next_token
|
|
109
109
|
prepare_string_scanner(20)
|
|
110
110
|
prepare_string_scanner(20) while @ss.skip(WHITESPACE_MULTI_RE)
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
byte = @ss.string.getbyte(@ss.pos) || -1
|
|
112
|
+
if (48 <= byte && byte <= 57) || byte == 45 || byte == 43 || byte == 46 # 0..9 - + .
|
|
113
113
|
parse_number
|
|
114
|
-
|
|
114
|
+
elsif byte == 47 # /
|
|
115
115
|
parse_name
|
|
116
|
-
|
|
116
|
+
elsif byte == 40 # (
|
|
117
117
|
parse_literal_string
|
|
118
|
-
|
|
118
|
+
elsif byte == 60 # <
|
|
119
119
|
if @ss.string.getbyte(@ss.pos + 1) != 60
|
|
120
120
|
parse_hex_string
|
|
121
121
|
else
|
|
122
122
|
@ss.pos += 2
|
|
123
123
|
TOKEN_DICT_START
|
|
124
124
|
end
|
|
125
|
-
|
|
125
|
+
elsif byte == 62 # >
|
|
126
126
|
unless @ss.string.getbyte(@ss.pos + 1) == 62
|
|
127
127
|
raise HexaPDF::MalformedPDFError.new("Delimiter '>' found at invalid position", pos: pos)
|
|
128
128
|
end
|
|
129
129
|
@ss.pos += 2
|
|
130
130
|
TOKEN_DICT_END
|
|
131
|
-
|
|
131
|
+
elsif byte == 91 # [
|
|
132
132
|
@ss.pos += 1
|
|
133
133
|
TOKEN_ARRAY_START
|
|
134
|
-
|
|
134
|
+
elsif byte == 93 # ]
|
|
135
135
|
@ss.pos += 1
|
|
136
136
|
TOKEN_ARRAY_END
|
|
137
|
-
|
|
137
|
+
elsif byte == 123 || byte == 125 # { }
|
|
138
138
|
Token.new(@ss.get_byte)
|
|
139
|
-
|
|
139
|
+
elsif byte == 37 # %
|
|
140
140
|
until @ss.skip_until(/(?=[\r\n])/)
|
|
141
141
|
return NO_MORE_TOKENS unless prepare_string_scanner
|
|
142
142
|
end
|
|
143
143
|
next_token
|
|
144
|
-
|
|
144
|
+
elsif byte == -1 # we reached the end of the file
|
|
145
145
|
NO_MORE_TOKENS
|
|
146
146
|
else # everything else consisting of regular characters
|
|
147
147
|
parse_keyword
|
data/lib/hexapdf/type.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/type/catalog.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/type/font.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/type/form.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
data/lib/hexapdf/type/image.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# This file is part of HexaPDF.
|
|
5
5
|
#
|
|
6
6
|
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
-
# Copyright (C)
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
8
|
#
|
|
9
9
|
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
10
|
# under the terms of the GNU Affero General Public License version 3 as
|
|
@@ -31,7 +31,10 @@
|
|
|
31
31
|
# is created or manipulated using HexaPDF.
|
|
32
32
|
#++
|
|
33
33
|
|
|
34
|
+
require 'zlib'
|
|
35
|
+
require 'hexapdf/error'
|
|
34
36
|
require 'hexapdf/stream'
|
|
37
|
+
require 'hexapdf/image_loader'
|
|
35
38
|
|
|
36
39
|
module HexaPDF
|
|
37
40
|
module Type
|
|
@@ -41,6 +44,10 @@ module HexaPDF
|
|
|
41
44
|
# See: PDF1.7 s8.8
|
|
42
45
|
class Image < Stream
|
|
43
46
|
|
|
47
|
+
# The structure that is returned by the Image#info method.
|
|
48
|
+
Info = Struct.new(:type, :width, :height, :color_space, :indexed, :components,
|
|
49
|
+
:bits_per_component, :writable, :extension)
|
|
50
|
+
|
|
44
51
|
define_field :Type, type: Symbol, default: :XObject
|
|
45
52
|
define_field :Subtype, type: Symbol, required: true, default: :Image
|
|
46
53
|
define_field :Width, type: Integer, required: true
|
|
@@ -67,6 +74,185 @@ module HexaPDF
|
|
|
67
74
|
# facility and not when the image is part of a loaded PDF file.
|
|
68
75
|
attr_accessor :source_path
|
|
69
76
|
|
|
77
|
+
# Returns an Info structure with information about the image.
|
|
78
|
+
#
|
|
79
|
+
# Available accessors:
|
|
80
|
+
#
|
|
81
|
+
# type::
|
|
82
|
+
# The type of the image. Either :jpeg, :jp2, :jbig2, :ccitt or :png.
|
|
83
|
+
# width::
|
|
84
|
+
# The width of the image.
|
|
85
|
+
# height::
|
|
86
|
+
# The height of the image.
|
|
87
|
+
# color_space::
|
|
88
|
+
# The color space the image uses. Either :rgb, :cmyk, :gray or :other.
|
|
89
|
+
# indexed::
|
|
90
|
+
# Whether the image uses an indexed color space or not.
|
|
91
|
+
# components::
|
|
92
|
+
# The number of color components of the color space, or -1 if the number couldn't be
|
|
93
|
+
# determined.
|
|
94
|
+
# bits_per_component::
|
|
95
|
+
# The number of bits per color component.
|
|
96
|
+
# writable::
|
|
97
|
+
# Whether the image can be written by HexaPDF.
|
|
98
|
+
# extension::
|
|
99
|
+
# The file extension that would be used when writing the file. Either jpg, jpx or png. Only
|
|
100
|
+
# meaningful when writable is true.
|
|
101
|
+
def info
|
|
102
|
+
result = Info.new
|
|
103
|
+
result.width = self[:Width]
|
|
104
|
+
result.height = self[:Height]
|
|
105
|
+
result.bits_per_component = self[:BitsPerComponent]
|
|
106
|
+
result.indexed = false
|
|
107
|
+
result.writable = true
|
|
108
|
+
|
|
109
|
+
filter, rest = *self[:Filter]
|
|
110
|
+
case filter
|
|
111
|
+
when :DCTDecode
|
|
112
|
+
result.type = :jpeg
|
|
113
|
+
result.extension = 'jpg'.freeze
|
|
114
|
+
when :JPXDecode
|
|
115
|
+
result.type = :jp2
|
|
116
|
+
result.extension = 'jpx'.freeze
|
|
117
|
+
when :JBIG2Decode
|
|
118
|
+
result.type = :jbig2
|
|
119
|
+
when :CCITTFaxDecode
|
|
120
|
+
result.type = :ccitt
|
|
121
|
+
else
|
|
122
|
+
result.type = :png
|
|
123
|
+
result.extension = 'png'.freeze
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
if rest || ![:FlateDecode, :DCTDecode, :JPXDecode, nil].include?(filter)
|
|
127
|
+
result.writable = false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
color_space, = *self[:ColorSpace]
|
|
131
|
+
if color_space == :Indexed
|
|
132
|
+
result.indexed = true
|
|
133
|
+
color_space, = *document.deref(self[:ColorSpace][1])
|
|
134
|
+
end
|
|
135
|
+
case color_space
|
|
136
|
+
when :DeviceRGB, :CalRGB
|
|
137
|
+
result.color_space = :rgb
|
|
138
|
+
result.components = 3
|
|
139
|
+
when :DeviceGray, :CalGray
|
|
140
|
+
result.color_space = :gray
|
|
141
|
+
result.components = 1
|
|
142
|
+
when :DeviceCMYK
|
|
143
|
+
result.color_space = :cmyk
|
|
144
|
+
result.components = 4
|
|
145
|
+
result.writable = false if result.type == :png
|
|
146
|
+
else
|
|
147
|
+
result.color_space = :other
|
|
148
|
+
result.components = -1
|
|
149
|
+
result.writable = false if result.type == :png
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
result
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# :call-seq:
|
|
156
|
+
# image.write(basename)
|
|
157
|
+
# image.write(io)
|
|
158
|
+
#
|
|
159
|
+
# Saves this image XObject to the file with the given name and appends the correct extension
|
|
160
|
+
# (if the name already contains this extension, the name is used as is), or the given IO
|
|
161
|
+
# object.
|
|
162
|
+
#
|
|
163
|
+
# Raises an error if the image format is not supported.
|
|
164
|
+
#
|
|
165
|
+
# The output format and extension depends on the image type as returned by the #info method:
|
|
166
|
+
#
|
|
167
|
+
# :jpeg:: Saved as a JPEG file with the extension '.jpg'
|
|
168
|
+
# :jp2:: Saved as a JPEG2000 file with the extension '.jpx'
|
|
169
|
+
# :png:: Saved as a PNG file with the extension '.png'
|
|
170
|
+
def write(name_or_io)
|
|
171
|
+
info = self.info
|
|
172
|
+
|
|
173
|
+
unless info.writable
|
|
174
|
+
raise HexaPDF::Error, "PDF image format not supported for writing"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
io = if name_or_io.kind_of?(String)
|
|
178
|
+
File.open(name_or_io.sub(/\.#{info.extension}\z/, '') + "." + info.extension, "wb")
|
|
179
|
+
else
|
|
180
|
+
name_or_io
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
if info.type == :jpeg || info.type == :jp2
|
|
184
|
+
source = stream_source
|
|
185
|
+
while source.alive? && (chunk = source.resume)
|
|
186
|
+
io << chunk
|
|
187
|
+
end
|
|
188
|
+
else
|
|
189
|
+
write_png(io, info)
|
|
190
|
+
end
|
|
191
|
+
ensure
|
|
192
|
+
io.close if io && name_or_io.kind_of?(String)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
private
|
|
196
|
+
|
|
197
|
+
# Writes the image as PNG to the given IO stream.
|
|
198
|
+
def write_png(io, info)
|
|
199
|
+
io << ImageLoader::PNG::MAGIC_FILE_MARKER
|
|
200
|
+
|
|
201
|
+
color_type = if info.indexed
|
|
202
|
+
ImageLoader::PNG::INDEXED
|
|
203
|
+
elsif info.color_space == :rgb
|
|
204
|
+
ImageLoader::PNG::TRUECOLOR
|
|
205
|
+
else
|
|
206
|
+
ImageLoader::PNG::GREYSCALE
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
io << png_chunk('IHDR', [info.width, info.height, info.bits_per_component,
|
|
210
|
+
color_type, 0, 0, 0].pack('N2C5'))
|
|
211
|
+
|
|
212
|
+
if key?(:Intent)
|
|
213
|
+
# PNG s11.3.3.5
|
|
214
|
+
intent = ImageLoader::PNG::RENDERING_INTENT_MAP.rassoc(self[:Intent]).first
|
|
215
|
+
io << png_chunk('sRGB', intent.chr) <<
|
|
216
|
+
png_chunk('gAMA', [45455].pack('N')) <<
|
|
217
|
+
png_chunk('cHRM', [31270, 32900, 64000, 33000, 30000, 60000, 15000, 6000].pack('N8'))
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
if color_type == ImageLoader::PNG::INDEXED
|
|
221
|
+
palette_data = document.deref(self[:ColorSpace][3])
|
|
222
|
+
palette_data = palette_data.stream unless palette_data.kind_of?(String)
|
|
223
|
+
palette = ''.b
|
|
224
|
+
if info.color_space == :rgb
|
|
225
|
+
palette = palette_data[0, palette_data.length - palette_data.length % 3]
|
|
226
|
+
else
|
|
227
|
+
palette_data.each_byte {|byte| palette << byte << byte << byte}
|
|
228
|
+
end
|
|
229
|
+
io << png_chunk('PLTE', palette)
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
if self[:Mask].kind_of?(Array) && self[:Mask].each_slice(2).all? {|a, b| a == b} &&
|
|
233
|
+
(color_type == ImageLoader::PNG::TRUECOLOR || color_type == ImageLoader::PNG::GREYSCALE)
|
|
234
|
+
io << png_chunk('tRNS', self[:Mask].each_slice(2).map {|a, _| a}.pack('n*'))
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
filter, = *self[:Filter]
|
|
238
|
+
if filter == :FlateDecode && self[:DecodeParms] && self[:DecodeParms][:Predictor].to_i >= 10
|
|
239
|
+
data = stream_source
|
|
240
|
+
else
|
|
241
|
+
flate_decode = GlobalConfiguration.constantize('filter.map', :FlateDecode)
|
|
242
|
+
data = flate_decode.encoder(stream_decoder, Predictor: 15, Colors: 1, Columns: info.width,
|
|
243
|
+
BitsPerComponent: info.bits_per_component)
|
|
244
|
+
end
|
|
245
|
+
io << png_chunk('IDAT', Filter.string_from_source(data))
|
|
246
|
+
|
|
247
|
+
io << png_chunk('IEND', '')
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Returns the binary representation of the PNG chunk for the given chunk type and data.
|
|
251
|
+
def png_chunk(type, data = nil)
|
|
252
|
+
[data.to_s.length].pack("N") << type << data.to_s <<
|
|
253
|
+
[Zlib.crc32(data, Zlib.crc32(type))].pack("N")
|
|
254
|
+
end
|
|
255
|
+
|
|
70
256
|
end
|
|
71
257
|
|
|
72
258
|
end
|