pnm 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 309f7c8934e624de40581059644cbda2d9ae575e
4
- data.tar.gz: 36cb4969d02048d04064962091b2df86f8a24491
3
+ metadata.gz: ef19db0d86c0c55bca6a6b6c3f9a5d4eaaac62f6
4
+ data.tar.gz: ffa665ee3688f90f201045230818b97dd5c11b22
5
5
  SHA512:
6
- metadata.gz: 1d30ee950e419b1d83165f3e000ccb0769b6f9a50a223f94f6d50af048c8c8fcce9f3cb7799c0c7b74bcafddd1accbeae2fd78e6acef3b844ae1ec03b8208935
7
- data.tar.gz: 561aaf230c4b41044bcaeb3ee62204963b032e9cbad3ea96c39e17510cd2608ef43e3334e4e6d9aba7b425f2eb1e65f80a73eb97e4030d2771428e50c672d812
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.9,
86
- - Rubinius 2.2.1.
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 &copy; 2013 Marcus Stollsteimer
102
+ Copyright &copy; 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
@@ -1,6 +1,6 @@
1
1
  # rakefile for the PNM library.
2
2
  #
3
- # Copyright (C) 2013 Marcus Stollsteimer
3
+ # Copyright (C) 2013-2014 Marcus Stollsteimer
4
4
 
5
5
  require 'rake/testtask'
6
6
 
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # bm_converter.rb: Benchmarks for the PNM library.
3
3
  #
4
- # Copyright (C) 2013 Marcus Stollsteimer
4
+ # Copyright (C) 2013-2014 Marcus Stollsteimer
5
5
 
6
6
  require 'benchmark'
7
7
  require_relative '../lib/pnm'
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) 2012-2013 Marcus Stollsteimer.
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
- else
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].to_i
139
- height = content[:height].to_i
140
- maxgray = content[:maxgray].to_i
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
@@ -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
- values = data.gsub(/\A[ \t\r\n]+/, '').split(/[ \t\r\n]+/).map {|value| value.to_i }
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
- if data.size != bytes_per_row * height
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
@@ -0,0 +1,10 @@
1
+ module PNM
2
+
3
+ # Base class for all PNM exceptions.
4
+ class Error < StandardError; end
5
+
6
+ class ArgumentError < Error; end
7
+ class ParserError < Error; end
8
+ class DataSizeError < Error; end
9
+ class DataError < Error; end
10
+ end
@@ -1,6 +1,11 @@
1
1
  module PNM
2
2
 
3
- # Class for +PBM+, +PGM+, and +PPM+ images. See PNM module for examples.
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 default, the type is guessed from the provided
44
- # pixel data, unless this option is used.
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 (default: empty 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 = (options[:comment] || '').chomp
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 <= 1
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
- if comment
126
- comment.split("\n").each {|line| header << "# #{line}\n" }
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
 
@@ -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 as strings:
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
- raise "Unknown magic number" unless token_number[magic_number]
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
@@ -1,4 +1,4 @@
1
1
  module PNM
2
- VERSION = '0.2.1' # :nodoc:
3
- DATE = '2013-12-17' # :nodoc:
2
+ VERSION = '0.3.0' # :nodoc:
3
+ DATE = '2014-02-08' # :nodoc:
4
4
  end
@@ -1,6 +1,6 @@
1
1
  # test_converter.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'
@@ -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
@@ -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
@@ -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 => '6',
25
- :height => '2',
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 => '4',
41
- :height => '2',
42
- :maxgray => '100',
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 => '8',
54
- :height => '2',
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 => '3',
74
- :height => '2',
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 => '6',
112
- :height => '2',
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
  }
@@ -1,6 +1,6 @@
1
1
  # test_pnm.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'
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.2.1
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: 2013-12-17 00:00:00.000000000 Z
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
- - lib/pnm/converter.rb
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/bilevel_2_binary.pbm
56
- - test/color_ascii.ppm
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.1.11
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