pnm 0.5.1 → 0.5.2
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 +5 -5
- data/README.md +4 -7
- data/Rakefile +11 -10
- data/benchmark/bm_converter.rb +21 -17
- data/lib/pnm.rb +35 -39
- data/lib/pnm/converter.rb +45 -48
- data/lib/pnm/exceptions.rb +2 -0
- data/lib/pnm/image.rb +53 -44
- data/lib/pnm/parser.rb +32 -30
- data/lib/pnm/version.rb +4 -2
- data/pnm.gemspec +23 -20
- data/test/test_converter.rb +57 -54
- data/test/test_exceptions.rb +122 -120
- data/test/test_image.rb +110 -108
- data/test/test_parser.rb +45 -43
- data/test/test_pnm.rb +42 -40
- metadata +11 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 66de49354358fed31c8299381599bb8b16d87d2143e2102ca61da00e6b8b2927
|
4
|
+
data.tar.gz: 2bd7e0d7491be12b5562c3a1de19ee7e538d95c3535fc9bb92723726b5e5787c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd83d15feb8b65b28b43f64cd48ab23a5e3f710a991f781c43d6d74bc9ea9a02cb905d61bae70af1fe2476c551ece310050eccd0210acb5701d87efb40d61173
|
7
|
+
data.tar.gz: 574e62b56e1ac1fea7a9110f1c01c805f373bfafd50210bb2145fca4086054d7d1ace113d1e46eadfe0b5c9314b3ca221168cdc2dba2e7168742615a7462e728
|
data/README.md
CHANGED
@@ -27,7 +27,7 @@ pixels = [[ 0, 10, 20],
|
|
27
27
|
[10, 20, 30]]
|
28
28
|
|
29
29
|
# optional settings
|
30
|
-
options = {:
|
30
|
+
options = { maxgray: 30, comment: "Test Image" }
|
31
31
|
|
32
32
|
# create the image object
|
33
33
|
image = PNM.create(pixels, options)
|
@@ -71,7 +71,7 @@ image.pixels # => [[0, 10, 20], [10, 20, 30]]
|
|
71
71
|
Force an image type:
|
72
72
|
|
73
73
|
``` ruby
|
74
|
-
color_image = PNM.create([[0, 1],[1, 0]], :
|
74
|
+
color_image = PNM.create([[0, 1],[1, 0]], type: :ppm)
|
75
75
|
color_image.info # => "PPM 2x2 Color"
|
76
76
|
```
|
77
77
|
|
@@ -98,10 +98,7 @@ Requirements
|
|
98
98
|
|
99
99
|
- PNM has been tested with
|
100
100
|
|
101
|
-
- Ruby 2.4,
|
102
|
-
- Ruby 2.3,
|
103
|
-
- Ruby 2.2,
|
104
|
-
- Ruby 2.1,
|
101
|
+
- Ruby 2.6, 2.5, 2.4, 2.3, 2.2, 2.1,
|
105
102
|
- Ruby 2.0.0,
|
106
103
|
- Ruby 1.9.3,
|
107
104
|
- JRuby 1.7.19,
|
@@ -121,7 +118,7 @@ Report bugs on the PNM home page: <https://github.com/stomar/pnm/>
|
|
121
118
|
License
|
122
119
|
-------
|
123
120
|
|
124
|
-
Copyright © 2013-
|
121
|
+
Copyright © 2013-2019 Marcus Stollsteimer
|
125
122
|
|
126
123
|
`PNM` is free software: you can redistribute it and/or modify
|
127
124
|
it under the terms of the GNU General Public License version 3 or later (GPLv3+),
|
data/Rakefile
CHANGED
@@ -1,34 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rakefile for the PNM library.
|
2
4
|
#
|
3
|
-
# Copyright (C) 2013-
|
5
|
+
# Copyright (C) 2013-2019 Marcus Stollsteimer
|
4
6
|
|
5
|
-
require
|
7
|
+
require "rake/testtask"
|
6
8
|
|
7
|
-
require_relative
|
9
|
+
require_relative "lib/pnm"
|
8
10
|
|
9
11
|
|
10
12
|
def gemspec_file
|
11
|
-
|
13
|
+
"pnm.gemspec"
|
12
14
|
end
|
13
15
|
|
14
16
|
|
15
|
-
task :
|
17
|
+
task default: :test
|
16
18
|
|
17
19
|
Rake::TestTask.new do |t|
|
18
|
-
t.pattern =
|
19
|
-
t.ruby_opts << '-rubygems'
|
20
|
+
t.pattern = "test/**/test_*.rb"
|
20
21
|
t.verbose = true
|
21
22
|
t.warning = true
|
22
23
|
end
|
23
24
|
|
24
25
|
|
25
|
-
desc
|
26
|
+
desc "Run benchmarks"
|
26
27
|
task :benchmark do
|
27
|
-
Dir[
|
28
|
+
Dir["benchmark/**/bm_*.rb"].each {|f| require_relative f }
|
28
29
|
end
|
29
30
|
|
30
31
|
|
31
|
-
desc
|
32
|
+
desc "Build gem"
|
32
33
|
task :build do
|
33
34
|
sh "gem build #{gemspec_file}"
|
34
35
|
end
|
data/benchmark/bm_converter.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
2
4
|
# bm_converter.rb: Benchmarks for the PNM library.
|
3
5
|
#
|
4
|
-
# Copyright (C) 2013-
|
6
|
+
# Copyright (C) 2013-2019 Marcus Stollsteimer
|
5
7
|
|
6
|
-
require
|
7
|
-
require_relative
|
8
|
+
require "benchmark"
|
9
|
+
require_relative "../lib/pnm"
|
8
10
|
|
11
|
+
# Benchmarks for PNM::Converter.
|
9
12
|
class ConverterBenchmark
|
10
13
|
|
11
14
|
def initialize
|
@@ -14,7 +17,7 @@ class ConverterBenchmark
|
|
14
17
|
|
15
18
|
@srcpath = File.dirname(__FILE__)
|
16
19
|
|
17
|
-
print
|
20
|
+
print "Initializing test data..."
|
18
21
|
@pbm_image = PNM.read(File.expand_path("#{@srcpath}/random_image.pbm"))
|
19
22
|
@pgm_image = PNM.read(File.expand_path("#{@srcpath}/random_image.pgm"))
|
20
23
|
@ppm_image = PNM.read(File.expand_path("#{@srcpath}/random_image.ppm"))
|
@@ -32,7 +35,7 @@ class ConverterBenchmark
|
|
32
35
|
run_benchmark(@pgm_image)
|
33
36
|
run_benchmark(@ppm_image)
|
34
37
|
|
35
|
-
puts "\nTotal: " <<
|
38
|
+
puts "\nTotal: ".dup <<
|
36
39
|
@user.round(2).to_s.ljust(11) <<
|
37
40
|
@system.round(2).to_s.ljust(11) <<
|
38
41
|
@total.round(2).to_s
|
@@ -40,43 +43,44 @@ class ConverterBenchmark
|
|
40
43
|
|
41
44
|
def run_benchmark(image)
|
42
45
|
type = image.type
|
43
|
-
type_string = type.upcase
|
44
46
|
width = image.width
|
45
47
|
height = image.height
|
46
48
|
array = image.pixels
|
47
49
|
ascii = PNM::Converter.array2ascii(array)
|
48
50
|
binary = PNM::Converter.array2binary(type, array)
|
51
|
+
type_string = type.upcase
|
49
52
|
|
50
53
|
puts
|
51
54
|
|
52
55
|
Benchmark.bm(18) do |bm|
|
53
|
-
|
56
|
+
|
57
|
+
bm.report("#{type_string} / ascii2array") do
|
54
58
|
@repetitions.times do
|
55
59
|
PNM::Converter.ascii2array(type, width, height, ascii)
|
56
60
|
end
|
57
|
-
|
61
|
+
end
|
58
62
|
|
59
|
-
bm.report("#{type_string} / array2ascii")
|
63
|
+
bm.report("#{type_string} / array2ascii") do
|
60
64
|
@repetitions.times do
|
61
65
|
PNM::Converter.array2ascii(array)
|
62
66
|
end
|
63
|
-
|
67
|
+
end
|
64
68
|
|
65
|
-
bm.report("#{type_string} / binary2array")
|
69
|
+
bm.report("#{type_string} / binary2array") do
|
66
70
|
@repetitions.times do
|
67
71
|
PNM::Converter.binary2array(type, width, height, binary)
|
68
72
|
end
|
69
|
-
|
73
|
+
end
|
70
74
|
|
71
|
-
bm.report("#{type_string} / array2binary")
|
75
|
+
bm.report("#{type_string} / array2binary") do
|
72
76
|
@repetitions.times do
|
73
77
|
PNM::Converter.array2binary(type, array)
|
74
78
|
end
|
75
|
-
|
79
|
+
end
|
76
80
|
|
77
|
-
@user += bm.list.map
|
78
|
-
@system += bm.list.map
|
79
|
-
@total += bm.list.map
|
81
|
+
@user += bm.list.map(&:utime).reduce(:+)
|
82
|
+
@system += bm.list.map(&:stime).reduce(:+)
|
83
|
+
@total += bm.list.map(&:total).reduce(:+)
|
80
84
|
end
|
81
85
|
end
|
82
86
|
end
|
data/lib/pnm.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# = pnm.rb - create/read/write PNM image files (PBM, PGM, PPM)
|
2
4
|
#
|
3
5
|
# See PNM module for documentation.
|
4
6
|
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
8
|
-
require_relative
|
9
|
-
require_relative
|
7
|
+
require_relative "pnm/version"
|
8
|
+
require_relative "pnm/image"
|
9
|
+
require_relative "pnm/parser"
|
10
|
+
require_relative "pnm/converter"
|
11
|
+
require_relative "pnm/exceptions"
|
10
12
|
|
11
13
|
|
12
14
|
# PNM is a pure Ruby library for creating, reading,
|
@@ -33,7 +35,7 @@ require_relative 'pnm/exceptions'
|
|
33
35
|
# [10, 20, 30]]
|
34
36
|
#
|
35
37
|
# # optional settings
|
36
|
-
# options = {:
|
38
|
+
# options = { maxgray: 30, comment: "Test Image" }
|
37
39
|
#
|
38
40
|
# # create the image object
|
39
41
|
# image = PNM.create(pixels, options)
|
@@ -71,7 +73,7 @@ require_relative 'pnm/exceptions'
|
|
71
73
|
#
|
72
74
|
# Force an image type:
|
73
75
|
#
|
74
|
-
# color_image = PNM.create([[0, 1],[1, 0]], :
|
76
|
+
# color_image = PNM.create([[0, 1],[1, 0]], type: :ppm)
|
75
77
|
# color_image.info # => "PPM 2x2 Color"
|
76
78
|
#
|
77
79
|
# Check equality of two images:
|
@@ -85,28 +87,28 @@ require_relative 'pnm/exceptions'
|
|
85
87
|
#
|
86
88
|
# == Author
|
87
89
|
#
|
88
|
-
# Copyright (C) 2013-
|
90
|
+
# Copyright (C) 2013-2019 Marcus Stollsteimer
|
89
91
|
#
|
90
92
|
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
91
93
|
#
|
92
94
|
module PNM
|
93
95
|
|
94
|
-
LIBNAME =
|
95
|
-
HOMEPAGE =
|
96
|
-
TAGLINE =
|
96
|
+
LIBNAME = "pnm"
|
97
|
+
HOMEPAGE = "https://github.com/stomar/pnm"
|
98
|
+
TAGLINE = "create/read/write PNM image files (PBM, PGM, PPM)"
|
97
99
|
|
98
|
-
COPYRIGHT = <<-
|
99
|
-
Copyright (C) 2013-
|
100
|
+
COPYRIGHT = <<-TEXT.gsub(/^ +/, "")
|
101
|
+
Copyright (C) 2013-2019 Marcus Stollsteimer.
|
100
102
|
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
|
101
103
|
This is free software: you are free to change and redistribute it.
|
102
104
|
There is NO WARRANTY, to the extent permitted by law.
|
103
|
-
|
105
|
+
TEXT
|
104
106
|
|
105
107
|
# Reads an image from +file+ (a filename or an IO object).
|
106
108
|
#
|
107
109
|
# Returns a PNM::Image object.
|
108
110
|
def self.read(file)
|
109
|
-
if file.
|
111
|
+
if file.is_a?(String)
|
110
112
|
raw_data = File.binread(file)
|
111
113
|
elsif file.respond_to?(:binmode)
|
112
114
|
file.binmode
|
@@ -117,26 +119,20 @@ module PNM
|
|
117
119
|
|
118
120
|
content = Parser.parse(raw_data)
|
119
121
|
|
120
|
-
case content[:magic_number]
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
type = :pgm
|
135
|
-
encoding = :binary
|
136
|
-
when 'P6'
|
137
|
-
type = :ppm
|
138
|
-
encoding = :binary
|
139
|
-
end
|
122
|
+
type, encoding = case content[:magic_number]
|
123
|
+
when "P1"
|
124
|
+
[:pbm, :ascii]
|
125
|
+
when "P2"
|
126
|
+
[:pgm, :ascii]
|
127
|
+
when "P3"
|
128
|
+
[:ppm, :ascii]
|
129
|
+
when "P4"
|
130
|
+
[:pbm, :binary]
|
131
|
+
when "P5"
|
132
|
+
[:pgm, :binary]
|
133
|
+
when "P6"
|
134
|
+
[:ppm, :binary]
|
135
|
+
end
|
140
136
|
|
141
137
|
width = content[:width]
|
142
138
|
height = content[:height]
|
@@ -147,7 +143,7 @@ module PNM
|
|
147
143
|
Converter.binary2array(type, width, height, content[:data])
|
148
144
|
end
|
149
145
|
|
150
|
-
options = {:
|
146
|
+
options = { type: type, maxgray: maxgray }
|
151
147
|
options[:comment] = content[:comments].join("\n") if content[:comments]
|
152
148
|
|
153
149
|
create(pixels, options)
|
@@ -191,9 +187,9 @@ module PNM
|
|
191
187
|
# @private
|
192
188
|
def self.magic_number # :nodoc:
|
193
189
|
{
|
194
|
-
:
|
195
|
-
:
|
196
|
-
:
|
190
|
+
pbm: { ascii: "P1", binary: "P4" },
|
191
|
+
pgm: { ascii: "P2", binary: "P5" },
|
192
|
+
ppm: { ascii: "P3", binary: "P6" }
|
197
193
|
}
|
198
194
|
end
|
199
195
|
end
|
data/lib/pnm/converter.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module PNM
|
2
4
|
|
3
5
|
# @private
|
@@ -30,12 +32,12 @@ module PNM
|
|
30
32
|
values = convert_to_integers(data, type)
|
31
33
|
assert_data_size(values.size, values_per_row * height)
|
32
34
|
|
33
|
-
case type
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
pixel_matrix = case type
|
36
|
+
when :pbm, :pgm
|
37
|
+
values.each_slice(width).to_a
|
38
|
+
when :ppm
|
39
|
+
values.each_slice(3 * width).map {|row| row.each_slice(3).to_a }
|
40
|
+
end
|
39
41
|
|
40
42
|
pixel_matrix
|
41
43
|
end
|
@@ -49,22 +51,21 @@ module PNM
|
|
49
51
|
# Returns a two-dimensional array of bilevel, gray, or RGB values.
|
50
52
|
def self.binary2array(type, width, height, data)
|
51
53
|
bytes_per_row = byte_width(type, width)
|
54
|
+
expected_size = bytes_per_row * height
|
52
55
|
|
53
|
-
if data.size ==
|
54
|
-
data.slice!(-1)
|
55
|
-
end
|
56
|
+
data.slice!(-1) if data.size == expected_size + 1 && data[-1] =~ /[ \t\r\n]/
|
56
57
|
|
57
|
-
assert_data_size(data.size,
|
58
|
+
assert_data_size(data.size, expected_size)
|
58
59
|
|
59
|
-
case type
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
60
|
+
pixel_matrix = case type
|
61
|
+
when :pbm
|
62
|
+
rows = data.scan(/.{#{bytes_per_row}}/m)
|
63
|
+
rows.map {|row| row.unpack("B*").first[0, width].each_char.map(&:to_i) }
|
64
|
+
when :pgm
|
65
|
+
data.each_byte.each_slice(bytes_per_row).to_a
|
66
|
+
when :ppm
|
67
|
+
data.each_byte.each_slice(bytes_per_row).map {|row| row.each_slice(3).to_a }
|
68
|
+
end
|
68
69
|
|
69
70
|
pixel_matrix
|
70
71
|
end
|
@@ -75,12 +76,12 @@ module PNM
|
|
75
76
|
#
|
76
77
|
# Returns a string containing the pixel data in ASCII format.
|
77
78
|
def self.array2ascii(data)
|
78
|
-
case data.first.first
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
79
|
+
data_string = case data.first.first
|
80
|
+
when Array
|
81
|
+
data.map {|row| row.flatten.join(" ") }.join("\n")
|
82
|
+
else
|
83
|
+
data.map {|row| row.join(" ") }.join("\n")
|
84
|
+
end
|
84
85
|
|
85
86
|
data_string << "\n"
|
86
87
|
end
|
@@ -94,38 +95,34 @@ module PNM
|
|
94
95
|
def self.array2binary(type, data)
|
95
96
|
height = data.size
|
96
97
|
|
97
|
-
if type == :pbm
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
98
|
+
data_string = if type == :pbm
|
99
|
+
binary_rows = data.map(&:join)
|
100
|
+
binary_rows.pack("B*" * height)
|
101
|
+
else
|
102
|
+
data.flatten.pack("C*")
|
103
|
+
end
|
103
104
|
|
104
105
|
data_string
|
105
106
|
end
|
106
107
|
|
107
108
|
def self.convert_to_integers(data, type)
|
108
|
-
if type == :pbm
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
109
|
+
values_as_string = if type == :pbm
|
110
|
+
data.gsub(/[ \t\r\n]+/, "").split("")
|
111
|
+
else
|
112
|
+
data.gsub(/\A[ \t\r\n]+/, "").split(/[ \t\r\n]+/)
|
113
|
+
end
|
113
114
|
|
114
|
-
values_as_string.map
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
raise PNM::DataError, "invalid pixel value: Integer expected"
|
120
|
-
else
|
121
|
-
raise
|
122
|
-
end
|
115
|
+
values_as_string.map {|value| Integer(value) }
|
116
|
+
rescue ::ArgumentError => error
|
117
|
+
raise unless error.message.start_with?("invalid value for Integer")
|
118
|
+
|
119
|
+
raise PNM::DataError, "invalid pixel value: Integer expected"
|
123
120
|
end
|
124
121
|
|
125
122
|
def self.assert_data_size(actual, expected)
|
126
|
-
|
127
|
-
|
128
|
-
|
123
|
+
return if actual == expected
|
124
|
+
|
125
|
+
raise PNM::DataSizeError, "data size does not match expected size"
|
129
126
|
end
|
130
127
|
end
|
131
128
|
end
|