class NewerImageSize

Attributes

format[R]

Image format

h[R]

Image height

height[R]

Image height

w[R]

Image width

width[R]

Image width

Public Class Methods

new(data) click to toggle source

Given image as IO, StringIO, Tempfile or String finds its format and dimensions

# File lib/newer_image_size.rb, line 48
def initialize(data)
  ir = ImageReader.new(data)
  if @format = detect_format(ir)
    @width, @height = self.send("size_of_#{@format}", ir)
  end
  ir.rewind
end
path(path) click to toggle source

Given path to image finds its format, width and height

# File lib/newer_image_size.rb, line 43
def self.path(path)
  open(path, 'rb'){ |f| new(f) }
end

Public Instance Methods

size() click to toggle source

get image width and height as an array which to_s method returns “#{width}x#{height}”

# File lib/newer_image_size.rb, line 68
def size
  if format
    Size.new([width, height])
  end
end

Private Instance Methods

detect_format(ir) click to toggle source
# File lib/newer_image_size.rb, line 76
def detect_format(ir)
  head = ir[0, 1024]
  case
  when head =~ /^GIF8[7,9]a/              then :gif
  when head[0, 8] == "\211PNG\r\n\032\n"  then :png
  when head[0, 2] == "\377\330"           then :jpeg
  when head[0, 2] == 'BM'                 then :bmp
  when head =~ /^P[1-7]/                  then :ppm
  when head =~ /\#define\s+\S+\s+\d+/     then :xbm
  when head[0, 4] == "II*\000"            then :tiff
  when head[0, 4] == "MM\000*"            then :tiff
  when head =~ /\/\* XPM \*\//            then :xpm
  when head[0, 4] == '8BPS'               then :psd
  when head =~ /^[FC]WS/                  then :swf
  when head[0, 1] == "\n"                 then :pcx
  end
end
size_of_bmp(ir) click to toggle source
# File lib/newer_image_size.rb, line 126
def size_of_bmp(ir)
  ir[18, 8].unpack('VV')
end
size_of_gif(ir) click to toggle source
# File lib/newer_image_size.rb, line 94
def size_of_gif(ir)
  ir[6, 4].unpack('vv')
end
size_of_jpeg(ir) click to toggle source
# File lib/newer_image_size.rb, line 111
def size_of_jpeg(ir)
  section_marker = "\xFF"
  offset = 2
  loop do
    marker, code, length = ir[offset, 4].unpack('aan')
    offset += 4
    raise 'JPEG marker not found' if marker != section_marker

    if JpegCodeCheck.include?(code)
      return ir[offset + 1, 4].unpack('nn').reverse
    end
    offset += length - 2
  end
end
size_of_pcx(ir) click to toggle source
# File lib/newer_image_size.rb, line 191
def size_of_pcx(ir)
  parts = ir[4, 8].unpack('S4')
  [parts[2] - parts[0] + 1, parts[3] - parts[1] + 1]
end
size_of_png(ir) click to toggle source
# File lib/newer_image_size.rb, line 98
def size_of_png(ir)
  unless ir[12, 4] == 'IHDR'
    raise 'IHDR not in place for PNG'
  end
  ir[16, 8].unpack('NN')
end
size_of_ppm(ir) click to toggle source
# File lib/newer_image_size.rb, line 130
def size_of_ppm(ir)
  header = ir[0, 1024]
  header.gsub!(/^\#[^\n\r]*/m, '')
  header =~ /^(P[1-6])\s+?(\d+)\s+?(\d+)/m
  case $1
    when 'P1', 'P4' then @format = :pbm
    when 'P2', 'P5' then @format = :pgm
  end
  [$2.to_i, $3.to_i]
end
size_of_psd(ir) click to toggle source
# File lib/newer_image_size.rb, line 157
def size_of_psd(ir)
  ir[14, 8].unpack('NN')
end
size_of_swf(ir) click to toggle source
# File lib/newer_image_size.rb, line 196
def size_of_swf(ir)
  value_bit_length = ir[8, 1].unpack('B5').first.to_i(2)
  bit_length = 5 + value_bit_length * 4
  rect_bits = ir[8, bit_length / 8 + 1].unpack("B#{bit_length}").first
  values = rect_bits.unpack('@5' + "a#{value_bit_length}" * 4).map{ |bits| bits.to_i(2) }
  x_min, x_max, y_min, y_max = values
  [(x_max - x_min) / 20, (y_max - y_min) / 20]
end
size_of_tiff(ir) click to toggle source
# File lib/newer_image_size.rb, line 161
def size_of_tiff(ir)
  endian2b = (ir[0, 4] == "II*\000") ? 'v' : 'n'
  endian4b = endian2b.upcase
  packspec = [nil, 'C', nil, endian2b, endian4b, nil, 'c', nil, endian2b, endian4b]

  offset = ir[4, 4].unpack(endian4b)[0]
  num_dirent = ir[offset, 2].unpack(endian2b)[0]
  offset += 2
  num_dirent = offset + (num_dirent * 12)

  width = height = nil
  until width && height
    ifd = ir[offset, 12]
    raise 'Reached end of directory entries in TIFF' if ifd.nil? || offset > num_dirent
    tag, type = ifd.unpack(endian2b * 2)
    offset += 12

    unless packspec[type].nil?
      value = ifd[8, 4].unpack(packspec[type])[0]
      case tag
      when 0x0100
        width = value
      when 0x0101
        height = value
      end
    end
  end
  [width, height]
end
size_of_xbm(ir) click to toggle source
# File lib/newer_image_size.rb, line 141
def size_of_xbm(ir)
  ir[0, 1024] =~ /^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)/mi
  [$1.to_i, $2.to_i]
end
size_of_xpm(ir) click to toggle source
# File lib/newer_image_size.rb, line 146
def size_of_xpm(ir)
  length = 1024
  until (data = ir[0, length]) =~ /"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*"/m
    if data.length != length
      raise 'XPM size not found'
    end
    length += 1024
  end
  [$1.to_i, $2.to_i]
end