Class: Tb::PNMReader

Inherits:
Object
  • Object
show all
Defined in:
lib/tb/pnm.rb

Overview

practical only for (very) small images.

Constant Summary collapse

WSP =
/(?:[ \t\r\n]|\#[^\r\n]*[\r\n])+/

Instance Method Summary collapse

Constructor Details

#initialize(pnm_content) ⇒ PNMReader

Returns a new instance of PNMReader.

Raises:

  • (ArgumentError)


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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/tb/pnm.rb', line 62

def initialize(pnm_content)
  pnm_content.force_encoding("ASCII-8BIT") if pnm_content.respond_to? :force_encoding
  if /\A(P[63])(#{WSP})(\d+)(#{WSP})(\d+)(#{WSP})(\d+)[ \t\r\n]/on =~ pnm_content
    magic, wsp1, w, wsp2, h, wsp3, max, raster = $1, $2, $3.to_i, $4, $5.to_i, $6, $7.to_i, $'
    pixel_component = %w[R G B]
  elsif /\A(P[52])(#{WSP})(\d+)(#{WSP})(\d+)(#{WSP})(\d+)[ \t\r\n]/on =~ pnm_content
    magic, wsp1, w, wsp2, h, wsp3, max, raster = $1, $2, $3.to_i, $4, $5.to_i, $6, $7.to_i, $'
    pixel_component = %w[V]
  elsif /\A(P[41])(#{WSP})(\d+)(#{WSP})(\d+)[ \t\r\n]/on =~ pnm_content
    magic, wsp1, w, wsp2, h, raster = $1, $2, $3.to_i, $4, $5.to_i, $'
    wsp3 = nil
    max = 1
    pixel_component = %w[V]
  else
    raise ArgumentError, "not PNM format"
  end
  raise ArgumentError, "unsupported max value: #{max}" if 65535 < max

  @ary = [
    ['type', 'x', 'y', 'component', 'value'],
    ['meta', nil, nil, 'pnm_type', magic],
    ['meta', nil, nil, 'width', w],
    ['meta', nil, nil, 'height', h],
    ['meta', nil, nil, 'max', max]
  ]

  [wsp1, wsp2, wsp3].each {|wsp|
    next if !wsp
    wsp.scan(/\#([^\r\n]*)[\r\n]/) { @ary << ['meta', nil, nil, 'comment', $1] }
  }

  if /P[65]/ =~ magic # raw (binary) PPM/PGM
    if max < 0x100
      each_pixel_component = method(:raw_ppm_pgm_1byte_each_pixel_component)
    else
      each_pixel_component = method(:raw_ppm_pgm_2byte_each_pixel_component)
    end
  elsif /P4/ =~ magic # raw (binary) PBM
    each_pixel_component = make_raw_pbm_each_pixel_component(w)
  elsif /P[32]/ =~ magic # plain (ascii) PPM/PGM
    each_pixel_component = method(:plain_ppm_pgm_each_pixel_component)
  elsif /P1/ =~ magic # plain (ascii) PBM
    each_pixel_component = method(:plain_pbm_each_pixel_component)
  end
  n = w * h * pixel_component.length
  i = 0
  each_pixel_component.call(raster) {|value|
    break if i == n
    y, x = (i / pixel_component.length).divmod(w)
    c = pixel_component[i % pixel_component.length]
    @ary << ['pixel', x, y, c, value.to_f / max]
    i += 1
  }
  if i != n
    raise ArgumentError, "PNM raster data too short."
  end
end

Instance Method Details

#closeObject



179
180
# File 'lib/tb/pnm.rb', line 179

def close
end

#eachObject



166
167
168
169
170
171
# File 'lib/tb/pnm.rb', line 166

def each
  while ary = self.shift
    yield ary
  end
  nil
end

#make_raw_pbm_each_pixel_component(width) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/tb/pnm.rb', line 139

def make_raw_pbm_each_pixel_component(width)
  iter = Object.new
  iter.instance_variable_set(:@width, width)
  def iter.call(raster)
    numbytes = (@width + 7) / 8
    y = 0
    while true
      return if raster.size <= y * numbytes
      line = raster[y * numbytes, numbytes]
      x = 0
      while x < @width
        i, j = x.divmod(8)
        return if line.size <= i
        byte = line[x/8].ord
        yield 1 - ((byte >> (7-j)) & 1)
        x += 1
      end
      y += 1
    end
  end
  iter
end

#plain_pbm_each_pixel_component(raster) ⇒ Object



135
136
137
# File 'lib/tb/pnm.rb', line 135

def plain_pbm_each_pixel_component(raster)
  raster.scan(/[01]/) { yield 1 - $&.to_i }
end

#plain_ppm_pgm_each_pixel_component(raster) ⇒ Object



131
132
133
# File 'lib/tb/pnm.rb', line 131

def plain_ppm_pgm_each_pixel_component(raster)
  raster.scan(/\d+/) { yield $&.to_i }
end

#raw_ppm_pgm_1byte_each_pixel_component(raster, &b) ⇒ Object



120
121
122
# File 'lib/tb/pnm.rb', line 120

def raw_ppm_pgm_1byte_each_pixel_component(raster, &b)
  raster.each_byte(&b)
end

#raw_ppm_pgm_2byte_each_pixel_component(raster) ⇒ Object



124
125
126
127
128
129
# File 'lib/tb/pnm.rb', line 124

def raw_ppm_pgm_2byte_each_pixel_component(raster)
  raster.enum_for(:each_byte).each_slice(2) {|byte1, byte2|
    word = byte1 * 0x100 + byte2
    yield word
  }
end

#shiftObject



162
163
164
# File 'lib/tb/pnm.rb', line 162

def shift
  @ary.shift
end

#to_aObject



173
174
175
176
177
# File 'lib/tb/pnm.rb', line 173

def to_a
  result= []
  each {|ary| result << ary }
  result
end