pnm 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e0626fcd5c88b2477eb1f76891857c83fb10d881
4
+ data.tar.gz: 29724fe5ca19969bb9bf66358272222189b17f33
5
+ SHA512:
6
+ metadata.gz: 9e1f19e832e56b253d9db10794d4b414fc0211222c8e24ac572ffa93399e505bab04648b51ad1598916959480e2769fbac6f74253557f8a2a2ec81fca06aab8f
7
+ data.tar.gz: de73725df2c7703abd73e105ea770c4efe89d5db7caa01da45a747335a3d819003a946a8aaa31aa08869e0a8a6662e578cd23227d31daab00eabc686ac86e0ef
@@ -0,0 +1,93 @@
1
+ PNM - A Ruby library for PNM image files (PBM, PGM, PPM)
2
+ ========================================================
3
+
4
+ PNM is a pure [Ruby][Ruby] library for creating, reading,
5
+ and writing of `PNM` image files (Portable Anymap):
6
+
7
+ - `PBM` (Portable Bitmap),
8
+ - `PGM` (Portable Graymap), and
9
+ - `PPM` (Portable Pixmap).
10
+
11
+ Examples
12
+ --------
13
+
14
+ Create a PGM grayscale image from a two-dimensional array of gray values:
15
+
16
+ require 'pnm'
17
+
18
+ # pixel data
19
+ pixels = [[ 0, 10, 20],
20
+ [10, 20, 30]]
21
+
22
+ # optional settings
23
+ options = {:maxgray => 30, :comment => 'Test Image'}
24
+
25
+ # create the image object
26
+ image = PNM::Image.new(:pgm, pixels, options)
27
+
28
+ # retrieve some image properties
29
+ image.info # => "PGM 3x2 Grayscale"
30
+ image.width # => 3
31
+ image.height # => 2
32
+
33
+ See PNM::Image.new for a more detailed description of pixel data formats
34
+ and available options.
35
+
36
+ Write an image to a file:
37
+
38
+ image.write('test.pgm')
39
+
40
+ # use ASCII or "plain" format (default is binary)
41
+ image.write('test.pgm', :ascii)
42
+
43
+ # write to an I/O stream
44
+ File.open('test.pgm', 'w') {|f| image.write(f) }
45
+
46
+ Read an image from a file (returns a PNM::Image object):
47
+
48
+ image = PNM.read('test.pgm')
49
+ image.comment # => "Test Image"
50
+ image.maxgray # => 30
51
+ image.pixels # => [[0, 10, 20], [10, 20, 30]]
52
+
53
+
54
+ Installation
55
+ ------------
56
+
57
+ To install PNM, you can either
58
+
59
+ - use `gem install pnm`, or
60
+
61
+ - clone or download the repository and use
62
+ `rake build` and `[sudo] gem install pnm`.
63
+
64
+ Requirements
65
+ ------------
66
+
67
+ - No additional Ruby gems or native libraries are needed.
68
+
69
+ - PNM has been tested with Ruby 1.9.3 and Ruby 2.0.0
70
+ on Linux and on Windows.
71
+
72
+ Documentation
73
+ -------------
74
+
75
+ Documentation should be available via `ri PNM`.
76
+
77
+ Reporting bugs
78
+ --------------
79
+
80
+ Report bugs on the PNM home page: <https://github.com/stomar/pnm/>
81
+
82
+ License
83
+ -------
84
+
85
+ Copyright &copy; 2013 Marcus Stollsteimer
86
+
87
+ `PNM` is free software: you can redistribute it and/or modify
88
+ it under the terms of the GNU General Public License version 3 or later (GPLv3+),
89
+ see [www.gnu.org/licenses/gpl.html](http://www.gnu.org/licenses/gpl.html).
90
+ There is NO WARRANTY, to the extent permitted by law.
91
+
92
+
93
+ [Ruby]: http://www.ruby-lang.org/
@@ -0,0 +1,34 @@
1
+ # rakefile for the PNM library.
2
+ #
3
+ # Copyright (C) 2013 Marcus Stollsteimer
4
+
5
+ require 'rake/testtask'
6
+
7
+ require_relative 'lib/pnm'
8
+
9
+
10
+ def gemspec_file
11
+ 'pnm.gemspec'
12
+ end
13
+
14
+
15
+ task :default => [:test]
16
+
17
+ Rake::TestTask.new do |t|
18
+ t.pattern = 'test/**/test_*.rb'
19
+ t.ruby_opts << '-rubygems'
20
+ t.verbose = true
21
+ t.warning = true
22
+ end
23
+
24
+
25
+ desc 'Run benchmarks'
26
+ task :benchmark do
27
+ Dir['benchmark/**/bm_*.rb'].each {|f| require_relative f }
28
+ end
29
+
30
+
31
+ desc 'Build gem'
32
+ task :build do
33
+ sh "gem build #{gemspec_file}"
34
+ end
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env ruby
2
+ # bm_converter.rb: Benchmarks for the PNM library.
3
+ #
4
+ # Copyright (C) 2013 Marcus Stollsteimer
5
+
6
+ require 'benchmark'
7
+ require_relative '../lib/pnm'
8
+ require_relative '../lib/pnm/converter'
9
+
10
+ class ConverterBenchmark
11
+
12
+ def initialize
13
+ @repetitions = ARGV[0].to_i if ARGV[0] =~ /[0-9]+/
14
+ @repetitions ||= 10
15
+
16
+ @srcpath = File.dirname(__FILE__)
17
+
18
+ print 'Initializing test data...'
19
+ @pbm_image = PNM.read(File.expand_path("#{@srcpath}/random_image.pbm"))
20
+ @pgm_image = PNM.read(File.expand_path("#{@srcpath}/random_image.pgm"))
21
+ @ppm_image = PNM.read(File.expand_path("#{@srcpath}/random_image.ppm"))
22
+ puts " done\n"
23
+
24
+ @user = 0.0
25
+ @system = 0.0
26
+ @total = 0.0
27
+ end
28
+
29
+ def run
30
+ puts "Running benchmarks (#{@repetitions} repetitions)..."
31
+
32
+ run_benchmark(@pbm_image)
33
+ run_benchmark(@pgm_image)
34
+ run_benchmark(@ppm_image)
35
+
36
+ puts "\nTotal: " <<
37
+ @user.round(2).to_s.ljust(11) <<
38
+ @system.round(2).to_s.ljust(11) <<
39
+ @total.round(2).to_s
40
+ end
41
+
42
+ def run_benchmark(image)
43
+ type = image.type
44
+ type_string = type.upcase
45
+ width = image.width
46
+ height = image.height
47
+ array = image.pixels
48
+ ascii = PNM::Converter.array2ascii(array)
49
+ binary = PNM::Converter.array2binary(type, array)
50
+
51
+ puts
52
+
53
+ Benchmark.bm(18) do |bm|
54
+ bm.report("#{type_string} / ascii2array") {
55
+ @repetitions.times do
56
+ PNM::Converter.ascii2array(type, ascii)
57
+ end
58
+ }
59
+
60
+ bm.report("#{type_string} / array2ascii") {
61
+ @repetitions.times do
62
+ PNM::Converter.array2ascii(array)
63
+ end
64
+ }
65
+
66
+ bm.report("#{type_string} / binary2array") {
67
+ @repetitions.times do
68
+ PNM::Converter.binary2array(type, width, height, binary)
69
+ end
70
+ }
71
+
72
+ bm.report("#{type_string} / array2binary") {
73
+ @repetitions.times do
74
+ PNM::Converter.array2binary(type, array)
75
+ end
76
+ }
77
+
78
+ @user += bm.list.map {|tms| tms.utime }.reduce(:+)
79
+ @system += bm.list.map {|tms| tms.stime }.reduce(:+)
80
+ @total += bm.list.map {|tms| tms.total }.reduce(:+)
81
+ end
82
+ end
83
+ end
84
+
85
+ ConverterBenchmark.new.run
@@ -0,0 +1,155 @@
1
+ # = pnm.rb - create/read/write PNM image files (PBM, PGM, PPM)
2
+ #
3
+ # See PNM module for documentation.
4
+
5
+ require_relative 'pnm/version'
6
+ require_relative 'pnm/image'
7
+ require_relative 'pnm/parser'
8
+ require_relative 'pnm/converter'
9
+
10
+
11
+ # PNM is a pure Ruby library for creating, reading,
12
+ # and writing of +PNM+ image files (Portable Anymap):
13
+ #
14
+ # - +PBM+ (Portable Bitmap),
15
+ # - +PGM+ (Portable Graymap), and
16
+ # - +PPM+ (Portable Pixmap).
17
+ #
18
+ # == Examples
19
+ #
20
+ # Create a PGM grayscale image from a two-dimensional array of gray values:
21
+ #
22
+ # require 'pnm'
23
+ #
24
+ # # pixel data
25
+ # pixels = [[ 0, 10, 20],
26
+ # [10, 20, 30]]
27
+ #
28
+ # # optional settings
29
+ # options = {:maxgray => 30, :comment => 'Test Image'}
30
+ #
31
+ # # create the image object
32
+ # image = PNM::Image.new(:pgm, pixels, options)
33
+ #
34
+ # # retrieve some image properties
35
+ # image.info # => "PGM 3x2 Grayscale"
36
+ # image.width # => 3
37
+ # image.height # => 2
38
+ #
39
+ # See PNM::Image.new for a more detailed description of pixel data formats
40
+ # and available options.
41
+ #
42
+ # Write an image to a file:
43
+ #
44
+ # image.write('test.pgm')
45
+ #
46
+ # # use ASCII or "plain" format (default is binary)
47
+ # image.write('test.pgm', :ascii)
48
+ #
49
+ # # write to an I/O stream
50
+ # File.open('test.pgm', 'w') {|f| image.write(f) }
51
+ #
52
+ # Read an image from a file (returns a PNM::Image object):
53
+ #
54
+ # image = PNM.read('test.pgm')
55
+ # image.comment # => "Test Image"
56
+ # image.maxgray # => 30
57
+ # image.pixels # => [[0, 10, 20], [10, 20, 30]]
58
+ #
59
+ # == See also
60
+ #
61
+ # Further information on the PNM library is available on the
62
+ # project home page: <https://github.com/stomar/pnm/>.
63
+ #
64
+ # == Author
65
+ #
66
+ # Copyright (C) 2013 Marcus Stollsteimer
67
+ #
68
+ # License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
69
+ #
70
+ #--
71
+ #
72
+ # == PNM magic numbers
73
+ #
74
+ # Magic Number Type Encoding
75
+ # ------------ ---------------- -------
76
+ # P1 Portable bitmap ASCII
77
+ # P2 Portable graymap ASCII
78
+ # P3 Portable pixmap ASCII
79
+ # P4 Portable bitmap Binary
80
+ # P5 Portable graymap Binary
81
+ # P6 Portable pixmap Binary
82
+ #
83
+ #++
84
+ #
85
+ module PNM
86
+
87
+ LIBNAME = 'pnm' # :nodoc:
88
+ HOMEPAGE = 'https://github.com/stomar/pnm' # :nodoc:
89
+ TAGLINE = 'create/read/write PNM image files (PBM, PGM, PPM)' # :nodoc:
90
+
91
+ COPYRIGHT = <<-copyright.gsub(/^ +/, '') # :nodoc:
92
+ Copyright (C) 2012-2013 Marcus Stollsteimer.
93
+ License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
94
+ This is free software: you are free to change and redistribute it.
95
+ There is NO WARRANTY, to the extent permitted by law.
96
+ copyright
97
+
98
+ # Reads an image from +file+ (a filename or an IO object).
99
+ #
100
+ # Returns a PNM::Image object.
101
+ def self.read(file)
102
+ raw_data = nil
103
+ if file.kind_of?(String)
104
+ raw_data = File.binread(file)
105
+ else
106
+ file.binmode
107
+ raw_data = file.read
108
+ end
109
+
110
+ content = Parser.parse(raw_data)
111
+
112
+ case content[:magic_number]
113
+ when 'P1'
114
+ type = :pbm
115
+ encoding = :ascii
116
+ when 'P2'
117
+ type = :pgm
118
+ encoding = :ascii
119
+ when 'P3'
120
+ type = :ppm
121
+ encoding = :ascii
122
+ when 'P4'
123
+ type = :pbm
124
+ encoding = :binary
125
+ when 'P5'
126
+ type = :pgm
127
+ encoding = :binary
128
+ when 'P6'
129
+ type = :ppm
130
+ encoding = :binary
131
+ end
132
+
133
+ width = content[:width].to_i
134
+ height = content[:height].to_i
135
+ maxgray = content[:maxgray].to_i
136
+ pixels = if encoding == :ascii
137
+ Converter.ascii2array(type, content[:data])
138
+ else
139
+ Converter.binary2array(type, width, height, content[:data])
140
+ end
141
+
142
+ options = {:maxgray => maxgray}
143
+ options[:comment] = content[:comments].join("\n") if content[:comments]
144
+
145
+ Image.new(type, pixels, options)
146
+ end
147
+
148
+ def self.magic_number # :nodoc:
149
+ {
150
+ :pbm => {:ascii => 'P1', :binary => 'P4'},
151
+ :pgm => {:ascii => 'P2', :binary => 'P5'},
152
+ :ppm => {:ascii => 'P3', :binary => 'P6'}
153
+ }
154
+ end
155
+ end
@@ -0,0 +1,101 @@
1
+ module PNM
2
+
3
+ # Converter for pixel data. Only for internal usage.
4
+ class Converter
5
+
6
+ # Returns the number of bytes needed for one row of pixels
7
+ # (in binary encoding).
8
+ def self.byte_width(type, width)
9
+ case type
10
+ when :pbm
11
+ (width - 1) / 8 + 1
12
+ when :pgm
13
+ width
14
+ when :ppm
15
+ 3 * width
16
+ end
17
+ end
18
+
19
+ # Converts from ASCII format to an array of pixel values.
20
+ #
21
+ # +type+:: +:pbm+, +:pgm+, or +:ppm+.
22
+ # +data+:: A string containing the raw pixel data in ASCII format.
23
+ #
24
+ # Returns a two-dimensional array of bilevel, gray, or RGB values.
25
+ def self.ascii2array(type, data)
26
+ pixels = data.split("\n").map do |row|
27
+ row.split(/ +/).map {|value| value.to_i }
28
+ end
29
+
30
+ pixels.map! {|row| row.each_slice(3).to_a } if type == :ppm
31
+
32
+ pixels
33
+ end
34
+
35
+ # Converts from binary format to an array of pixel values.
36
+ #
37
+ # +type+:: +:pbm+, +:pgm+, or +:ppm+.
38
+ # +width+, +height+:: The image dimensions in pixels.
39
+ # +data+:: A string containing the raw pixel data in binary format.
40
+ #
41
+ # Returns a two-dimensional array of bilevel, gray, or RGB values.
42
+ def self.binary2array(type, width, height, data)
43
+ bytes_per_row = byte_width(type, width)
44
+
45
+ if data.size == bytes_per_row * height + 1 && data[-1] =~ /[ \n\t\r]/
46
+ data.slice!(-1)
47
+ end
48
+
49
+ if data.size != bytes_per_row * height
50
+ raise 'data size does not match expected size'
51
+ end
52
+
53
+ case type
54
+ when :pbm
55
+ pixels = data.scan(/.{#{bytes_per_row}}/m)
56
+ pixels.map! {|row| row.unpack('B*').first[0, width].each_char.map {|char| char.to_i } }
57
+ when :pgm
58
+ pixels = data.each_byte.each_slice(bytes_per_row).to_a
59
+ when :ppm
60
+ pixels = data.each_byte.each_slice(bytes_per_row).map {|row| row.each_slice(3).to_a }
61
+ end
62
+
63
+ pixels
64
+ end
65
+
66
+ # Converts a two-dimensional array of pixel values to an ASCII format string.
67
+ #
68
+ # +data+:: A two-dimensional array of bilevel, gray, or RGB values.
69
+ #
70
+ # Returns a string containing the pixel data in ASCII format.
71
+ def self.array2ascii(data)
72
+ case data.first.first
73
+ when Array
74
+ output = data.map {|row| row.flatten.join(' ') }.join("\n")
75
+ else
76
+ output = data.map {|row| row.join(' ') }.join("\n")
77
+ end
78
+
79
+ output << "\n"
80
+ end
81
+
82
+ # Converts a two-dimensional array of pixel values to a binary format string.
83
+ #
84
+ # +type+:: +:pbm+, +:pgm+, or +:ppm+.
85
+ # +data+:: A two-dimensional array of bilevel, gray, or RGB values.
86
+ #
87
+ # Returns a string containing the pixel data in binary format.
88
+ def self.array2binary(type, data)
89
+ height = data.size
90
+
91
+ if type == :pbm
92
+ binary_rows = data.map {|row| row.join }
93
+ data_string = binary_rows.pack('B*' * height)
94
+ else
95
+ data_string = data.flatten.pack('C*')
96
+ end
97
+
98
+ data_string
99
+ end
100
+ end
101
+ end