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
|
@@ -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
|
|
@@ -157,29 +157,29 @@ module HexaPDF
|
|
|
157
157
|
pos = 0
|
|
158
158
|
|
|
159
159
|
decode_row = lambda do |result|
|
|
160
|
-
line = data[pos, bytes_per_row]
|
|
160
|
+
line = data[pos + 1, bytes_per_row - 1]
|
|
161
161
|
|
|
162
|
-
case
|
|
162
|
+
case data.getbyte(pos)
|
|
163
163
|
when PREDICTOR_PNG_NONE
|
|
164
164
|
# nothing to do
|
|
165
165
|
when PREDICTOR_PNG_SUB
|
|
166
|
-
|
|
166
|
+
bytes_per_pixel.upto(bytes_per_row - 2) do |i|
|
|
167
167
|
line.setbyte(i, line.getbyte(i) + line.getbyte(i - bytes_per_pixel))
|
|
168
168
|
end
|
|
169
169
|
when PREDICTOR_PNG_UP
|
|
170
|
-
|
|
170
|
+
0.upto(bytes_per_row - 2) do |i|
|
|
171
171
|
line.setbyte(i, line.getbyte(i) + last_line.getbyte(i))
|
|
172
172
|
end
|
|
173
173
|
when PREDICTOR_PNG_AVERAGE
|
|
174
|
-
|
|
175
|
-
a = i
|
|
174
|
+
0.upto(bytes_per_row - 2) do |i|
|
|
175
|
+
a = i < bytes_per_pixel ? 0 : line.getbyte(i - bytes_per_pixel)
|
|
176
176
|
line.setbyte(i, line.getbyte(i) + ((a + last_line.getbyte(i)) >> 1))
|
|
177
177
|
end
|
|
178
178
|
when PREDICTOR_PNG_PAETH
|
|
179
|
-
|
|
180
|
-
a = i
|
|
179
|
+
0.upto(bytes_per_row - 2) do |i|
|
|
180
|
+
a = i < bytes_per_pixel ? 0 : line.getbyte(i - bytes_per_pixel)
|
|
181
181
|
b = last_line.getbyte(i)
|
|
182
|
-
c = i
|
|
182
|
+
c = i < bytes_per_pixel ? 0 : last_line.getbyte(i - bytes_per_pixel)
|
|
183
183
|
|
|
184
184
|
point = a + b - c
|
|
185
185
|
pa = (point - a).abs
|
|
@@ -192,7 +192,7 @@ module HexaPDF
|
|
|
192
192
|
end
|
|
193
193
|
end
|
|
194
194
|
|
|
195
|
-
result << line
|
|
195
|
+
result << line
|
|
196
196
|
last_line = line
|
|
197
197
|
end
|
|
198
198
|
|
|
@@ -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/font/cmap.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
|
|
@@ -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
|
|
@@ -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
|
|
@@ -44,6 +44,7 @@ module HexaPDF
|
|
|
44
44
|
module TrueType
|
|
45
45
|
|
|
46
46
|
autoload(:Font, 'hexapdf/font/true_type/font')
|
|
47
|
+
autoload(:Subsetter, 'hexapdf/font/true_type/subsetter')
|
|
47
48
|
|
|
48
49
|
end
|
|
49
50
|
|
|
@@ -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
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
#
|
|
3
|
+
#--
|
|
4
|
+
# This file is part of HexaPDF.
|
|
5
|
+
#
|
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
|
7
|
+
# Copyright (C) 2014-2017 Thomas Leitner
|
|
8
|
+
#
|
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
|
16
|
+
#
|
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
|
20
|
+
# License for more details.
|
|
21
|
+
#
|
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
|
24
|
+
#
|
|
25
|
+
# The interactive user interfaces in modified source and object code
|
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
|
28
|
+
#
|
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
|
31
|
+
# is created or manipulated using HexaPDF.
|
|
32
|
+
#++
|
|
33
|
+
|
|
34
|
+
module HexaPDF
|
|
35
|
+
module Font
|
|
36
|
+
module TrueType
|
|
37
|
+
|
|
38
|
+
# Subsets a TrueType font in the context of PDF.
|
|
39
|
+
#
|
|
40
|
+
# TrueType fonts can be embedded into PDF either as a simple font or as a composite font. This
|
|
41
|
+
# subsetter implements the functionality needed when embedding a TrueType subset for a
|
|
42
|
+
# composite font.
|
|
43
|
+
#
|
|
44
|
+
# This means in particular that the resulting font file cannot be used outside of the PDF.
|
|
45
|
+
class Subsetter
|
|
46
|
+
|
|
47
|
+
# Creates a new Subsetter for the given TrueType Font object.
|
|
48
|
+
def initialize(font)
|
|
49
|
+
@font = font
|
|
50
|
+
@glyph_map = {0 => 0}
|
|
51
|
+
@last_id = 0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Includes the glyph with the given ID in the subset and returns the new subset glyph ID.
|
|
55
|
+
#
|
|
56
|
+
# Can be called multiple times with the same glyph ID, always returning the correct new
|
|
57
|
+
# subset glyph ID.
|
|
58
|
+
def use_glyph(glyph_id)
|
|
59
|
+
return @glyph_map[glyph_id] if @glyph_map.key?(glyph_id)
|
|
60
|
+
@last_id += 1
|
|
61
|
+
@glyph_map[glyph_id] = @last_id
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Builds the subset font file and returns it as a binary string.
|
|
65
|
+
def build_font
|
|
66
|
+
glyf, locations = build_glyf_table
|
|
67
|
+
loca = build_loca_table(locations)
|
|
68
|
+
hmtx = build_hmtx_table
|
|
69
|
+
head = build_head_table(modified: Time.now, loca_type: 1)
|
|
70
|
+
hhea = build_hhea_table(@glyph_map.size)
|
|
71
|
+
maxp = build_maxp_table(@glyph_map.size)
|
|
72
|
+
|
|
73
|
+
tables = {
|
|
74
|
+
'head' => head,
|
|
75
|
+
'hhea' => hhea,
|
|
76
|
+
'maxp' => maxp,
|
|
77
|
+
'glyf' => glyf,
|
|
78
|
+
'loca' => loca,
|
|
79
|
+
'hmtx' => hmtx,
|
|
80
|
+
}
|
|
81
|
+
tables['cvt '] = @font[:"cvt "].raw_data if @font[:"cvt "]
|
|
82
|
+
tables['fpgm'] = @font[:fpgm].raw_data if @font[:fpgm]
|
|
83
|
+
tables['prep'] = @font[:prep].raw_data if @font[:prep]
|
|
84
|
+
|
|
85
|
+
search_range = 2**(tables.length.bit_length - 1) * 16
|
|
86
|
+
entry_selector = tables.length.bit_length - 1
|
|
87
|
+
range_shift = tables.length * 16 - search_range
|
|
88
|
+
|
|
89
|
+
font_data = "\x0\x1\x0\x0".b + \
|
|
90
|
+
[tables.length, search_range, entry_selector, range_shift].pack('n4')
|
|
91
|
+
|
|
92
|
+
offset = font_data.length + tables.length * 16
|
|
93
|
+
checksum = Table.calculate_checksum(font_data)
|
|
94
|
+
|
|
95
|
+
tables.each do |tag, data|
|
|
96
|
+
table_checksum = Table.calculate_checksum(data)
|
|
97
|
+
# tag, offset, data.length are all 32bit uint, table_checksum for header and body
|
|
98
|
+
checksum += tag.unpack('N').first + 2 * table_checksum + offset + data.length
|
|
99
|
+
font_data << [tag, table_checksum, offset, data.length].pack('a4N3')
|
|
100
|
+
offset += data.length
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
head[8, 4] = [0xB1B0AFBA - checksum].pack('N')
|
|
104
|
+
tables.each_value {|data| font_data << data}
|
|
105
|
+
|
|
106
|
+
font_data
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# Builds the glyf table.
|
|
112
|
+
def build_glyf_table
|
|
113
|
+
add_glyph_components
|
|
114
|
+
|
|
115
|
+
orig_glyf = @font[:glyf]
|
|
116
|
+
table = ''.b
|
|
117
|
+
locations = []
|
|
118
|
+
|
|
119
|
+
@glyph_map.each_key do |old_gid|
|
|
120
|
+
glyph = orig_glyf[old_gid]
|
|
121
|
+
locations << table.size
|
|
122
|
+
data = glyph.raw_data
|
|
123
|
+
if glyph.compound?
|
|
124
|
+
data = data.dup
|
|
125
|
+
glyph.component_offsets.each_with_index do |offset, index|
|
|
126
|
+
data[offset, 2] = [@glyph_map[glyph.components[index]]].pack('n')
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
table << data
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
locations << table.size
|
|
133
|
+
|
|
134
|
+
[table, locations]
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# Builds the loca table given the locations.
|
|
138
|
+
def build_loca_table(locations)
|
|
139
|
+
locations.pack('N*')
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Builds the hmtx table.
|
|
143
|
+
def build_hmtx_table
|
|
144
|
+
hmtx = @font[:hmtx]
|
|
145
|
+
data = ''.b
|
|
146
|
+
@glyph_map.each_key do |old_gid|
|
|
147
|
+
metric = hmtx[old_gid]
|
|
148
|
+
data << [metric.advance_width, metric.left_side_bearing].pack('n2'.freeze)
|
|
149
|
+
end
|
|
150
|
+
data
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Builds the hhea table, adjusting the value of the number of horizontal metrics.
|
|
154
|
+
def build_hhea_table(num_of_long_hor_metrics)
|
|
155
|
+
data = @font[:hhea].raw_data
|
|
156
|
+
data[-2, 2] = [num_of_long_hor_metrics].pack('n')
|
|
157
|
+
data
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Builds the head table, adjusting the modification time and location table type.
|
|
161
|
+
def build_head_table(modified:, loca_type:)
|
|
162
|
+
data = @font[:head].raw_data
|
|
163
|
+
data[8, 4] = "\0\0\0\0"
|
|
164
|
+
data[28, 8] = [(modified - TrueType::Table::TIME_EPOCH).to_i].pack('q>')
|
|
165
|
+
data[-4, 2] = [loca_type].pack('n')
|
|
166
|
+
data
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# Builds the maxp table, adjusting the number of glyphs.
|
|
170
|
+
def build_maxp_table(nr_of_glyphs)
|
|
171
|
+
data = @font[:maxp].raw_data
|
|
172
|
+
data[4, 2] = [nr_of_glyphs].pack('n')
|
|
173
|
+
data
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Adds the components of compound glyphs to the subset.
|
|
177
|
+
def add_glyph_components
|
|
178
|
+
glyf = @font[:glyf]
|
|
179
|
+
@glyph_map.keys.each {|gid| glyf[gid].components&.each {|cgid| use_glyph(cgid)}}
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
@@ -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
|
|
@@ -87,8 +87,12 @@ module HexaPDF
|
|
|
87
87
|
# Returns +true+ if the checksum stored in the directory entry of the table matches the
|
|
88
88
|
# tables data.
|
|
89
89
|
def checksum_valid?
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
directory_entry.checksum == self.class.calculate_checksum(raw_data)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Returns the raw table data.
|
|
94
|
+
def raw_data
|
|
95
|
+
with_io_pos(directory_entry.offset) { io.read(directory_entry.length) }
|
|
92
96
|
end
|
|
93
97
|
|
|
94
98
|
private
|
|
@@ -134,7 +138,7 @@ module HexaPDF
|
|
|
134
138
|
|
|
135
139
|
# Reads a 16.16-bit signed fixed-point integer and returns a Rational as result.
|
|
136
140
|
def read_fixed
|
|
137
|
-
Rational(io.read(4).unpack('
|
|
141
|
+
Rational(io.read(4).unpack('i>').first, 65536)
|
|
138
142
|
end
|
|
139
143
|
|
|
140
144
|
end
|
|
@@ -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
|