origami 1.2.7 → 2.0.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 +66 -0
- data/README.md +112 -0
- data/bin/config/pdfcop.conf.yml +232 -233
- data/bin/gui/about.rb +27 -37
- data/bin/gui/config.rb +108 -117
- data/bin/gui/file.rb +416 -365
- data/bin/gui/gtkhex.rb +1138 -1153
- data/bin/gui/hexview.rb +55 -57
- data/bin/gui/imgview.rb +48 -51
- data/bin/gui/menu.rb +388 -386
- data/bin/gui/properties.rb +114 -130
- data/bin/gui/signing.rb +571 -617
- data/bin/gui/textview.rb +77 -95
- data/bin/gui/treeview.rb +382 -387
- data/bin/gui/walker.rb +227 -232
- data/bin/gui/xrefs.rb +56 -60
- data/bin/pdf2pdfa +53 -57
- data/bin/pdf2ruby +212 -228
- data/bin/pdfcop +338 -348
- data/bin/pdfdecompress +58 -65
- data/bin/pdfdecrypt +56 -60
- data/bin/pdfencrypt +75 -80
- data/bin/pdfexplode +185 -182
- data/bin/pdfextract +201 -218
- data/bin/pdfmetadata +83 -82
- data/bin/pdfsh +4 -5
- data/bin/pdfwalker +1 -2
- data/bin/shell/.irbrc +45 -82
- data/bin/shell/console.rb +105 -130
- data/bin/shell/hexdump.rb +40 -64
- data/examples/README.md +34 -0
- data/examples/attachments/attachment.rb +38 -0
- data/examples/attachments/nested_document.rb +51 -0
- data/examples/encryption/encryption.rb +28 -0
- data/{samples/actions/triggerevents/trigger.rb → examples/events/events.rb} +13 -16
- data/examples/flash/flash.rb +37 -0
- data/{samples → examples}/flash/helloworld.swf +0 -0
- data/examples/forms/javascript.rb +54 -0
- data/examples/forms/xfa.rb +115 -0
- data/examples/javascript/hello_world.rb +22 -0
- data/examples/javascript/js_emulation.rb +54 -0
- data/examples/loop/goto.rb +32 -0
- data/examples/loop/named.rb +33 -0
- data/examples/signature/signature.rb +65 -0
- data/examples/uri/javascript.rb +56 -0
- data/examples/uri/open-uri.rb +21 -0
- data/examples/uri/submitform.rb +47 -0
- data/lib/origami.rb +29 -42
- data/lib/origami/3d.rb +350 -225
- data/lib/origami/acroform.rb +262 -288
- data/lib/origami/actions.rb +268 -288
- data/lib/origami/annotations.rb +697 -722
- data/lib/origami/array.rb +258 -184
- data/lib/origami/boolean.rb +74 -84
- data/lib/origami/catalog.rb +397 -434
- data/lib/origami/collections.rb +144 -0
- data/lib/origami/destinations.rb +233 -194
- data/lib/origami/dictionary.rb +253 -232
- data/lib/origami/encryption.rb +1274 -1243
- data/lib/origami/export.rb +232 -268
- data/lib/origami/extensions/fdf.rb +307 -220
- data/lib/origami/extensions/ppklite.rb +368 -435
- data/lib/origami/filespec.rb +197 -0
- data/lib/origami/filters.rb +301 -295
- data/lib/origami/filters/ascii.rb +177 -180
- data/lib/origami/filters/ccitt.rb +528 -535
- data/lib/origami/filters/crypt.rb +26 -35
- data/lib/origami/filters/dct.rb +46 -52
- data/lib/origami/filters/flate.rb +95 -94
- data/lib/origami/filters/jbig2.rb +49 -55
- data/lib/origami/filters/jpx.rb +38 -44
- data/lib/origami/filters/lzw.rb +189 -183
- data/lib/origami/filters/predictors.rb +221 -235
- data/lib/origami/filters/runlength.rb +103 -104
- data/lib/origami/font.rb +173 -186
- data/lib/origami/functions.rb +67 -81
- data/lib/origami/graphics.rb +25 -21
- data/lib/origami/graphics/colors.rb +178 -187
- data/lib/origami/graphics/instruction.rb +79 -85
- data/lib/origami/graphics/path.rb +142 -148
- data/lib/origami/graphics/patterns.rb +160 -167
- data/lib/origami/graphics/render.rb +43 -50
- data/lib/origami/graphics/state.rb +138 -153
- data/lib/origami/graphics/text.rb +188 -205
- data/lib/origami/graphics/xobject.rb +819 -815
- data/lib/origami/header.rb +63 -78
- data/lib/origami/javascript.rb +596 -597
- data/lib/origami/linearization.rb +285 -290
- data/lib/origami/metadata.rb +139 -148
- data/lib/origami/name.rb +112 -148
- data/lib/origami/null.rb +53 -62
- data/lib/origami/numeric.rb +162 -175
- data/lib/origami/obfuscation.rb +186 -174
- data/lib/origami/object.rb +593 -573
- data/lib/origami/outline.rb +42 -47
- data/lib/origami/outputintents.rb +73 -82
- data/lib/origami/page.rb +703 -592
- data/lib/origami/parser.rb +238 -290
- data/lib/origami/parsers/fdf.rb +41 -33
- data/lib/origami/parsers/pdf.rb +75 -95
- data/lib/origami/parsers/pdf/lazy.rb +137 -0
- data/lib/origami/parsers/pdf/linear.rb +64 -66
- data/lib/origami/parsers/ppklite.rb +34 -70
- data/lib/origami/pdf.rb +1030 -1005
- data/lib/origami/reference.rb +102 -102
- data/lib/origami/signature.rb +591 -609
- data/lib/origami/stream.rb +668 -551
- data/lib/origami/string.rb +397 -373
- data/lib/origami/template/patterns.rb +56 -0
- data/lib/origami/template/widgets.rb +151 -0
- data/lib/origami/trailer.rb +144 -158
- data/lib/origami/tree.rb +62 -0
- data/lib/origami/version.rb +23 -0
- data/lib/origami/webcapture.rb +88 -79
- data/lib/origami/xfa.rb +2863 -2882
- data/lib/origami/xreftable.rb +472 -384
- data/test/dataset/calc.pdf +85 -0
- data/test/dataset/crypto.pdf +82 -0
- data/test/dataset/empty.pdf +49 -0
- data/test/test_actions.rb +27 -0
- data/test/test_annotations.rb +90 -0
- data/test/test_pages.rb +31 -0
- data/test/test_pdf.rb +16 -0
- data/test/test_pdf_attachment.rb +34 -0
- data/test/test_pdf_create.rb +24 -0
- data/test/test_pdf_encrypt.rb +95 -0
- data/test/test_pdf_parse.rb +96 -0
- data/test/test_pdf_sign.rb +58 -0
- data/test/test_streams.rb +182 -0
- data/test/test_xrefs.rb +67 -0
- metadata +88 -58
- data/README +0 -67
- data/bin/pdf2graph +0 -121
- data/bin/pdfcocoon +0 -104
- data/lib/origami/file.rb +0 -233
- data/samples/README.txt +0 -45
- data/samples/actions/launch/calc.rb +0 -87
- data/samples/actions/launch/winparams.rb +0 -22
- data/samples/actions/loop/loopgoto.rb +0 -24
- data/samples/actions/loop/loopnamed.rb +0 -21
- data/samples/actions/named/named.rb +0 -31
- data/samples/actions/samba/smbrelay.rb +0 -26
- data/samples/actions/webbug/submitform.js +0 -26
- data/samples/actions/webbug/webbug-browser.rb +0 -68
- data/samples/actions/webbug/webbug-js.rb +0 -67
- data/samples/actions/webbug/webbug-reader.rb +0 -90
- data/samples/attachments/attach.rb +0 -40
- data/samples/attachments/attached.txt +0 -1
- data/samples/crypto/crypto.rb +0 -28
- data/samples/digsig/signed.rb +0 -46
- data/samples/exploits/cve-2008-2992-utilprintf.rb +0 -87
- data/samples/exploits/cve-2009-0927-geticon.rb +0 -65
- data/samples/exploits/exploit_customdictopen.rb +0 -55
- data/samples/exploits/getannots.rb +0 -69
- data/samples/flash/flash.rb +0 -31
- data/samples/javascript/attached.txt +0 -1
- data/samples/javascript/js.rb +0 -52
- data/templates/patterns.rb +0 -66
- data/templates/widgets.rb +0 -173
- data/templates/xdp.rb +0 -92
- data/test/ts_pdf.rb +0 -50
|
@@ -1,196 +1,193 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
-
GNU Lesser General Public License for more details.
|
|
20
|
-
|
|
21
|
-
You should have received a copy of the GNU Lesser General Public License
|
|
22
|
-
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
3
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
|
4
|
+
Copyright (C) 2016 Guillaume Delugré.
|
|
5
|
+
|
|
6
|
+
Origami is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
10
|
+
|
|
11
|
+
Origami is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU Lesser General Public License for more details.
|
|
15
|
+
|
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
23
18
|
|
|
24
19
|
=end
|
|
25
20
|
|
|
26
21
|
module Origami
|
|
27
22
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
# Class representing a filter used to encode and decode data written into hexadecimal.
|
|
35
|
-
#
|
|
36
|
-
class ASCIIHex
|
|
37
|
-
include Filter
|
|
38
|
-
|
|
39
|
-
EOD = ">" #:nodoc:
|
|
40
|
-
|
|
41
|
-
#
|
|
42
|
-
# Encodes given data into upcase hexadecimal representation.
|
|
43
|
-
# _stream_:: The data to encode.
|
|
44
|
-
#
|
|
45
|
-
def encode(stream)
|
|
46
|
-
stream.unpack("H2" * stream.size).join.upcase
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
#
|
|
50
|
-
# Decodes given data writen into upcase hexadecimal representation.
|
|
51
|
-
# _string_:: The data to decode.
|
|
52
|
-
#
|
|
53
|
-
def decode(string)
|
|
54
|
-
|
|
55
|
-
input = string.include?(?>) ? string[0..string.index(?>) - 1] : string
|
|
56
|
-
digits = input.delete(" \f\t\r\n\0").split(/(..)/).delete_if{|digit| digit.empty?}
|
|
57
|
-
|
|
58
|
-
if not digits.all? { |d| d =~ /[a-fA-F0-9]{1,2}/ }
|
|
59
|
-
raise InvalidASCIIHexStringError, input
|
|
23
|
+
module Filter
|
|
24
|
+
|
|
25
|
+
class InvalidASCIIHexStringError < DecodeError #:nodoc:
|
|
60
26
|
end
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
5.times do |p|
|
|
102
|
-
c = inblock / 85 ** (4 - p)
|
|
103
|
-
outblock << ("!"[0].ord + c).chr
|
|
104
|
-
|
|
105
|
-
inblock -= c * 85 ** (4 - p)
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
outblock = "z" if outblock == "!!!!!" and addend == 0
|
|
109
|
-
|
|
110
|
-
if addend != 0
|
|
111
|
-
outblock = outblock[0,(4 - addend) + 1]
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
code << outblock
|
|
115
|
-
|
|
116
|
-
i = i + 4
|
|
27
|
+
|
|
28
|
+
#
|
|
29
|
+
# Class representing a filter used to encode and decode data written into hexadecimal.
|
|
30
|
+
#
|
|
31
|
+
class ASCIIHex
|
|
32
|
+
include Filter
|
|
33
|
+
|
|
34
|
+
EOD = ">" #:nodoc:
|
|
35
|
+
|
|
36
|
+
#
|
|
37
|
+
# Encodes given data into upcase hexadecimal representation.
|
|
38
|
+
# _stream_:: The data to encode.
|
|
39
|
+
#
|
|
40
|
+
def encode(stream)
|
|
41
|
+
stream.unpack("H*").join.upcase
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
#
|
|
45
|
+
# Decodes given data writen into upcase hexadecimal representation.
|
|
46
|
+
# _string_:: The data to decode.
|
|
47
|
+
#
|
|
48
|
+
def decode(string)
|
|
49
|
+
input = string.include?(EOD) ? string[0...string.index(EOD)] : string
|
|
50
|
+
digits = input.delete(" \f\t\r\n\0")
|
|
51
|
+
|
|
52
|
+
# Ensure every digit is in the hexadecimal charset.
|
|
53
|
+
unless digits =~ /^\h*$/
|
|
54
|
+
digits = digits.match(/^\h*/).to_s
|
|
55
|
+
|
|
56
|
+
raise InvalidASCIIHexStringError.new("Invalid characters", input_data: string, decoded_data: [ digits ].pack('H*'))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
[ digits ].pack "H*"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
AHx = ASCIIHex
|
|
64
|
+
|
|
65
|
+
class InvalidASCII85StringError < DecodeError #:nodoc:
|
|
117
66
|
end
|
|
118
67
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
68
|
+
#
|
|
69
|
+
# Class representing a filter used to encode and decode data written in base85 encoding.
|
|
70
|
+
#
|
|
71
|
+
class ASCII85
|
|
72
|
+
include Filter
|
|
73
|
+
|
|
74
|
+
EOD = "~>" #:nodoc:
|
|
75
|
+
|
|
76
|
+
#
|
|
77
|
+
# Encodes given data into base85.
|
|
78
|
+
# _stream_:: The data to encode.
|
|
79
|
+
#
|
|
80
|
+
def encode(stream)
|
|
81
|
+
i = 0
|
|
82
|
+
code = "".b
|
|
83
|
+
input = stream.dup
|
|
84
|
+
|
|
85
|
+
while i < input.size do
|
|
86
|
+
|
|
87
|
+
if input.length - i < 4
|
|
88
|
+
addend = 4 - (input.length - i)
|
|
89
|
+
input << "\0" * addend
|
|
90
|
+
else
|
|
91
|
+
addend = 0
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
inblock = (input[i].ord * 256**3 +
|
|
95
|
+
input[i+1].ord * 256**2 +
|
|
96
|
+
input[i+2].ord * 256 +
|
|
97
|
+
input[i+3].ord)
|
|
98
|
+
outblock = ""
|
|
99
|
+
|
|
100
|
+
5.times do |p|
|
|
101
|
+
c = inblock / 85 ** (4 - p)
|
|
102
|
+
outblock << ("!".ord + c).chr
|
|
103
|
+
|
|
104
|
+
inblock -= c * 85 ** (4 - p)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
outblock = "z" if outblock == "!!!!!" and addend == 0
|
|
108
|
+
|
|
109
|
+
if addend != 0
|
|
110
|
+
outblock = outblock[0,(4 - addend) + 1]
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
code << outblock
|
|
114
|
+
|
|
115
|
+
i = i + 4
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
code
|
|
151
119
|
end
|
|
152
|
-
|
|
153
|
-
#
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
120
|
+
|
|
121
|
+
#
|
|
122
|
+
# Decodes the given data encoded in base85.
|
|
123
|
+
# _string_:: The data to decode.
|
|
124
|
+
#
|
|
125
|
+
def decode(string)
|
|
126
|
+
input = (string.include?(EOD) ? string[0..string.index(EOD) - 1] : string).delete(" \f\t\r\n\0")
|
|
127
|
+
|
|
128
|
+
i = 0
|
|
129
|
+
result = "".b
|
|
130
|
+
while i < input.size do
|
|
131
|
+
|
|
132
|
+
outblock = ""
|
|
133
|
+
|
|
134
|
+
if input[i] == "z"
|
|
135
|
+
inblock = 0
|
|
136
|
+
codelen = 1
|
|
137
|
+
else
|
|
138
|
+
inblock = 0
|
|
139
|
+
codelen = 5
|
|
140
|
+
|
|
141
|
+
if input.length - i < 5
|
|
142
|
+
raise InvalidASCII85StringError.new("Invalid length", input_data: string, decoded_data: result) if input.length - i == 1
|
|
143
|
+
|
|
144
|
+
addend = 5 - (input.length - i)
|
|
145
|
+
input << "u" * addend
|
|
146
|
+
else
|
|
147
|
+
addend = 0
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Checking if this string is in base85
|
|
151
|
+
5.times do |j|
|
|
152
|
+
if input[i+j].ord > "u".ord or input[i+j].ord < "!".ord
|
|
153
|
+
raise InvalidASCII85StringError.new(
|
|
154
|
+
"Invalid character sequence: #{input[i,5].inspect}",
|
|
155
|
+
input_data: string,
|
|
156
|
+
decoded_data: result
|
|
157
|
+
)
|
|
158
|
+
else
|
|
159
|
+
inblock += (input[i+j].ord - "!".ord) * 85 ** (4 - j)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
raise InvalidASCII85StringError.new(
|
|
164
|
+
"Invalid value (#{inblock}) for block #{input[i,5].inspect}",
|
|
165
|
+
input_data: string,
|
|
166
|
+
decoded_data: result
|
|
167
|
+
) if inblock >= 2**32
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
4.times do |p|
|
|
171
|
+
c = inblock / 256 ** (3 - p)
|
|
172
|
+
outblock << c.chr
|
|
173
|
+
|
|
174
|
+
inblock -= c * 256 ** (3 - p)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
if addend != 0
|
|
178
|
+
outblock = outblock[0, 4 - addend]
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
result << outblock
|
|
182
|
+
|
|
183
|
+
i = i + codelen
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
result
|
|
163
187
|
end
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
raise InvalidASCII85StringError.new(
|
|
167
|
-
"Invalid value (#{inblock}) for block #{input[i,5].inspect}",
|
|
168
|
-
result
|
|
169
|
-
) if inblock >= 2**32
|
|
170
|
-
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
4.times do |p|
|
|
174
|
-
c = inblock / 256 ** (3 - p)
|
|
175
|
-
outblock << c.chr
|
|
176
|
-
|
|
177
|
-
inblock -= c * 256 ** (3 - p)
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
if addend != 0
|
|
181
|
-
outblock = outblock[0, 4 - addend]
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
result << outblock
|
|
185
|
-
|
|
186
|
-
i = i + codelen
|
|
188
|
+
|
|
187
189
|
end
|
|
188
|
-
|
|
189
|
-
result
|
|
190
|
-
end
|
|
190
|
+
A85 = ASCII85
|
|
191
191
|
|
|
192
192
|
end
|
|
193
|
-
A85 = ASCII85
|
|
194
|
-
end
|
|
195
193
|
end
|
|
196
|
-
|
|
@@ -1,576 +1,569 @@
|
|
|
1
1
|
=begin
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
= Info
|
|
7
|
-
This file is part of Origami, PDF manipulation framework for Ruby
|
|
8
|
-
Copyright (C) 2010 Guillaume Delugré <guillaume AT security-labs DOT org>
|
|
9
|
-
All right reserved.
|
|
10
|
-
|
|
11
|
-
Origami is free software: you can redistribute it and/or modify
|
|
12
|
-
it under the terms of the GNU Lesser General Public License as published by
|
|
13
|
-
the Free Software Foundation, either version 3 of the License, or
|
|
14
|
-
(at your option) any later version.
|
|
15
|
-
|
|
16
|
-
Origami is distributed in the hope that it will be useful,
|
|
17
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
19
|
-
GNU Lesser General Public License for more details.
|
|
20
|
-
|
|
21
|
-
You should have received a copy of the GNU Lesser General Public License
|
|
22
|
-
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
3
|
+
This file is part of Origami, PDF manipulation framework for Ruby
|
|
4
|
+
Copyright (C) 2016 Guillaume Delugré.
|
|
23
5
|
|
|
24
|
-
|
|
6
|
+
Origami is free software: you can redistribute it and/or modify
|
|
7
|
+
it under the terms of the GNU Lesser General Public License as published by
|
|
8
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
9
|
+
(at your option) any later version.
|
|
25
10
|
|
|
26
|
-
|
|
11
|
+
Origami is distributed in the hope that it will be useful,
|
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
+
GNU Lesser General Public License for more details.
|
|
27
15
|
|
|
28
|
-
|
|
16
|
+
You should have received a copy of the GNU Lesser General Public License
|
|
17
|
+
along with Origami. If not, see <http://www.gnu.org/licenses/>.
|
|
29
18
|
|
|
30
|
-
|
|
31
|
-
end
|
|
19
|
+
=end
|
|
32
20
|
|
|
33
|
-
|
|
34
|
-
end
|
|
21
|
+
module Origami
|
|
35
22
|
|
|
36
|
-
|
|
37
|
-
# Class representing a Filter used to encode and decode data with CCITT-facsimile compression algorithm.
|
|
38
|
-
#
|
|
39
|
-
class CCITTFax
|
|
40
|
-
include Filter
|
|
41
|
-
|
|
42
|
-
class DecodeParms < Dictionary
|
|
43
|
-
include StandardObject
|
|
44
|
-
|
|
45
|
-
field :K, :Type => Integer, :Default => 0
|
|
46
|
-
field :EndOfLine, :Type => Boolean, :Default => false
|
|
47
|
-
field :EncodedByteAlign, :Type => Boolean, :Default => false
|
|
48
|
-
field :Columns, :Type => Integer, :Default => 1728
|
|
49
|
-
field :Rows, :Type => Integer, :Default => 0
|
|
50
|
-
field :EndOfBlock, :Type => Boolean, :Default => true
|
|
51
|
-
field :BlackIs1, :Type => Boolean, :Default => false
|
|
52
|
-
field :DamagedRowsBeforeError, :Type => :Integer, :Default => 0
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
def self.codeword(str) #:nodoc:
|
|
56
|
-
[ str.to_i(2), str.length ]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
EOL = codeword('000000000001')
|
|
60
|
-
RTC = codeword('000000000001' * 6)
|
|
61
|
-
|
|
62
|
-
WHITE_TERMINAL_ENCODE_TABLE =
|
|
63
|
-
{
|
|
64
|
-
0 => codeword('00110101'),
|
|
65
|
-
1 => codeword('000111'),
|
|
66
|
-
2 => codeword('0111'),
|
|
67
|
-
3 => codeword('1000'),
|
|
68
|
-
4 => codeword('1011'),
|
|
69
|
-
5 => codeword('1100'),
|
|
70
|
-
6 => codeword('1110'),
|
|
71
|
-
7 => codeword('1111'),
|
|
72
|
-
8 => codeword('10011'),
|
|
73
|
-
9 => codeword('10100'),
|
|
74
|
-
10 => codeword('00111'),
|
|
75
|
-
11 => codeword('01000'),
|
|
76
|
-
12 => codeword('001000'),
|
|
77
|
-
13 => codeword('000011'),
|
|
78
|
-
14 => codeword('110100'),
|
|
79
|
-
15 => codeword('110101'),
|
|
80
|
-
16 => codeword('101010'),
|
|
81
|
-
17 => codeword('101011'),
|
|
82
|
-
18 => codeword('0100111'),
|
|
83
|
-
19 => codeword('0001100'),
|
|
84
|
-
20 => codeword('0001000'),
|
|
85
|
-
21 => codeword('0010111'),
|
|
86
|
-
22 => codeword('0000011'),
|
|
87
|
-
23 => codeword('0000100'),
|
|
88
|
-
24 => codeword('0101000'),
|
|
89
|
-
25 => codeword('0101011'),
|
|
90
|
-
26 => codeword('0010011'),
|
|
91
|
-
27 => codeword('0100100'),
|
|
92
|
-
28 => codeword('0011000'),
|
|
93
|
-
29 => codeword('00000010'),
|
|
94
|
-
30 => codeword('00000011'),
|
|
95
|
-
31 => codeword('00011010'),
|
|
96
|
-
32 => codeword('00011011'),
|
|
97
|
-
33 => codeword('00010010'),
|
|
98
|
-
34 => codeword('00010011'),
|
|
99
|
-
35 => codeword('00010100'),
|
|
100
|
-
36 => codeword('00010101'),
|
|
101
|
-
37 => codeword('00010110'),
|
|
102
|
-
38 => codeword('00010111'),
|
|
103
|
-
39 => codeword('00101000'),
|
|
104
|
-
40 => codeword('00101001'),
|
|
105
|
-
41 => codeword('00101010'),
|
|
106
|
-
42 => codeword('00101011'),
|
|
107
|
-
43 => codeword('00101100'),
|
|
108
|
-
44 => codeword('00101101'),
|
|
109
|
-
45 => codeword('00000100'),
|
|
110
|
-
46 => codeword('00000101'),
|
|
111
|
-
47 => codeword('00001010'),
|
|
112
|
-
48 => codeword('00001011'),
|
|
113
|
-
49 => codeword('01010010'),
|
|
114
|
-
50 => codeword('01010011'),
|
|
115
|
-
51 => codeword('01010100'),
|
|
116
|
-
52 => codeword('01010101'),
|
|
117
|
-
53 => codeword('00100100'),
|
|
118
|
-
54 => codeword('00100101'),
|
|
119
|
-
55 => codeword('01011000'),
|
|
120
|
-
56 => codeword('01011001'),
|
|
121
|
-
57 => codeword('01011010'),
|
|
122
|
-
58 => codeword('01011011'),
|
|
123
|
-
59 => codeword('01001010'),
|
|
124
|
-
60 => codeword('01001011'),
|
|
125
|
-
61 => codeword('00110010'),
|
|
126
|
-
62 => codeword('00110011'),
|
|
127
|
-
63 => codeword('00110100')
|
|
128
|
-
}
|
|
129
|
-
WHITE_TERMINAL_DECODE_TABLE = WHITE_TERMINAL_ENCODE_TABLE.invert
|
|
130
|
-
|
|
131
|
-
BLACK_TERMINAL_ENCODE_TABLE =
|
|
132
|
-
{
|
|
133
|
-
0 => codeword('0000110111'),
|
|
134
|
-
1 => codeword('010'),
|
|
135
|
-
2 => codeword('11'),
|
|
136
|
-
3 => codeword('10'),
|
|
137
|
-
4 => codeword('011'),
|
|
138
|
-
5 => codeword('0011'),
|
|
139
|
-
6 => codeword('0010'),
|
|
140
|
-
7 => codeword('00011'),
|
|
141
|
-
8 => codeword('000101'),
|
|
142
|
-
9 => codeword('000100'),
|
|
143
|
-
10 => codeword('0000100'),
|
|
144
|
-
11 => codeword('0000101'),
|
|
145
|
-
12 => codeword('0000111'),
|
|
146
|
-
13 => codeword('00000100'),
|
|
147
|
-
14 => codeword('00000111'),
|
|
148
|
-
15 => codeword('000011000'),
|
|
149
|
-
16 => codeword('0000010111'),
|
|
150
|
-
17 => codeword('0000011000'),
|
|
151
|
-
18 => codeword('0000001000'),
|
|
152
|
-
19 => codeword('00001100111'),
|
|
153
|
-
20 => codeword('00001101000'),
|
|
154
|
-
21 => codeword('00001101100'),
|
|
155
|
-
22 => codeword('00000110111'),
|
|
156
|
-
23 => codeword('00000101000'),
|
|
157
|
-
24 => codeword('00000010111'),
|
|
158
|
-
25 => codeword('00000011000'),
|
|
159
|
-
26 => codeword('000011001010'),
|
|
160
|
-
27 => codeword('000011001011'),
|
|
161
|
-
28 => codeword('000011001100'),
|
|
162
|
-
29 => codeword('000011001101'),
|
|
163
|
-
30 => codeword('000001101000'),
|
|
164
|
-
31 => codeword('000001101001'),
|
|
165
|
-
32 => codeword('000001101010'),
|
|
166
|
-
33 => codeword('000001101011'),
|
|
167
|
-
34 => codeword('000011010010'),
|
|
168
|
-
35 => codeword('000011010011'),
|
|
169
|
-
36 => codeword('000011010100'),
|
|
170
|
-
37 => codeword('000011010101'),
|
|
171
|
-
38 => codeword('000011010110'),
|
|
172
|
-
39 => codeword('000011010111'),
|
|
173
|
-
40 => codeword('000001101100'),
|
|
174
|
-
41 => codeword('000001101101'),
|
|
175
|
-
42 => codeword('000011011010'),
|
|
176
|
-
43 => codeword('000011011011'),
|
|
177
|
-
44 => codeword('000001010100'),
|
|
178
|
-
45 => codeword('000001010101'),
|
|
179
|
-
46 => codeword('000001010110'),
|
|
180
|
-
47 => codeword('000001010111'),
|
|
181
|
-
48 => codeword('000001100100'),
|
|
182
|
-
49 => codeword('000001100101'),
|
|
183
|
-
50 => codeword('000001010010'),
|
|
184
|
-
51 => codeword('000001010011'),
|
|
185
|
-
52 => codeword('000000100100'),
|
|
186
|
-
53 => codeword('000000110111'),
|
|
187
|
-
54 => codeword('000000111000'),
|
|
188
|
-
55 => codeword('000000100111'),
|
|
189
|
-
56 => codeword('000000101000'),
|
|
190
|
-
57 => codeword('000001011000'),
|
|
191
|
-
58 => codeword('000001011001'),
|
|
192
|
-
59 => codeword('000000101011'),
|
|
193
|
-
60 => codeword('000000101100'),
|
|
194
|
-
61 => codeword('000001011010'),
|
|
195
|
-
62 => codeword('000001100110'),
|
|
196
|
-
63 => codeword('000001100111')
|
|
197
|
-
}
|
|
198
|
-
BLACK_TERMINAL_DECODE_TABLE = BLACK_TERMINAL_ENCODE_TABLE.invert
|
|
199
|
-
|
|
200
|
-
WHITE_CONFIGURATION_ENCODE_TABLE =
|
|
201
|
-
{
|
|
202
|
-
64 => codeword('11011'),
|
|
203
|
-
128 => codeword('10010'),
|
|
204
|
-
192 => codeword('010111'),
|
|
205
|
-
256 => codeword('0110111'),
|
|
206
|
-
320 => codeword('00110110'),
|
|
207
|
-
384 => codeword('00110111'),
|
|
208
|
-
448 => codeword('01100100'),
|
|
209
|
-
512 => codeword('01100101'),
|
|
210
|
-
576 => codeword('01101000'),
|
|
211
|
-
640 => codeword('01100111'),
|
|
212
|
-
704 => codeword('011001100'),
|
|
213
|
-
768 => codeword('011001101'),
|
|
214
|
-
832 => codeword('011010010'),
|
|
215
|
-
896 => codeword('011010011'),
|
|
216
|
-
960 => codeword('011010100'),
|
|
217
|
-
1024 => codeword('011010101'),
|
|
218
|
-
1088 => codeword('011010110'),
|
|
219
|
-
1152 => codeword('011010111'),
|
|
220
|
-
1216 => codeword('011011000'),
|
|
221
|
-
1280 => codeword('011011001'),
|
|
222
|
-
1344 => codeword('011011010'),
|
|
223
|
-
1408 => codeword('011011011'),
|
|
224
|
-
1472 => codeword('010011000'),
|
|
225
|
-
1536 => codeword('010011001'),
|
|
226
|
-
1600 => codeword('010011010'),
|
|
227
|
-
1664 => codeword('011000'),
|
|
228
|
-
1728 => codeword('010011011'),
|
|
229
|
-
|
|
230
|
-
1792 => codeword('00000001000'),
|
|
231
|
-
1856 => codeword('00000001100'),
|
|
232
|
-
1920 => codeword('00000001001'),
|
|
233
|
-
1984 => codeword('000000010010'),
|
|
234
|
-
2048 => codeword('000000010011'),
|
|
235
|
-
2112 => codeword('000000010100'),
|
|
236
|
-
2176 => codeword('000000010101'),
|
|
237
|
-
2240 => codeword('000000010110'),
|
|
238
|
-
2340 => codeword('000000010111'),
|
|
239
|
-
2368 => codeword('000000011100'),
|
|
240
|
-
2432 => codeword('000000011101'),
|
|
241
|
-
2496 => codeword('000000011110'),
|
|
242
|
-
2560 => codeword('000000011111')
|
|
243
|
-
}
|
|
244
|
-
WHITE_CONFIGURATION_DECODE_TABLE = WHITE_CONFIGURATION_ENCODE_TABLE.invert
|
|
245
|
-
|
|
246
|
-
BLACK_CONFIGURATION_ENCODE_TABLE =
|
|
247
|
-
{
|
|
248
|
-
64 => codeword('0000001111'),
|
|
249
|
-
128 => codeword('000011001000'),
|
|
250
|
-
192 => codeword('000011001001'),
|
|
251
|
-
256 => codeword('000001011011'),
|
|
252
|
-
320 => codeword('000000110011'),
|
|
253
|
-
384 => codeword('000000110100'),
|
|
254
|
-
448 => codeword('000000110101'),
|
|
255
|
-
512 => codeword('0000001101100'),
|
|
256
|
-
576 => codeword('0000001101101'),
|
|
257
|
-
640 => codeword('0000001001010'),
|
|
258
|
-
704 => codeword('0000001001011'),
|
|
259
|
-
768 => codeword('0000001001100'),
|
|
260
|
-
832 => codeword('0000001001101'),
|
|
261
|
-
896 => codeword('0000001110010'),
|
|
262
|
-
960 => codeword('0000001110011'),
|
|
263
|
-
1024 => codeword('0000001110100'),
|
|
264
|
-
1088 => codeword('0000001110101'),
|
|
265
|
-
1152 => codeword('0000001110110'),
|
|
266
|
-
1216 => codeword('0000001110111'),
|
|
267
|
-
1280 => codeword('0000001010010'),
|
|
268
|
-
1344 => codeword('0000001010011'),
|
|
269
|
-
1408 => codeword('0000001010100'),
|
|
270
|
-
1472 => codeword('0000001010101'),
|
|
271
|
-
1536 => codeword('0000001011010'),
|
|
272
|
-
1600 => codeword('0000001011011'),
|
|
273
|
-
1664 => codeword('0000001100100'),
|
|
274
|
-
1728 => codeword('0000001100101'),
|
|
275
|
-
|
|
276
|
-
1792 => codeword('00000001000'),
|
|
277
|
-
1856 => codeword('00000001100'),
|
|
278
|
-
1920 => codeword('00000001001'),
|
|
279
|
-
1984 => codeword('000000010010'),
|
|
280
|
-
2048 => codeword('000000010011'),
|
|
281
|
-
2112 => codeword('000000010100'),
|
|
282
|
-
2176 => codeword('000000010101'),
|
|
283
|
-
2240 => codeword('000000010110'),
|
|
284
|
-
2340 => codeword('000000010111'),
|
|
285
|
-
2368 => codeword('000000011100'),
|
|
286
|
-
2432 => codeword('000000011101'),
|
|
287
|
-
2496 => codeword('000000011110'),
|
|
288
|
-
2560 => codeword('000000011111')
|
|
289
|
-
}
|
|
290
|
-
BLACK_CONFIGURATION_DECODE_TABLE = BLACK_CONFIGURATION_ENCODE_TABLE.invert
|
|
291
|
-
|
|
292
|
-
#
|
|
293
|
-
# Creates a new CCITT Fax Filter.
|
|
294
|
-
#
|
|
295
|
-
def initialize(parameters = {})
|
|
296
|
-
super(DecodeParms.new(parameters))
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
#
|
|
300
|
-
# Encodes data using CCITT-facsimile compression method.
|
|
301
|
-
#
|
|
302
|
-
def encode(stream)
|
|
303
|
-
mode = @params.has_key?(:K) ? @params.K.value : 0
|
|
304
|
-
|
|
305
|
-
unless mode.is_a?(::Integer) and mode <= 0
|
|
306
|
-
raise NotImplementedError, "CCITT encoding scheme not supported"
|
|
307
|
-
end
|
|
23
|
+
module Filter
|
|
308
24
|
|
|
309
|
-
|
|
310
|
-
unless columns.is_a?(::Integer) and columns > 0 #and columns % 8 == 0
|
|
311
|
-
raise CCITTFaxFilterError, "Invalid value for parameter `Columns'"
|
|
25
|
+
class InvalidCCITTFaxDataError < DecodeError #:nodoc:
|
|
312
26
|
end
|
|
313
27
|
|
|
314
|
-
|
|
315
|
-
raise CCITTFaxFilterError, "Data size is not a multiple of image width"
|
|
28
|
+
class CCITTFaxFilterError < Error #:nodoc:
|
|
316
29
|
end
|
|
317
30
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
31
|
+
#
|
|
32
|
+
# Class representing a Filter used to encode and decode data with CCITT-facsimile compression algorithm.
|
|
33
|
+
#
|
|
34
|
+
class CCITTFax
|
|
35
|
+
include Filter
|
|
36
|
+
|
|
37
|
+
class DecodeParms < Dictionary
|
|
38
|
+
include StandardObject
|
|
39
|
+
|
|
40
|
+
field :K, :Type => Integer, :Default => 0
|
|
41
|
+
field :EndOfLine, :Type => Boolean, :Default => false
|
|
42
|
+
field :EncodedByteAlign, :Type => Boolean, :Default => false
|
|
43
|
+
field :Columns, :Type => Integer, :Default => 1728
|
|
44
|
+
field :Rows, :Type => Integer, :Default => 0
|
|
45
|
+
field :EndOfBlock, :Type => Boolean, :Default => true
|
|
46
|
+
field :BlackIs1, :Type => Boolean, :Default => false
|
|
47
|
+
field :DamagedRowsBeforeError, :Type => :Integer, :Default => 0
|
|
48
|
+
end
|
|
322
49
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
write_bit_range(prev_line, white, columns)
|
|
327
|
-
prev_line = Utils::BitReader.new(prev_line.final.to_s)
|
|
328
|
-
end
|
|
50
|
+
def self.codeword(str) #:nodoc:
|
|
51
|
+
[ str.to_i(2), str.length ]
|
|
52
|
+
end
|
|
329
53
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
54
|
+
EOL = codeword('000000000001')
|
|
55
|
+
RTC = codeword('000000000001' * 6)
|
|
56
|
+
|
|
57
|
+
WHITE_TERMINAL_ENCODE_TABLE =
|
|
58
|
+
{
|
|
59
|
+
0 => codeword('00110101'),
|
|
60
|
+
1 => codeword('000111'),
|
|
61
|
+
2 => codeword('0111'),
|
|
62
|
+
3 => codeword('1000'),
|
|
63
|
+
4 => codeword('1011'),
|
|
64
|
+
5 => codeword('1100'),
|
|
65
|
+
6 => codeword('1110'),
|
|
66
|
+
7 => codeword('1111'),
|
|
67
|
+
8 => codeword('10011'),
|
|
68
|
+
9 => codeword('10100'),
|
|
69
|
+
10 => codeword('00111'),
|
|
70
|
+
11 => codeword('01000'),
|
|
71
|
+
12 => codeword('001000'),
|
|
72
|
+
13 => codeword('000011'),
|
|
73
|
+
14 => codeword('110100'),
|
|
74
|
+
15 => codeword('110101'),
|
|
75
|
+
16 => codeword('101010'),
|
|
76
|
+
17 => codeword('101011'),
|
|
77
|
+
18 => codeword('0100111'),
|
|
78
|
+
19 => codeword('0001100'),
|
|
79
|
+
20 => codeword('0001000'),
|
|
80
|
+
21 => codeword('0010111'),
|
|
81
|
+
22 => codeword('0000011'),
|
|
82
|
+
23 => codeword('0000100'),
|
|
83
|
+
24 => codeword('0101000'),
|
|
84
|
+
25 => codeword('0101011'),
|
|
85
|
+
26 => codeword('0010011'),
|
|
86
|
+
27 => codeword('0100100'),
|
|
87
|
+
28 => codeword('0011000'),
|
|
88
|
+
29 => codeword('00000010'),
|
|
89
|
+
30 => codeword('00000011'),
|
|
90
|
+
31 => codeword('00011010'),
|
|
91
|
+
32 => codeword('00011011'),
|
|
92
|
+
33 => codeword('00010010'),
|
|
93
|
+
34 => codeword('00010011'),
|
|
94
|
+
35 => codeword('00010100'),
|
|
95
|
+
36 => codeword('00010101'),
|
|
96
|
+
37 => codeword('00010110'),
|
|
97
|
+
38 => codeword('00010111'),
|
|
98
|
+
39 => codeword('00101000'),
|
|
99
|
+
40 => codeword('00101001'),
|
|
100
|
+
41 => codeword('00101010'),
|
|
101
|
+
42 => codeword('00101011'),
|
|
102
|
+
43 => codeword('00101100'),
|
|
103
|
+
44 => codeword('00101101'),
|
|
104
|
+
45 => codeword('00000100'),
|
|
105
|
+
46 => codeword('00000101'),
|
|
106
|
+
47 => codeword('00001010'),
|
|
107
|
+
48 => codeword('00001011'),
|
|
108
|
+
49 => codeword('01010010'),
|
|
109
|
+
50 => codeword('01010011'),
|
|
110
|
+
51 => codeword('01010100'),
|
|
111
|
+
52 => codeword('01010101'),
|
|
112
|
+
53 => codeword('00100100'),
|
|
113
|
+
54 => codeword('00100101'),
|
|
114
|
+
55 => codeword('01011000'),
|
|
115
|
+
56 => codeword('01011001'),
|
|
116
|
+
57 => codeword('01011010'),
|
|
117
|
+
58 => codeword('01011011'),
|
|
118
|
+
59 => codeword('01001010'),
|
|
119
|
+
60 => codeword('01001011'),
|
|
120
|
+
61 => codeword('00110010'),
|
|
121
|
+
62 => codeword('00110011'),
|
|
122
|
+
63 => codeword('00110100')
|
|
123
|
+
}
|
|
124
|
+
WHITE_TERMINAL_DECODE_TABLE = WHITE_TERMINAL_ENCODE_TABLE.invert
|
|
125
|
+
|
|
126
|
+
BLACK_TERMINAL_ENCODE_TABLE =
|
|
127
|
+
{
|
|
128
|
+
0 => codeword('0000110111'),
|
|
129
|
+
1 => codeword('010'),
|
|
130
|
+
2 => codeword('11'),
|
|
131
|
+
3 => codeword('10'),
|
|
132
|
+
4 => codeword('011'),
|
|
133
|
+
5 => codeword('0011'),
|
|
134
|
+
6 => codeword('0010'),
|
|
135
|
+
7 => codeword('00011'),
|
|
136
|
+
8 => codeword('000101'),
|
|
137
|
+
9 => codeword('000100'),
|
|
138
|
+
10 => codeword('0000100'),
|
|
139
|
+
11 => codeword('0000101'),
|
|
140
|
+
12 => codeword('0000111'),
|
|
141
|
+
13 => codeword('00000100'),
|
|
142
|
+
14 => codeword('00000111'),
|
|
143
|
+
15 => codeword('000011000'),
|
|
144
|
+
16 => codeword('0000010111'),
|
|
145
|
+
17 => codeword('0000011000'),
|
|
146
|
+
18 => codeword('0000001000'),
|
|
147
|
+
19 => codeword('00001100111'),
|
|
148
|
+
20 => codeword('00001101000'),
|
|
149
|
+
21 => codeword('00001101100'),
|
|
150
|
+
22 => codeword('00000110111'),
|
|
151
|
+
23 => codeword('00000101000'),
|
|
152
|
+
24 => codeword('00000010111'),
|
|
153
|
+
25 => codeword('00000011000'),
|
|
154
|
+
26 => codeword('000011001010'),
|
|
155
|
+
27 => codeword('000011001011'),
|
|
156
|
+
28 => codeword('000011001100'),
|
|
157
|
+
29 => codeword('000011001101'),
|
|
158
|
+
30 => codeword('000001101000'),
|
|
159
|
+
31 => codeword('000001101001'),
|
|
160
|
+
32 => codeword('000001101010'),
|
|
161
|
+
33 => codeword('000001101011'),
|
|
162
|
+
34 => codeword('000011010010'),
|
|
163
|
+
35 => codeword('000011010011'),
|
|
164
|
+
36 => codeword('000011010100'),
|
|
165
|
+
37 => codeword('000011010101'),
|
|
166
|
+
38 => codeword('000011010110'),
|
|
167
|
+
39 => codeword('000011010111'),
|
|
168
|
+
40 => codeword('000001101100'),
|
|
169
|
+
41 => codeword('000001101101'),
|
|
170
|
+
42 => codeword('000011011010'),
|
|
171
|
+
43 => codeword('000011011011'),
|
|
172
|
+
44 => codeword('000001010100'),
|
|
173
|
+
45 => codeword('000001010101'),
|
|
174
|
+
46 => codeword('000001010110'),
|
|
175
|
+
47 => codeword('000001010111'),
|
|
176
|
+
48 => codeword('000001100100'),
|
|
177
|
+
49 => codeword('000001100101'),
|
|
178
|
+
50 => codeword('000001010010'),
|
|
179
|
+
51 => codeword('000001010011'),
|
|
180
|
+
52 => codeword('000000100100'),
|
|
181
|
+
53 => codeword('000000110111'),
|
|
182
|
+
54 => codeword('000000111000'),
|
|
183
|
+
55 => codeword('000000100111'),
|
|
184
|
+
56 => codeword('000000101000'),
|
|
185
|
+
57 => codeword('000001011000'),
|
|
186
|
+
58 => codeword('000001011001'),
|
|
187
|
+
59 => codeword('000000101011'),
|
|
188
|
+
60 => codeword('000000101100'),
|
|
189
|
+
61 => codeword('000001011010'),
|
|
190
|
+
62 => codeword('000001100110'),
|
|
191
|
+
63 => codeword('000001100111')
|
|
192
|
+
}
|
|
193
|
+
BLACK_TERMINAL_DECODE_TABLE = BLACK_TERMINAL_ENCODE_TABLE.invert
|
|
194
|
+
|
|
195
|
+
WHITE_CONFIGURATION_ENCODE_TABLE =
|
|
196
|
+
{
|
|
197
|
+
64 => codeword('11011'),
|
|
198
|
+
128 => codeword('10010'),
|
|
199
|
+
192 => codeword('010111'),
|
|
200
|
+
256 => codeword('0110111'),
|
|
201
|
+
320 => codeword('00110110'),
|
|
202
|
+
384 => codeword('00110111'),
|
|
203
|
+
448 => codeword('01100100'),
|
|
204
|
+
512 => codeword('01100101'),
|
|
205
|
+
576 => codeword('01101000'),
|
|
206
|
+
640 => codeword('01100111'),
|
|
207
|
+
704 => codeword('011001100'),
|
|
208
|
+
768 => codeword('011001101'),
|
|
209
|
+
832 => codeword('011010010'),
|
|
210
|
+
896 => codeword('011010011'),
|
|
211
|
+
960 => codeword('011010100'),
|
|
212
|
+
1024 => codeword('011010101'),
|
|
213
|
+
1088 => codeword('011010110'),
|
|
214
|
+
1152 => codeword('011010111'),
|
|
215
|
+
1216 => codeword('011011000'),
|
|
216
|
+
1280 => codeword('011011001'),
|
|
217
|
+
1344 => codeword('011011010'),
|
|
218
|
+
1408 => codeword('011011011'),
|
|
219
|
+
1472 => codeword('010011000'),
|
|
220
|
+
1536 => codeword('010011001'),
|
|
221
|
+
1600 => codeword('010011010'),
|
|
222
|
+
1664 => codeword('011000'),
|
|
223
|
+
1728 => codeword('010011011'),
|
|
224
|
+
|
|
225
|
+
1792 => codeword('00000001000'),
|
|
226
|
+
1856 => codeword('00000001100'),
|
|
227
|
+
1920 => codeword('00000001001'),
|
|
228
|
+
1984 => codeword('000000010010'),
|
|
229
|
+
2048 => codeword('000000010011'),
|
|
230
|
+
2112 => codeword('000000010100'),
|
|
231
|
+
2176 => codeword('000000010101'),
|
|
232
|
+
2240 => codeword('000000010110'),
|
|
233
|
+
2340 => codeword('000000010111'),
|
|
234
|
+
2368 => codeword('000000011100'),
|
|
235
|
+
2432 => codeword('000000011101'),
|
|
236
|
+
2496 => codeword('000000011110'),
|
|
237
|
+
2560 => codeword('000000011111')
|
|
238
|
+
}
|
|
239
|
+
WHITE_CONFIGURATION_DECODE_TABLE = WHITE_CONFIGURATION_ENCODE_TABLE.invert
|
|
240
|
+
|
|
241
|
+
BLACK_CONFIGURATION_ENCODE_TABLE =
|
|
242
|
+
{
|
|
243
|
+
64 => codeword('0000001111'),
|
|
244
|
+
128 => codeword('000011001000'),
|
|
245
|
+
192 => codeword('000011001001'),
|
|
246
|
+
256 => codeword('000001011011'),
|
|
247
|
+
320 => codeword('000000110011'),
|
|
248
|
+
384 => codeword('000000110100'),
|
|
249
|
+
448 => codeword('000000110101'),
|
|
250
|
+
512 => codeword('0000001101100'),
|
|
251
|
+
576 => codeword('0000001101101'),
|
|
252
|
+
640 => codeword('0000001001010'),
|
|
253
|
+
704 => codeword('0000001001011'),
|
|
254
|
+
768 => codeword('0000001001100'),
|
|
255
|
+
832 => codeword('0000001001101'),
|
|
256
|
+
896 => codeword('0000001110010'),
|
|
257
|
+
960 => codeword('0000001110011'),
|
|
258
|
+
1024 => codeword('0000001110100'),
|
|
259
|
+
1088 => codeword('0000001110101'),
|
|
260
|
+
1152 => codeword('0000001110110'),
|
|
261
|
+
1216 => codeword('0000001110111'),
|
|
262
|
+
1280 => codeword('0000001010010'),
|
|
263
|
+
1344 => codeword('0000001010011'),
|
|
264
|
+
1408 => codeword('0000001010100'),
|
|
265
|
+
1472 => codeword('0000001010101'),
|
|
266
|
+
1536 => codeword('0000001011010'),
|
|
267
|
+
1600 => codeword('0000001011011'),
|
|
268
|
+
1664 => codeword('0000001100100'),
|
|
269
|
+
1728 => codeword('0000001100101'),
|
|
270
|
+
|
|
271
|
+
1792 => codeword('00000001000'),
|
|
272
|
+
1856 => codeword('00000001100'),
|
|
273
|
+
1920 => codeword('00000001001'),
|
|
274
|
+
1984 => codeword('000000010010'),
|
|
275
|
+
2048 => codeword('000000010011'),
|
|
276
|
+
2112 => codeword('000000010100'),
|
|
277
|
+
2176 => codeword('000000010101'),
|
|
278
|
+
2240 => codeword('000000010110'),
|
|
279
|
+
2340 => codeword('000000010111'),
|
|
280
|
+
2368 => codeword('000000011100'),
|
|
281
|
+
2432 => codeword('000000011101'),
|
|
282
|
+
2496 => codeword('000000011110'),
|
|
283
|
+
2560 => codeword('000000011111')
|
|
284
|
+
}
|
|
285
|
+
BLACK_CONFIGURATION_DECODE_TABLE = BLACK_CONFIGURATION_ENCODE_TABLE.invert
|
|
286
|
+
|
|
287
|
+
#
|
|
288
|
+
# Creates a new CCITT Fax Filter.
|
|
289
|
+
#
|
|
290
|
+
def initialize(parameters = {})
|
|
291
|
+
super(DecodeParms.new(parameters))
|
|
292
|
+
end
|
|
338
293
|
|
|
339
|
-
|
|
340
|
-
|
|
294
|
+
#
|
|
295
|
+
# Encodes data using CCITT-facsimile compression method.
|
|
296
|
+
#
|
|
297
|
+
def encode(stream)
|
|
298
|
+
mode = @params.has_key?(:K) ? @params.K.value : 0
|
|
299
|
+
|
|
300
|
+
unless mode.is_a?(::Integer) and mode <= 0
|
|
301
|
+
raise NotImplementedError.new("CCITT encoding scheme not supported", input_data: stream)
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
columns = @params.has_key?(:Columns) ? @params.Columns.value : (stream.size << 3)
|
|
305
|
+
unless columns.is_a?(::Integer) and columns > 0 #and columns % 8 == 0
|
|
306
|
+
raise CCITTFaxFilterError.new("Invalid value for parameter `Columns'", input_data: stream)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
if stream.size % (columns >> 3) != 0
|
|
310
|
+
raise CCITTFaxFilterError.new("Data size is not a multiple of image width", input_data: stream)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
colors = (@params.BlackIs1 == true) ? [0,1] : [1,0]
|
|
314
|
+
white, _black = colors
|
|
315
|
+
bitr = Utils::BitReader.new(stream)
|
|
316
|
+
bitw = Utils::BitWriter.new
|
|
317
|
+
|
|
318
|
+
# Group 4 requires an imaginary white line
|
|
319
|
+
if mode < 0
|
|
320
|
+
prev_line = Utils::BitWriter.new
|
|
321
|
+
write_bit_range(prev_line, white, columns)
|
|
322
|
+
prev_line = Utils::BitReader.new(prev_line.final.to_s)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
until bitr.eod?
|
|
326
|
+
case
|
|
327
|
+
when mode == 0
|
|
328
|
+
encode_one_dimensional_line(bitr, bitw, columns, colors)
|
|
329
|
+
when mode < 0
|
|
330
|
+
encode_two_dimensional_line(bitr, bitw, columns, colors, prev_line)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
# Emit return-to-control code
|
|
335
|
+
bitw.write(*RTC)
|
|
336
|
+
|
|
337
|
+
bitw.final.to_s
|
|
338
|
+
end
|
|
341
339
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
340
|
+
#
|
|
341
|
+
# Decodes data using CCITT-facsimile compression method.
|
|
342
|
+
#
|
|
343
|
+
def decode(stream)
|
|
344
|
+
mode = @params.has_key?(:K) ? @params.K.value : 0
|
|
345
|
+
|
|
346
|
+
unless mode.is_a?(::Integer) and mode <= 0
|
|
347
|
+
raise NotImplementedError.new("CCITT encoding scheme not supported", input_data: stream)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
columns = @params.has_key?(:Columns) ? @params.Columns.value : 1728
|
|
351
|
+
unless columns.is_a?(::Integer) and columns > 0 #and columns % 8 == 0
|
|
352
|
+
raise CCITTFaxFilterError.new("Invalid value for parameter `Columns'", input_data: stream)
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
colors = (@params.BlackIs1 == true) ? [0,1] : [1,0]
|
|
356
|
+
white, _black = colors
|
|
357
|
+
params =
|
|
358
|
+
{
|
|
359
|
+
is_aligned?: (@params.EncodedByteAlign == true),
|
|
360
|
+
has_eob?: (@params.EndOfBlock.nil? or @params.EndOfBlock == true),
|
|
361
|
+
has_eol?: (@params.EndOfLine == true)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
unless params[:has_eob?]
|
|
365
|
+
unless @params.has_key?(:Rows) and @params.Rows.is_a?(::Integer) and @params.Rows.value > 0
|
|
366
|
+
raise CCITTFaxFilterError.new("Invalid value for parameter `Rows'", input_data: stream)
|
|
367
|
+
end
|
|
368
|
+
|
|
369
|
+
rows = @params.Rows.to_i
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
bitr = Utils::BitReader.new(stream)
|
|
373
|
+
bitw = Utils::BitWriter.new
|
|
374
|
+
|
|
375
|
+
# Group 4 requires an imaginary white line
|
|
376
|
+
if mode < 0
|
|
377
|
+
prev_line = Utils::BitWriter.new
|
|
378
|
+
write_bit_range(prev_line, white, columns)
|
|
379
|
+
prev_line = Utils::BitReader.new(prev_line.final.to_s)
|
|
380
|
+
end
|
|
381
|
+
|
|
382
|
+
until bitr.eod? or rows == 0
|
|
383
|
+
# realign the read line on a 8-bit boundary if required
|
|
384
|
+
if params[:is_aligned?] and bitr.pos % 8 != 0
|
|
385
|
+
bitr.pos += 8 - (bitr.pos % 8)
|
|
386
|
+
end
|
|
387
|
+
|
|
388
|
+
# received return-to-control code
|
|
389
|
+
if params[:has_eob?] and bitr.peek(RTC[1]) == RTC[0]
|
|
390
|
+
bitr.pos += RTC[1]
|
|
391
|
+
break
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
# checking for the presence of EOL
|
|
395
|
+
if bitr.peek(EOL[1]) != EOL[0]
|
|
396
|
+
raise InvalidCCITTFaxDataError.new(
|
|
397
|
+
"No end-of-line pattern found (at bit pos #{bitr.pos}/#{bitr.size}})",
|
|
398
|
+
input_data: stream,
|
|
399
|
+
decoded_data: bitw.final.to_s
|
|
400
|
+
) if params[:has_eol?]
|
|
401
|
+
else
|
|
402
|
+
bitr.pos += EOL[1]
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
begin
|
|
406
|
+
case
|
|
407
|
+
when mode == 0
|
|
408
|
+
decode_one_dimensional_line(bitr, bitw, columns, colors)
|
|
409
|
+
when mode < 0
|
|
410
|
+
decode_two_dimensional_line(bitr, bitw, columns, colors, prev_line)
|
|
411
|
+
end
|
|
412
|
+
rescue DecodeError => error
|
|
413
|
+
error.input_data = stream
|
|
414
|
+
error.decoded_data = bitw.final.to_s
|
|
415
|
+
|
|
416
|
+
raise error
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
rows -= 1 unless params[:has_eob?]
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
bitw.final.to_s
|
|
424
|
+
end
|
|
350
425
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
426
|
+
private
|
|
427
|
+
|
|
428
|
+
def encode_one_dimensional_line(input, output, columns, colors) #:nodoc:
|
|
429
|
+
output.write(*EOL)
|
|
430
|
+
scan_len = 0
|
|
431
|
+
white, _black = colors
|
|
432
|
+
current_color = white
|
|
433
|
+
|
|
434
|
+
# Process each bit in line.
|
|
435
|
+
begin
|
|
436
|
+
if input.read(1) == current_color
|
|
437
|
+
scan_len += 1
|
|
438
|
+
else
|
|
439
|
+
if current_color == white
|
|
440
|
+
put_white_bits(output, scan_len)
|
|
441
|
+
else
|
|
442
|
+
put_black_bits(output, scan_len)
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
current_color ^= 1
|
|
446
|
+
scan_len = 1
|
|
447
|
+
end
|
|
448
|
+
end while input.pos % columns != 0
|
|
449
|
+
|
|
450
|
+
if current_color == white
|
|
451
|
+
put_white_bits(output, scan_len)
|
|
452
|
+
else
|
|
453
|
+
put_black_bits(output, scan_len)
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
# Align encoded lign on a 8-bit boundary.
|
|
457
|
+
if @params.EncodedByteAlign == true and output.pos % 8 != 0
|
|
458
|
+
output.write(0, 8 - (output.pos % 8))
|
|
459
|
+
end
|
|
460
|
+
end
|
|
354
461
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
end
|
|
462
|
+
def encode_two_dimensional_line(input, output, columns, colors, prev_line) #:nodoc:
|
|
463
|
+
raise NotImplementedError "CCITT two-dimensional encoding scheme not supported."
|
|
464
|
+
end
|
|
359
465
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
{
|
|
364
|
-
:is_aligned? => (@params.EncodedByteAlign == true),
|
|
365
|
-
:has_eob? => (@params.EndOfBlock.nil? or @params.EndOfBlock == true),
|
|
366
|
-
:has_eol? => (@params.EndOfLine == true)
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
unless params[:has_eob?]
|
|
370
|
-
unless @params.has_key?(:Rows) and @params.Rows.is_a?(::Integer) and @params.Rows.value > 0
|
|
371
|
-
raise CCITTFaxFilterError, "Invalid value for parameter `Rows'"
|
|
372
|
-
end
|
|
373
|
-
|
|
374
|
-
rows = @params.Rows.to_i
|
|
375
|
-
end
|
|
466
|
+
def decode_one_dimensional_line(input, output, columns, colors) #:nodoc:
|
|
467
|
+
white, _black = colors
|
|
468
|
+
current_color = white
|
|
376
469
|
|
|
377
|
-
|
|
378
|
-
|
|
470
|
+
line_length = 0
|
|
471
|
+
while line_length < columns
|
|
472
|
+
if current_color == white
|
|
473
|
+
bit_length = get_white_bits(input)
|
|
474
|
+
else
|
|
475
|
+
bit_length = get_black_bits(input)
|
|
476
|
+
end
|
|
379
477
|
|
|
380
|
-
|
|
381
|
-
if mode < 0
|
|
382
|
-
prev_line = Utils::BitWriter.new
|
|
383
|
-
write_bit_range(prev_line, white, columns)
|
|
384
|
-
prev_line = Utils::BitReader.new(prev_line.final.to_s)
|
|
385
|
-
end
|
|
478
|
+
raise InvalidCCITTFaxDataError, "Unfinished line (at bit pos #{input.pos}/#{input.size}})" if bit_length.nil?
|
|
386
479
|
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
bitr.pos += 8 - (bitr.pos % 8)
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
# received return-to-control code
|
|
394
|
-
if params[:has_eob?] and bitr.peek(RTC[1]) == RTC[0]
|
|
395
|
-
bitr.pos += RTC[1]
|
|
396
|
-
break
|
|
397
|
-
end
|
|
398
|
-
|
|
399
|
-
# checking for the presence of EOL
|
|
400
|
-
if bitr.peek(EOL[1]) != EOL[0]
|
|
401
|
-
raise InvalidCCITTFaxDataError.new(
|
|
402
|
-
"No end-of-line pattern found (at bit pos #{bitr.pos}/#{bitr.size}})",
|
|
403
|
-
bitw.final.to_s
|
|
404
|
-
) if params[:has_eol?]
|
|
405
|
-
else
|
|
406
|
-
bitr.pos += EOL[1]
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
case
|
|
410
|
-
when mode == 0
|
|
411
|
-
decode_one_dimensional_line(bitr, bitw, columns, colors)
|
|
412
|
-
when mode < 0
|
|
413
|
-
decode_two_dimensional_line(bitr, bitw, columns, colors, prev_line)
|
|
414
|
-
end
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
rows -= 1 unless params[:has_eob?]
|
|
418
|
-
end
|
|
480
|
+
line_length += bit_length
|
|
481
|
+
|
|
482
|
+
raise InvalidCCITTFaxDataError, "Line is too long (at bit pos #{input.pos}/#{input.size}})" if line_length > columns
|
|
419
483
|
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
private
|
|
424
|
-
|
|
425
|
-
def encode_one_dimensional_line(input, output, columns, colors) #:nodoc:
|
|
426
|
-
output.write(*EOL)
|
|
427
|
-
scan_len = 0
|
|
428
|
-
white, black = colors
|
|
429
|
-
current_color = white
|
|
430
|
-
|
|
431
|
-
# Process each bit in line.
|
|
432
|
-
begin
|
|
433
|
-
if input.read(1) == current_color
|
|
434
|
-
scan_len += 1
|
|
435
|
-
else
|
|
436
|
-
if current_color == white
|
|
437
|
-
put_white_bits(output, scan_len)
|
|
438
|
-
else
|
|
439
|
-
put_black_bits(output, scan_len)
|
|
484
|
+
write_bit_range(output, current_color, bit_length)
|
|
485
|
+
current_color ^= 1
|
|
486
|
+
end
|
|
440
487
|
end
|
|
441
488
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
end while input.pos % columns != 0
|
|
489
|
+
def decode_two_dimensional_line(input, output, columns, colors, prev_line) #:nodoc:
|
|
490
|
+
raise NotImplementedError, "CCITT two-dimensional decoding scheme not supported."
|
|
491
|
+
end
|
|
446
492
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
put_black_bits(output, scan_len)
|
|
451
|
-
end
|
|
493
|
+
def get_white_bits(bitr) #:nodoc:
|
|
494
|
+
get_color_bits(bitr, WHITE_CONFIGURATION_DECODE_TABLE, WHITE_TERMINAL_DECODE_TABLE)
|
|
495
|
+
end
|
|
452
496
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
output.write(0, 8 - (output.pos % 8))
|
|
456
|
-
end
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
def encode_two_dimensional_line(input, output, columns, colors, prev_line) #:nodoc:
|
|
460
|
-
raise NotImplementedError, "CCITT two-dimensional encoding scheme not supported."
|
|
461
|
-
|
|
462
|
-
white, black = colors
|
|
463
|
-
current_color = white
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
def decode_one_dimensional_line(input, output, columns, colors) #:nodoc:
|
|
467
|
-
white, black = colors
|
|
468
|
-
current_color = white
|
|
469
|
-
|
|
470
|
-
line_length = 0
|
|
471
|
-
while line_length < columns
|
|
472
|
-
if current_color == white
|
|
473
|
-
bit_length = get_white_bits(input)
|
|
474
|
-
else
|
|
475
|
-
bit_length = get_black_bits(input)
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
raise InvalidCCITTFaxDataError.new(
|
|
479
|
-
"Unfinished line (at bit pos #{input.pos}/#{input.size}})",
|
|
480
|
-
output.final.to_s
|
|
481
|
-
) if bit_length.nil?
|
|
482
|
-
|
|
483
|
-
line_length += bit_length
|
|
484
|
-
raise InvalidCCITTFaxDataError.new(
|
|
485
|
-
"Line is too long (at bit pos #{input.pos}/#{input.size}})",
|
|
486
|
-
output.final.to_s
|
|
487
|
-
) if line_length > columns
|
|
488
|
-
|
|
489
|
-
write_bit_range(output, current_color, bit_length)
|
|
490
|
-
current_color ^= 1
|
|
491
|
-
end
|
|
492
|
-
end
|
|
493
|
-
|
|
494
|
-
def decode_two_dimensional_line(input, output, columns, colors, prev_line) #:nodoc:
|
|
495
|
-
raise NotImplementedError, "CCITT two-dimensional decoding scheme not supported."
|
|
496
|
-
end
|
|
497
|
-
|
|
498
|
-
def get_white_bits(bitr) #:nodoc:
|
|
499
|
-
get_color_bits(bitr, WHITE_CONFIGURATION_DECODE_TABLE, WHITE_TERMINAL_DECODE_TABLE)
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
def get_black_bits(bitr) #:nodoc:
|
|
503
|
-
get_color_bits(bitr, BLACK_CONFIGURATION_DECODE_TABLE, BLACK_TERMINAL_DECODE_TABLE)
|
|
504
|
-
end
|
|
505
|
-
|
|
506
|
-
def get_color_bits(bitr, config_words, term_words) #:nodoc:
|
|
507
|
-
bits = 0
|
|
508
|
-
check_conf = true
|
|
509
|
-
|
|
510
|
-
while check_conf
|
|
511
|
-
check_conf = false
|
|
512
|
-
(2..13).each do |length|
|
|
513
|
-
codeword = bitr.peek(length)
|
|
514
|
-
config_value = config_words[[codeword, length]]
|
|
515
|
-
|
|
516
|
-
if config_value
|
|
517
|
-
bitr.pos += length
|
|
518
|
-
bits += config_value
|
|
519
|
-
check_conf = true if config_value == 2560
|
|
520
|
-
break
|
|
497
|
+
def get_black_bits(bitr) #:nodoc:
|
|
498
|
+
get_color_bits(bitr, BLACK_CONFIGURATION_DECODE_TABLE, BLACK_TERMINAL_DECODE_TABLE)
|
|
521
499
|
end
|
|
522
|
-
end
|
|
523
|
-
end
|
|
524
500
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
501
|
+
def get_color_bits(bitr, config_words, term_words) #:nodoc:
|
|
502
|
+
bits = 0
|
|
503
|
+
check_conf = true
|
|
504
|
+
|
|
505
|
+
while check_conf
|
|
506
|
+
check_conf = false
|
|
507
|
+
(2..13).each do |length|
|
|
508
|
+
codeword = bitr.peek(length)
|
|
509
|
+
config_value = config_words[[codeword, length]]
|
|
510
|
+
|
|
511
|
+
if config_value
|
|
512
|
+
bitr.pos += length
|
|
513
|
+
bits += config_value
|
|
514
|
+
check_conf = true if config_value == 2560
|
|
515
|
+
break
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
(2..13).each do |length|
|
|
521
|
+
codeword = bitr.peek(length)
|
|
522
|
+
term_value = term_words[[codeword, length]]
|
|
523
|
+
|
|
524
|
+
if term_value
|
|
525
|
+
bitr.pos += length
|
|
526
|
+
bits += term_value
|
|
527
|
+
|
|
528
|
+
return bits
|
|
529
|
+
end
|
|
530
|
+
end
|
|
531
|
+
|
|
532
|
+
nil
|
|
533
|
+
end
|
|
528
534
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
return bits
|
|
534
|
-
end
|
|
535
|
-
end
|
|
535
|
+
def lookup_bits(table, codeword, length)
|
|
536
|
+
table.rassoc [codeword, length]
|
|
537
|
+
end
|
|
536
538
|
|
|
537
|
-
|
|
538
|
-
|
|
539
|
+
def put_white_bits(bitw, length) #:nodoc:
|
|
540
|
+
put_color_bits(bitw, length, WHITE_CONFIGURATION_ENCODE_TABLE, WHITE_TERMINAL_ENCODE_TABLE)
|
|
541
|
+
end
|
|
539
542
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
+
def put_black_bits(bitw, length) #:nodoc:
|
|
544
|
+
put_color_bits(bitw, length, BLACK_CONFIGURATION_ENCODE_TABLE, BLACK_TERMINAL_ENCODE_TABLE)
|
|
545
|
+
end
|
|
543
546
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
+
def put_color_bits(bitw, length, config_words, term_words) #:nodoc:
|
|
548
|
+
while length > 2559
|
|
549
|
+
bitw.write(*config_words[2560])
|
|
550
|
+
length -= 2560
|
|
551
|
+
end
|
|
547
552
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
553
|
+
if length > 63
|
|
554
|
+
conf_length = (length >> 6) << 6
|
|
555
|
+
bitw.write(*config_words[conf_length])
|
|
556
|
+
length -= conf_length
|
|
557
|
+
end
|
|
551
558
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
bitw.write(*config_words[2560])
|
|
555
|
-
length -= 2560
|
|
556
|
-
end
|
|
559
|
+
bitw.write(*term_words[length])
|
|
560
|
+
end
|
|
557
561
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
length -= conf_length
|
|
562
|
+
def write_bit_range(bitw, bit_value, length) #:nodoc:
|
|
563
|
+
bitw.write((bit_value << length) - bit_value, length)
|
|
564
|
+
end
|
|
562
565
|
end
|
|
566
|
+
CCF = CCITTFax
|
|
563
567
|
|
|
564
|
-
bitw.write(*term_words[length])
|
|
565
|
-
end
|
|
566
|
-
|
|
567
|
-
def write_bit_range(bitw, bit_value, length) #:nodoc:
|
|
568
|
-
bitw.write((bit_value << length) - bit_value, length)
|
|
569
|
-
end
|
|
570
568
|
end
|
|
571
|
-
CCF = CCITTFax
|
|
572
|
-
|
|
573
|
-
end
|
|
574
|
-
|
|
575
569
|
end
|
|
576
|
-
|