pnm 0.2.1 → 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/README.md +4 -3
- data/Rakefile +1 -1
- data/benchmark/bm_converter.rb +1 -1
- data/lib/pnm.rb +9 -7
- data/lib/pnm/converter.rb +24 -5
- data/lib/pnm/exceptions.rb +10 -0
- data/lib/pnm/image.rb +111 -15
- data/lib/pnm/parser.rb +39 -4
- data/lib/pnm/version.rb +2 -2
- data/test/test_converter.rb +1 -1
- data/test/test_exceptions.rb +230 -0
- data/test/test_image.rb +15 -1
- data/test/test_parser.rb +12 -12
- data/test/test_pnm.rb +1 -1
- metadata +22 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef19db0d86c0c55bca6a6b6c3f9a5d4eaaac62f6
|
4
|
+
data.tar.gz: ffa665ee3688f90f201045230818b97dd5c11b22
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8ff711e119c0950b4d249c9171735b0baf8e5c9401e10e8160e047def08df4d53f1db203be41a7220bd5e6a09945e56e308141fa23877b059b4242097916be7
|
7
|
+
data.tar.gz: 18d891b4969653b32f4d7d5c253a673479c14fcc3b53ea918b282528737a108714463538150552886d39ee61ae777f99c9950a23333869564262c26ca3e43212
|
data/README.md
CHANGED
@@ -80,10 +80,11 @@ Requirements
|
|
80
80
|
|
81
81
|
- PNM has been tested with
|
82
82
|
|
83
|
+
- Ruby 2.1.0,
|
83
84
|
- Ruby 2.0.0 on Linux and on Windows,
|
84
85
|
- Ruby 1.9.3,
|
85
|
-
- JRuby 1.7.
|
86
|
-
- Rubinius 2.2.
|
86
|
+
- JRuby 1.7.10,
|
87
|
+
- Rubinius 2.2.4.
|
87
88
|
|
88
89
|
Documentation
|
89
90
|
-------------
|
@@ -98,7 +99,7 @@ Report bugs on the PNM home page: <https://github.com/stomar/pnm/>
|
|
98
99
|
License
|
99
100
|
-------
|
100
101
|
|
101
|
-
Copyright © 2013 Marcus Stollsteimer
|
102
|
+
Copyright © 2013-2014 Marcus Stollsteimer
|
102
103
|
|
103
104
|
`PNM` is free software: you can redistribute it and/or modify
|
104
105
|
it under the terms of the GNU General Public License version 3 or later (GPLv3+),
|
data/Rakefile
CHANGED
data/benchmark/bm_converter.rb
CHANGED
data/lib/pnm.rb
CHANGED
@@ -6,6 +6,7 @@ require_relative 'pnm/version'
|
|
6
6
|
require_relative 'pnm/image'
|
7
7
|
require_relative 'pnm/parser'
|
8
8
|
require_relative 'pnm/converter'
|
9
|
+
require_relative 'pnm/exceptions'
|
9
10
|
|
10
11
|
|
11
12
|
# PNM is a pure Ruby library for creating, reading,
|
@@ -68,7 +69,7 @@ require_relative 'pnm/converter'
|
|
68
69
|
#
|
69
70
|
# == Author
|
70
71
|
#
|
71
|
-
# Copyright (C) 2013 Marcus Stollsteimer
|
72
|
+
# Copyright (C) 2013-2014 Marcus Stollsteimer
|
72
73
|
#
|
73
74
|
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
74
75
|
#
|
@@ -94,7 +95,7 @@ module PNM
|
|
94
95
|
TAGLINE = 'create/read/write PNM image files (PBM, PGM, PPM)' # :nodoc:
|
95
96
|
|
96
97
|
COPYRIGHT = <<-copyright.gsub(/^ +/, '') # :nodoc:
|
97
|
-
Copyright (C)
|
98
|
+
Copyright (C) 2013-2014 Marcus Stollsteimer.
|
98
99
|
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
99
100
|
This is free software: you are free to change and redistribute it.
|
100
101
|
There is NO WARRANTY, to the extent permitted by law.
|
@@ -104,12 +105,13 @@ module PNM
|
|
104
105
|
#
|
105
106
|
# Returns a PNM::Image object.
|
106
107
|
def self.read(file)
|
107
|
-
raw_data = nil
|
108
108
|
if file.kind_of?(String)
|
109
109
|
raw_data = File.binread(file)
|
110
|
-
|
110
|
+
elsif file.respond_to?(:binmode)
|
111
111
|
file.binmode
|
112
112
|
raw_data = file.read
|
113
|
+
else
|
114
|
+
raise PNM::ArgumentError, "wrong argument type"
|
113
115
|
end
|
114
116
|
|
115
117
|
content = Parser.parse(raw_data)
|
@@ -135,9 +137,9 @@ module PNM
|
|
135
137
|
encoding = :binary
|
136
138
|
end
|
137
139
|
|
138
|
-
width = content[:width]
|
139
|
-
height = content[:height]
|
140
|
-
maxgray = content[:maxgray]
|
140
|
+
width = content[:width]
|
141
|
+
height = content[:height]
|
142
|
+
maxgray = content[:maxgray]
|
141
143
|
pixels = if encoding == :ascii
|
142
144
|
Converter.ascii2array(type, width, height, content[:data])
|
143
145
|
else
|
data/lib/pnm/converter.rb
CHANGED
@@ -5,7 +5,7 @@ module PNM
|
|
5
5
|
|
6
6
|
# Returns the number of bytes needed for one row of pixels
|
7
7
|
# (in binary encoding).
|
8
|
-
def self.byte_width(type, width)
|
8
|
+
def self.byte_width(type, width) # :nodoc:
|
9
9
|
case type
|
10
10
|
when :pbm
|
11
11
|
(width - 1) / 8 + 1
|
@@ -24,7 +24,10 @@ module PNM
|
|
24
24
|
#
|
25
25
|
# Returns a two-dimensional array of bilevel, gray, or RGB values.
|
26
26
|
def self.ascii2array(type, width, height, data)
|
27
|
-
|
27
|
+
values_per_row = type == :ppm ? 3 * width : width
|
28
|
+
|
29
|
+
values = convert_to_integers(data)
|
30
|
+
assert_data_size(values.size, values_per_row * height)
|
28
31
|
|
29
32
|
case type
|
30
33
|
when :pbm, :pgm
|
@@ -50,9 +53,7 @@ module PNM
|
|
50
53
|
data.slice!(-1)
|
51
54
|
end
|
52
55
|
|
53
|
-
|
54
|
-
raise 'data size does not match expected size'
|
55
|
-
end
|
56
|
+
assert_data_size(data.size, bytes_per_row * height)
|
56
57
|
|
57
58
|
case type
|
58
59
|
when :pbm
|
@@ -101,5 +102,23 @@ module PNM
|
|
101
102
|
|
102
103
|
data_string
|
103
104
|
end
|
105
|
+
|
106
|
+
def self.convert_to_integers(data) # :nodoc:
|
107
|
+
data.gsub(/\A[ \t\r\n]+/, '').split(/[ \t\r\n]+/).map do |value|
|
108
|
+
Integer(value)
|
109
|
+
end
|
110
|
+
rescue ::ArgumentError => e
|
111
|
+
if e.message.start_with?('invalid value for Integer')
|
112
|
+
raise PNM::DataError, "invalid pixel value: Integer expected"
|
113
|
+
else
|
114
|
+
raise
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.assert_data_size(actual, expected) # :nodoc:
|
119
|
+
unless actual == expected
|
120
|
+
raise PNM::DataSizeError, 'data size does not match expected size'
|
121
|
+
end
|
122
|
+
end
|
104
123
|
end
|
105
124
|
end
|
data/lib/pnm/image.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
module PNM
|
2
2
|
|
3
|
-
# Class for +PBM+, +PGM+, and +PPM+ images.
|
3
|
+
# Class for +PBM+, +PGM+, and +PPM+ images.
|
4
|
+
#
|
5
|
+
# Images can be created from pixel values, see ::new,
|
6
|
+
# or read from a file or I/O stream, see PNM.read.
|
7
|
+
#
|
8
|
+
# See PNM module for examples.
|
4
9
|
class Image
|
5
10
|
|
6
11
|
# The type of the image. See ::new for details.
|
@@ -20,11 +25,13 @@ module PNM
|
|
20
25
|
# See ::new for details.
|
21
26
|
attr_reader :pixels
|
22
27
|
|
23
|
-
# An optional multiline comment string.
|
28
|
+
# An optional multiline comment string (or +nil+).
|
24
29
|
attr_reader :comment
|
25
30
|
|
26
31
|
# Creates an image from a two-dimensional array of bilevel,
|
27
32
|
# gray, or RGB values.
|
33
|
+
# The image type is guessed from the provided pixel data,
|
34
|
+
# unless it is explicitly set with the +type+ option.
|
28
35
|
#
|
29
36
|
# +pixels+:: The pixel data, given as a two-dimensional array of
|
30
37
|
#
|
@@ -33,38 +40,47 @@ module PNM
|
|
33
40
|
# * for PPM: an array of 3 values between 0 and +maxgray+,
|
34
41
|
# corresponding to red, green, and blue (RGB).
|
35
42
|
#
|
36
|
-
# PPM also accepts an array of bilevel or gray values.
|
37
|
-
#
|
38
43
|
# A value of 0 means that the color is turned off.
|
39
44
|
#
|
40
45
|
# Optional settings that can be specified in the +options+ hash:
|
41
46
|
#
|
42
47
|
# +type+:: The type of the image (+:pbm+, +:pgm+, or +:ppm+).
|
43
|
-
# By
|
44
|
-
# pixel data,
|
48
|
+
# By explicitly setting +type+, PGM images can be
|
49
|
+
# created from bilevel pixel data, and PPM images can be
|
50
|
+
# created from bilevel or gray pixel data.
|
45
51
|
# +maxgray+:: The maximum gray or color value.
|
46
52
|
# For PGM and PPM, +maxgray+ must be less or equal 255
|
47
53
|
# (the default value).
|
48
54
|
# For PBM pixel data, setting +maxgray+ implies a conversion
|
49
55
|
# to +:pgm+. If +type+ is explicitly set to +:pbm+,
|
50
56
|
# the +maxgray+ setting is disregarded.
|
51
|
-
# +comment+:: A multiline comment string
|
57
|
+
# +comment+:: A multiline comment string.
|
52
58
|
def initialize(pixels, options = {})
|
53
59
|
@type = options[:type]
|
54
|
-
@width = pixels.first.size
|
55
|
-
@height = pixels.size
|
56
60
|
@maxgray = options[:maxgray]
|
57
|
-
@comment =
|
61
|
+
@comment = options[:comment]
|
58
62
|
@pixels = pixels.dup
|
59
63
|
|
64
|
+
assert_valid_type if @type
|
65
|
+
assert_valid_maxgray if @maxgray
|
66
|
+
assert_valid_comment if @comment
|
67
|
+
assert_valid_array
|
68
|
+
|
69
|
+
@width = pixels.first.size
|
70
|
+
@height = pixels.size
|
71
|
+
|
60
72
|
@type ||= detect_type(@pixels, @maxgray)
|
61
73
|
|
74
|
+
assert_matching_type_and_data
|
75
|
+
|
62
76
|
if @type == :pbm
|
63
77
|
@maxgray = 1
|
64
78
|
else
|
65
79
|
@maxgray ||= 255
|
66
80
|
end
|
67
81
|
|
82
|
+
assert_valid_pixel_values
|
83
|
+
|
68
84
|
if type == :ppm && !pixels.first.first.kind_of?(Array)
|
69
85
|
@pixels.map! {|row| row.map {|pixel| gray_to_rgb(pixel) } }
|
70
86
|
end
|
@@ -113,17 +129,89 @@ module PNM
|
|
113
129
|
def detect_type(pixels, maxgray) # :nodoc:
|
114
130
|
if pixels.first.first.kind_of?(Array)
|
115
131
|
:ppm
|
116
|
-
elsif pixels.flatten.max
|
117
|
-
maxgray ? :pgm : :pbm
|
118
|
-
else
|
132
|
+
elsif maxgray || pixels.flatten.max > 1
|
119
133
|
:pgm
|
134
|
+
else
|
135
|
+
:pbm
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def assert_valid_array # :nodoc:
|
140
|
+
msg = "invalid pixel data: Array expected"
|
141
|
+
raise PNM::ArgumentError, msg unless Array === pixels
|
142
|
+
|
143
|
+
msg = "invalid pixel array"
|
144
|
+
raise PNM::DataError, msg unless Array === pixels.first
|
145
|
+
|
146
|
+
width = pixels.first.size
|
147
|
+
is_color = (Array === pixels.first.first)
|
148
|
+
|
149
|
+
pixels.each do |row|
|
150
|
+
raise PNM::DataError, msg unless Array === row && row.size == width
|
151
|
+
|
152
|
+
if is_color
|
153
|
+
row.each {|pixel| assert_valid_color_pixel(pixel) }
|
154
|
+
else
|
155
|
+
row.each {|pixel| assert_valid_pixel(pixel) }
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def assert_valid_pixel(pixel) # :nodoc:
|
161
|
+
unless Fixnum === pixel
|
162
|
+
msg = "invalid pixel value: Fixnum expected - #{pixel.inspect}"
|
163
|
+
raise PNM::DataError, msg
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def assert_valid_color_pixel(pixel) # :nodoc:
|
168
|
+
unless Array === pixel && pixel.map(&:class) == [Fixnum, Fixnum, Fixnum]
|
169
|
+
msg = "invalid pixel value: "
|
170
|
+
msg << "Array of 3 Fixnums expected - #{pixel.inspect}"
|
171
|
+
|
172
|
+
raise PNM::DataError, msg
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def assert_valid_type # :nodoc:
|
177
|
+
unless [:pbm, :pgm, :ppm].include?(type)
|
178
|
+
msg = "invalid image type - #{type.inspect}"
|
179
|
+
raise PNM::ArgumentError, msg
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def assert_matching_type_and_data # :nodoc:
|
184
|
+
if Array === pixels.first.first && [:pbm, :pgm].include?(type)
|
185
|
+
msg = "specified type does not match data - #{type.inspect}"
|
186
|
+
raise PNM::DataError, msg
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def assert_valid_maxgray # :nodoc:
|
191
|
+
unless Fixnum === maxgray && maxgray > 0 && maxgray <= 255
|
192
|
+
raise PNM::ArgumentError, "invalid maxgray value - #{maxgray.inspect}"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def assert_valid_comment # :nodoc:
|
197
|
+
unless String === comment
|
198
|
+
raise PNM::ArgumentError, "invalid comment value - #{comment.inspect}"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def assert_valid_pixel_values # :nodoc:
|
203
|
+
unless pixels.flatten.max <= maxgray
|
204
|
+
raise PNM::DataError, "invalid data: value(s) greater than maxgray"
|
205
|
+
end
|
206
|
+
unless pixels.flatten.min >= 0
|
207
|
+
raise PNM::DataError, "invalid data: value(s) less than zero"
|
120
208
|
end
|
121
209
|
end
|
122
210
|
|
123
211
|
def header(encoding) # :nodoc:
|
124
212
|
header = "#{PNM.magic_number[type][encoding]}\n"
|
125
|
-
|
126
|
-
|
213
|
+
comment_lines.each do |line|
|
214
|
+
header << (line.empty? ? "#\n" : "# #{line}\n")
|
127
215
|
end
|
128
216
|
header << "#{width} #{height}\n"
|
129
217
|
header << "#{maxgray}\n" unless type == :pbm
|
@@ -131,6 +219,14 @@ module PNM
|
|
131
219
|
header
|
132
220
|
end
|
133
221
|
|
222
|
+
def comment_lines # :nodoc:
|
223
|
+
return [] unless comment
|
224
|
+
return [''] if comment.empty?
|
225
|
+
|
226
|
+
keep_trailing_null_fields = -1 # magic value for split limit
|
227
|
+
comment.split(/\n/, keep_trailing_null_fields)
|
228
|
+
end
|
229
|
+
|
134
230
|
def to_ascii # :nodoc:
|
135
231
|
data_string = Converter.array2ascii(pixels)
|
136
232
|
|
data/lib/pnm/parser.rb
CHANGED
@@ -7,13 +7,13 @@ module PNM
|
|
7
7
|
#
|
8
8
|
# +content+:: A string containing the image file content.
|
9
9
|
#
|
10
|
-
# Returns a hash containing the parsed data
|
10
|
+
# Returns a hash containing the parsed data:
|
11
11
|
#
|
12
|
-
# * +:magic_number
|
12
|
+
# * +:magic_number+ (<tt>"P1"</tt>, ..., <tt>"P6"</tt>),
|
13
13
|
# * +:maxgray+ (only for PGM and PPM),
|
14
14
|
# * +:width+,
|
15
15
|
# * +:height+,
|
16
|
-
# * +:data
|
16
|
+
# * +:data+ (as string),
|
17
17
|
# * +:comments+ (only if present): an array of comment strings.
|
18
18
|
def self.parse(content)
|
19
19
|
content = content.dup
|
@@ -32,7 +32,7 @@ module PNM
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
|
35
|
+
assert_valid_magic_number(magic_number)
|
36
36
|
|
37
37
|
while tokens.size < token_number[magic_number]
|
38
38
|
content.gsub!(/\A[ \t\r\n]+/, '')
|
@@ -47,6 +47,18 @@ module PNM
|
|
47
47
|
|
48
48
|
width, height, maxgray = tokens
|
49
49
|
|
50
|
+
assert_integer(width, "width")
|
51
|
+
assert_integer(height, "height")
|
52
|
+
assert_integer(maxgray, "maxgray") if maxgray
|
53
|
+
|
54
|
+
width = width.to_i
|
55
|
+
height = height.to_i
|
56
|
+
maxgray = maxgray.to_i if maxgray
|
57
|
+
|
58
|
+
assert_value(width, "width") {|x| x > 0 }
|
59
|
+
assert_value(height, "height") {|x| x > 0 }
|
60
|
+
assert_value(maxgray, "maxgray") {|x| x > 0 && x <= 255 } if maxgray
|
61
|
+
|
50
62
|
result = {
|
51
63
|
:magic_number => magic_number,
|
52
64
|
:width => width,
|
@@ -78,9 +90,32 @@ module PNM
|
|
78
90
|
end
|
79
91
|
|
80
92
|
token, rest = content.split(delimiter, 2)
|
93
|
+
raise PNM::ParserError, 'not enough tokens in file' unless rest
|
94
|
+
|
81
95
|
content.replace(rest)
|
82
96
|
|
83
97
|
token
|
84
98
|
end
|
99
|
+
|
100
|
+
def self.assert_valid_magic_number(magic_number) # :nodoc:
|
101
|
+
unless %w{P1 P2 P3 P4 P5 P6}.include?(magic_number)
|
102
|
+
msg = "unknown magic number - `#{magic_number}'"
|
103
|
+
raise PNM::ParserError, msg
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def self.assert_integer(value_string, value_name) # :nodoc:
|
108
|
+
unless /\A[0-9]+\Z/ === value_string
|
109
|
+
msg = "#{value_name} must be an integer - `#{value_string}'"
|
110
|
+
raise PNM::ParserError, msg
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.assert_value(value, name) # :nodoc:
|
115
|
+
unless yield(value)
|
116
|
+
msg = "invalid #{name} value - `#{value}'"
|
117
|
+
raise PNM::ParserError, msg
|
118
|
+
end
|
119
|
+
end
|
85
120
|
end
|
86
121
|
end
|
data/lib/pnm/version.rb
CHANGED
data/test/test_converter.rb
CHANGED
@@ -0,0 +1,230 @@
|
|
1
|
+
# test_exceptions.rb: Unit tests for the PNM library.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2013-2014 Marcus Stollsteimer
|
4
|
+
|
5
|
+
require 'minitest/spec'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'stringio'
|
8
|
+
require 'pnm'
|
9
|
+
|
10
|
+
|
11
|
+
describe 'PNM::Image.new' do
|
12
|
+
|
13
|
+
it 'raises an exception for invalid data type (String)' do
|
14
|
+
data = '0'
|
15
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::ArgumentError
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'raises an exception for invalid type (String)' do
|
19
|
+
data = [[0, 0], [0, 0]]
|
20
|
+
lambda { PNM::Image.new(data, :type => 'pbm') }.must_raise PNM::ArgumentError
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raises an exception for invalid maxgray (String)' do
|
24
|
+
data = [[0, 0], [0, 0]]
|
25
|
+
lambda { PNM::Image.new(data, :maxgray => '255') }.must_raise PNM::ArgumentError
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'raises an exception for invalid maxgray (> 255)' do
|
29
|
+
data = [[0, 0], [0, 0]]
|
30
|
+
lambda { PNM::Image.new(data, :maxgray => 256) }.must_raise PNM::ArgumentError
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'raises an exception for invalid maxgray (0)' do
|
34
|
+
data = [[0, 0], [0, 0]]
|
35
|
+
lambda { PNM::Image.new(data, :maxgray => 0) }.must_raise PNM::ArgumentError
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'raises an exception for invalid comment (Fixnum)' do
|
39
|
+
data = [[0, 0], [0, 0]]
|
40
|
+
lambda { PNM::Image.new(data, :comment => 1) }.must_raise PNM::ArgumentError
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'raises an exception for image type and data mismatch (PBM)' do
|
44
|
+
data = [[[0,0,0], [0,0,0]], [[0,0,0], [0,0,0]]]
|
45
|
+
lambda { PNM::Image.new(data, :type => :pbm) }.must_raise PNM::DataError
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'raises an exception for image type and data mismatch (PGM)' do
|
49
|
+
data = [[[0,0,0], [0,0,0]], [[0,0,0], [0,0,0]]]
|
50
|
+
lambda { PNM::Image.new(data, :type => :pgm) }.must_raise PNM::DataError
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'raises an exception for non-integer pixel value (String)' do
|
54
|
+
data = [[0, 0], ['X', 0]]
|
55
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'raises an exception for non-integer pixel value (Float)' do
|
59
|
+
data = [[0, 0], [0.5, 0]]
|
60
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'raises an exception for rows of different size' do
|
64
|
+
data = [[0, 0], [0, 0, 0]]
|
65
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'raises an exception for invalid array dimensions (#1)' do
|
69
|
+
data = [0, 0, 0]
|
70
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'raises an exception for invalid array dimensions (#2)' do
|
74
|
+
data = [[0, 0], 0, 0]
|
75
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'raises an exception for invalid array dimensions (#3)' do
|
79
|
+
data = [[0, 0], [0, [0, 0]]]
|
80
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'raises an exception for invalid array dimensions (#4)' do
|
84
|
+
data = [[[0,0], [0,0]], [[0,0], [0,0]]]
|
85
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'raises an exception for invalid array dimensions (#5)' do
|
89
|
+
data = [[[0,0,0], [0,0,0]], [0 ,0]]
|
90
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'raises an exception for invalid array dimensions (#6)' do
|
94
|
+
data = [[[0,0,0], 0], [0 ,0]]
|
95
|
+
lambda { PNM::Image.new(data) }.must_raise PNM::DataError
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'raises an exception for invalid PBM data (> 1)' do
|
99
|
+
data = [[0, 0], [2, 0]]
|
100
|
+
lambda { PNM::Image.new(data, :type => :pbm) }.must_raise PNM::DataError
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'raises an exception for invalid PBM data (< 0)' do
|
104
|
+
data = [[0, 0], [-1, 0]]
|
105
|
+
lambda { PNM::Image.new(data, :type => :pbm) }.must_raise PNM::DataError
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'raises an exception for invalid PGM data (> 255)' do
|
109
|
+
data = [[0, 0], [1, 500]]
|
110
|
+
lambda { PNM::Image.new(data, :type => :pgm) }.must_raise PNM::DataError
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'raises an exception for invalid PGM data (> maxgray)' do
|
114
|
+
data = [[0, 0], [1, 200]]
|
115
|
+
lambda { PNM::Image.new(data, :maxgray => 100) }.must_raise PNM::DataError
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
describe 'PNM.read' do
|
121
|
+
|
122
|
+
it 'raises an exception for integer argument' do
|
123
|
+
lambda { PNM.read(123) }.must_raise PNM::ArgumentError
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'raises an exception for unknown magic number' do
|
127
|
+
file = StringIO.new('P0 1 1 0')
|
128
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'raises an exception for an empty file' do
|
132
|
+
file = StringIO.new('')
|
133
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
134
|
+
end
|
135
|
+
|
136
|
+
it 'raises an exception for missing tokens (#1)' do
|
137
|
+
file = StringIO.new('P1')
|
138
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'raises an exception for missing tokens (#2)' do
|
142
|
+
file = StringIO.new('P1 1')
|
143
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'raises an exception for missing tokens (#3)' do
|
147
|
+
file = StringIO.new('P1 1 ')
|
148
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'raises an exception for missing tokens (#4)' do
|
152
|
+
file = StringIO.new('P1 1 1')
|
153
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'raises an exception for missing tokens (#5)' do
|
157
|
+
file = StringIO.new("P1 1 # Test\n 1")
|
158
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'raises an exception for missing tokens (#6)' do
|
162
|
+
file = StringIO.new("P2 1 1 255")
|
163
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'raises an exception for token of wrong type (#1)' do
|
167
|
+
file = StringIO.new('P1 ? 1 0')
|
168
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'raises an exception for token of wrong type (#2)' do
|
172
|
+
file = StringIO.new('P1 1 X 0')
|
173
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'raises an exception for token of wrong type (#3)' do
|
177
|
+
file = StringIO.new('P2 1 1 foo 0')
|
178
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'raises an exception for zero width' do
|
182
|
+
file = StringIO.new('P2 0 1 255 0')
|
183
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'raises an exception for zero height' do
|
187
|
+
file = StringIO.new('P2 1 0 255 0')
|
188
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'raises an exception for invalid maxgray (> 255)' do
|
192
|
+
file = StringIO.new('P2 1 1 256 0')
|
193
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'raises an exception for invalid maxgray (0)' do
|
197
|
+
file = StringIO.new('P2 1 1 0 0')
|
198
|
+
lambda { PNM.read(file) }.must_raise PNM::ParserError
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'raises an exception for image dimension mismatch (#1)' do
|
202
|
+
file = StringIO.new('P1 2 3 0 0 0 0 0')
|
203
|
+
lambda { PNM.read(file) }.must_raise PNM::DataSizeError
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'raises an exception for image dimension mismatch (#2)' do
|
207
|
+
file = StringIO.new('P1 2 3 0 0 0 0 0 0 0')
|
208
|
+
lambda { PNM.read(file) }.must_raise PNM::DataSizeError
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'raises an exception for image dimension mismatch (#3)' do
|
212
|
+
file = StringIO.new('P3 2 3 255 0 0 0 0 0 0')
|
213
|
+
lambda { PNM.read(file) }.must_raise PNM::DataSizeError
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'raises an exception for image dimension mismatch (#4)' do
|
217
|
+
file = StringIO.new('P5 2 3 255 AAAAAAA')
|
218
|
+
lambda { PNM.read(file) }.must_raise PNM::DataSizeError
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'raises an exception for image dimension mismatch (#5)' do
|
222
|
+
file = StringIO.new('P5 2 3 255 AAAAAAA')
|
223
|
+
lambda { PNM.read(file) }.must_raise PNM::DataSizeError
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'raises an exception for non-numeric image data' do
|
227
|
+
file = StringIO.new('P1 2 3 0 X 0 0 0 0')
|
228
|
+
lambda { PNM.read(file) }.must_raise PNM::DataError
|
229
|
+
end
|
230
|
+
end
|
data/test/test_image.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# test_image.rb: Unit tests for the PNM library.
|
2
2
|
#
|
3
|
-
# Copyright (C) 2013 Marcus Stollsteimer
|
3
|
+
# Copyright (C) 2013-2014 Marcus Stollsteimer
|
4
4
|
|
5
5
|
require 'minitest/spec'
|
6
6
|
require 'minitest/autorun'
|
@@ -168,4 +168,18 @@ describe PNM::Image do
|
|
168
168
|
File.binread(@temp_path).must_equal File.binread("#{@srcpath}/grayscale_binary_crlf.pgm")
|
169
169
|
File.delete(@temp_path)
|
170
170
|
end
|
171
|
+
|
172
|
+
it 'can write zero-length comments' do
|
173
|
+
comment = ''
|
174
|
+
PNM::Image.new([[0,0]], :comment => comment).write(@temp_path, :ascii)
|
175
|
+
File.binread(@temp_path).must_equal "P1\n#\n2 1\n0 0\n"
|
176
|
+
File.delete(@temp_path)
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'can write comments with trailing zero-length line' do
|
180
|
+
comment = "An empty line:\n"
|
181
|
+
PNM::Image.new([[0,0]], :comment => comment).write(@temp_path, :ascii)
|
182
|
+
File.binread(@temp_path).must_equal "P1\n# An empty line:\n#\n2 1\n0 0\n"
|
183
|
+
File.delete(@temp_path)
|
184
|
+
end
|
171
185
|
end
|
data/test/test_parser.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# test_parser.rb: Unit tests for the PNM library.
|
2
2
|
#
|
3
|
-
# Copyright (C) 2013 Marcus Stollsteimer
|
3
|
+
# Copyright (C) 2013-2014 Marcus Stollsteimer
|
4
4
|
|
5
5
|
require 'minitest/spec'
|
6
6
|
require 'minitest/autorun'
|
@@ -21,8 +21,8 @@ describe PNM::Parser do
|
|
21
21
|
EOF
|
22
22
|
expected = {
|
23
23
|
:magic_number => 'P1',
|
24
|
-
:width =>
|
25
|
-
:height =>
|
24
|
+
:width => 6,
|
25
|
+
:height => 2,
|
26
26
|
:data => "0 1 0 0 1 1\n0 0 0 1 1 1"
|
27
27
|
}
|
28
28
|
|
@@ -37,9 +37,9 @@ describe PNM::Parser do
|
|
37
37
|
EOF
|
38
38
|
expected = {
|
39
39
|
:magic_number => 'P2',
|
40
|
-
:width =>
|
41
|
-
:height =>
|
42
|
-
:maxgray =>
|
40
|
+
:width => 4,
|
41
|
+
:height => 2,
|
42
|
+
:maxgray => 100,
|
43
43
|
:data => "10 20 30 40\n50 60 70 80"
|
44
44
|
}
|
45
45
|
|
@@ -50,8 +50,8 @@ describe PNM::Parser do
|
|
50
50
|
content = 'P4 8 2 ' << ['05AF'].pack('H*')
|
51
51
|
expected = {
|
52
52
|
:magic_number => 'P4',
|
53
|
-
:width =>
|
54
|
-
:height =>
|
53
|
+
:width => 8,
|
54
|
+
:height => 2,
|
55
55
|
:data => ['05AF'].pack('H*')
|
56
56
|
}
|
57
57
|
|
@@ -70,8 +70,8 @@ describe PNM::Parser do
|
|
70
70
|
content = "P1 \n\t 3 \r \n2 0 1 0 0 1 1"
|
71
71
|
expected = {
|
72
72
|
:magic_number => 'P1',
|
73
|
-
:width =>
|
74
|
-
:height =>
|
73
|
+
:width => 3,
|
74
|
+
:height => 2,
|
75
75
|
:data => '0 1 0 0 1 1'
|
76
76
|
}
|
77
77
|
|
@@ -108,8 +108,8 @@ describe PNM::Parser do
|
|
108
108
|
EOF
|
109
109
|
expected = {
|
110
110
|
:magic_number => 'P1',
|
111
|
-
:width =>
|
112
|
-
:height =>
|
111
|
+
:width => 6,
|
112
|
+
:height => 2,
|
113
113
|
:comments => ['Comment 1', 'Comment 2', 'Comment 3', 'Comment 4', '', 'Comment 6'],
|
114
114
|
:data => "0 1 0 0 1 1\n0 0 0 1 1 1"
|
115
115
|
}
|
data/test/test_pnm.rb
CHANGED
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pnm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcus Stollsteimer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2014-02-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
description: 'PNM is a pure Ruby library for creating, reading, and writing of PNM
|
@@ -34,55 +34,58 @@ extra_rdoc_files: []
|
|
34
34
|
files:
|
35
35
|
- README.md
|
36
36
|
- Rakefile
|
37
|
-
- pnm.gemspec
|
38
|
-
- benchmark/random_image.ppm
|
39
37
|
- benchmark/bm_converter.rb
|
40
|
-
- benchmark/random_image.pgm
|
41
38
|
- benchmark/random_image.pbm
|
39
|
+
- benchmark/random_image.pgm
|
40
|
+
- benchmark/random_image.ppm
|
42
41
|
- lib/pnm.rb
|
42
|
+
- lib/pnm/converter.rb
|
43
|
+
- lib/pnm/exceptions.rb
|
43
44
|
- lib/pnm/image.rb
|
44
45
|
- lib/pnm/parser.rb
|
45
46
|
- lib/pnm/version.rb
|
46
|
-
-
|
47
|
+
- pnm.gemspec
|
48
|
+
- test/bilevel_2_binary.pbm
|
47
49
|
- test/bilevel_ascii.pbm
|
50
|
+
- test/bilevel_binary.pbm
|
51
|
+
- test/color_ascii.ppm
|
52
|
+
- test/color_binary.ppm
|
53
|
+
- test/grayscale_ascii.pgm
|
48
54
|
- test/grayscale_binary.pgm
|
49
|
-
- test/test_image.rb
|
50
55
|
- test/grayscale_binary_crlf.pgm
|
51
|
-
- test/color_binary.ppm
|
52
|
-
- test/bilevel_binary.pbm
|
53
|
-
- test/test_parser.rb
|
54
56
|
- test/test_converter.rb
|
55
|
-
- test/
|
56
|
-
- test/
|
57
|
+
- test/test_exceptions.rb
|
58
|
+
- test/test_image.rb
|
59
|
+
- test/test_parser.rb
|
57
60
|
- test/test_pnm.rb
|
58
|
-
- test/grayscale_ascii.pgm
|
59
61
|
homepage: https://github.com/stomar/pnm
|
60
62
|
licenses:
|
61
63
|
- GPL-3
|
62
64
|
metadata: {}
|
63
65
|
post_install_message:
|
64
66
|
rdoc_options:
|
65
|
-
- --charset=UTF-8
|
67
|
+
- "--charset=UTF-8"
|
66
68
|
require_paths:
|
67
69
|
- lib
|
68
70
|
required_ruby_version: !ruby/object:Gem::Requirement
|
69
71
|
requirements:
|
70
|
-
- -
|
72
|
+
- - ">="
|
71
73
|
- !ruby/object:Gem::Version
|
72
74
|
version: 1.9.3
|
73
75
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
76
|
requirements:
|
75
|
-
- -
|
77
|
+
- - ">="
|
76
78
|
- !ruby/object:Gem::Version
|
77
79
|
version: '0'
|
78
80
|
requirements: []
|
79
81
|
rubyforge_project:
|
80
|
-
rubygems_version: 2.
|
82
|
+
rubygems_version: 2.2.0
|
81
83
|
signing_key:
|
82
84
|
specification_version: 4
|
83
85
|
summary: PNM - create/read/write PNM image files (PBM, PGM, PPM)
|
84
86
|
test_files:
|
85
87
|
- test/test_image.rb
|
88
|
+
- test/test_exceptions.rb
|
86
89
|
- test/test_parser.rb
|
87
90
|
- test/test_converter.rb
|
88
91
|
- test/test_pnm.rb
|