class Writer::Graphics::ImageInfo
This is based on ImageSize, by Keisuke Minami <keisuke@rccn.com>. It can be found at www.rubycgi.org/tools/index.en.htm
This has been integrated into PDF::Writer because as yet there has been no response to emails asking for my extensions to be integrated and a RubyGem package to be made available.
Constants
- JPEG_APP_BLOCKS
- JPEG_SOF_BLOCKS
- Type
Image Format Constants
- XBM_DIMENSIONS_RE
- XPM_DIMENSIONS_RE
Attributes
bits[R]
channels[R]
format[R]
get_height[R]
get_type[R]
get_width[R]
height[R]
info[R]
width[R]
Public Class Methods
formats()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 44 def formats Formats.constants end
Also aliased as: type_list
new(data, format = nil)
click to toggle source
Receive image & make size. argument is image String or IO
# File lib/pdf/writer/graphics/imageinfo.rb, line 54 def initialize(data, format = nil) @data = data.dup rescue data @info = {} if @data.kind_of?(IO) @top = @data.read(128) @data.seek(0, 0) # Define Singleton-method definition to IO (byte, offset) def @data.read_o(length = 1, offset = nil) self.seek(offset, 0) if offset ret = self.read(length) raise "cannot read!!" unless ret ret end elsif @data.is_a?(String) @top = @data[0, 128] # Define Singleton-method definition to String (byte, offset) @data.extend(PDF::Writer::OffsetReader) else raise "argument class error!! #{data.type}" end if format.nil? @format = discover_format else match = false Formats.constants.each { |t| match = true if format == t } raise("format is failed. #{format}\n") unless match @format = format end __send__("measure_#@format".intern) unless @format == Formats::OTHER @data = data.dup end
Private Instance Methods
discover_format()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 102 def discover_format if @top =~ %r{^GIF8[79]a} Formats::GIF elsif @top[0, 3] == "\xff\xd8\xff" Formats::JPEG elsif @top[0, 8] == "\x89PNG\x0d\x0a\x1a\x0a" Formats::PNG elsif @top[0, 3] == "FWS" Formats::SWF elsif @top[0, 4] == "8BPS" Formats::PSD elsif @top[0, 2] == 'BM' Formats::BMP elsif @top[0, 4] == "MM\x00\x2a" Formats::TIFF elsif @top[0, 4] == "II\x2a\x00" Formats::TIFF elsif @top[0, 12] == "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a" Formats::JP2 elsif @top =~ %r{^P[1-7]} Formats::PPM elsif @top =~ %r{\#define\s+\S+\s+\d+} Formats::XBM elsif @top =~ %r{/\* XPM \*/} Formats::XPM elsif @top[0] == 10 Formats::PCX else Formats::OTHER # might be WBMP end end
measure_BMP()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 192 def measure_BMP # Skip the first 14 bytes of the image. @data.read_o(14) # Up to the next 16 bytes will be used. dim = @data.read_o(16) # Get the "size" of the image from the next four bytes. size = dim.unpack("V").first # <- UNPACK RETURNS ARRAY, SO GET FIRST ELEMENT if size == 12 @width, @height, @bits = dim.unpack("x4vvx3C") elsif size > 12 and (size <= 64 or size == 108) @width, @height, @bits = dim.unpack("x4VVv") end end
measure_GIF()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 135 def measure_GIF @data.read_o(6) # Skip GIF8.a @width, @height, @bits = @data.read_o(5).unpack('vvC') if @bits & 0x80 == 0x80 @bits = (@bits & 0x07) + 1 else @bits = 0 end @channels = 3 end
measure_JPEG()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 171 def measure_JPEG c_marker = "\xff" # Section marker. @data.read_o(2) # Skip the first two bytes of JPEG identifier. loop do marker, code, length = @data.read_o(4).unpack('aan') raise "JPEG marker not found!" if marker != c_marker if JPEG_SOF_BLOCKS.include?(code) @bits, @height, @width, @channels = @data.read_o(6).unpack("CnnC") break end buffer = @data.read_o(length - 2) if JPEG_APP_BLOCKS.include?(code) @info["APP#{code.to_i - 0xe0}"] = buffer end end end
measure_PCX()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 264 def measure_PCX header = @data.read_o(128) head_part = header.unpack('C4S4') @width = head_part[6] - head_part[4] + 1 @height = head_part[7] - head_part[5] + 1 end
measure_PNG()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 147 def measure_PNG @data.read_o(12) raise "This file is not PNG." unless @data.read_o(4) == "IHDR" # The file information is in the IHDR section. # Offset Bytes Meaning # 0 4 Width # 5 4 Height # 9 1 Bit Depth # 10 1 Compression Method # 11 1 Filter Method # 12 1 Interlace Method ihdr = @data.read_o(13).unpack("NNCCCCC") @width = ihdr[0] @height = ihdr[1] @bits = ihdr[2] @info[:color_type] = ihdr[3] @info[:compression_method] = ihdr[4] @info[:filter_method] = ihdr[5] @info[:interlace_method] = ihdr[6] end
measure_PPM()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 209 def measure_PPM header = @data.read_o(1024) header.gsub!(/^\#[^\n\r]*/m, "") md = %r{^(P[1-6])\s+?(\d+)\s+?(\d+)}mo.match(header) @width = md.captures[1] @height = md.captures[2] case md.captures[0] when "P1", "P4" @format = "PBM" when "P2", "P5" @format = "PGM" when "P3", "P6" @format = "PPM" # when "P7" # @format = "XV" # header =~ /IMGINFO:(\d+)x(\d+)/m # width = $1.to_i; height = $2.to_i end end
Also aliased as: measure_PGM, measure_PBM
measure_PSD()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 259 def measure_PSD @width, @height = @data.read_o(26).unpack("x14NN") end
measure_SWC()
click to toggle source
The same as SWF, except that the original data is compressed with Zlib. Disabled for now.
# File lib/pdf/writer/graphics/imageinfo.rb, line 292 def measure_SWC end
measure_SWF()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 272 def measure_SWF header = @data.read_o(9) raise "This file is not SWF." unless header.unpack('a3')[0] == 'FWS' bits = Integer("0b#{header.unpack('@8B5')}") header << @data.read_o(bits * 4 / 8 + 1) str = *(header.unpack("@8B#{5 + bits * 4}")) last = 5 x_min = Integer("0b#{str[last, bits]}") x_max = Integer("0b#{str[(last + bits), bits]}") y_min = Integer("0b#{str[(last + (2 * bits)), bits]}") y_max = Integer("0b#{str[(last + (3 * bits)), bits]}") @width = (x_max - x_min) / 20 @height = (y_max - y_min) / 20 end
measure_TIFF()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 296 def measure_TIFF # 'v' little-endian # 'n' default to big-endian endian = (@data.read_o(4) =~ /II\x2a\x00/o) ? 'v' : 'n' packspec = [ nil, # nothing (shouldn't happen) 'C', # BYTE (8-bit unsigned integer) nil, # ASCII endian, # SHORT (16-bit unsigned integer) endian.upcase, # LONG (32-bit unsigned integer) nil, # RATIONAL 'c', # SBYTE (8-bit signed integer) nil, # UNDEFINED endian, # SSHORT (16-bit unsigned integer) endian.upcase, # SLONG (32-bit unsigned integer) ] # Find the IFD location. ifd_addr = *(@data.read_o(4).unpack(endian.upcase)) # Get the number of entries in the IFD. ifd = @data.read_o(2, ifd_addr) num_dirent = *(ifd.unpack(endian)) # Make it useful ifd_addr += 2 num_dirent = ifd_addr + (num_dirent * 12) # Calc. maximum offset of IFD loop do break if @width and @height ifd = @data.read_o(12, ifd_addr) # Get directory entry. break if ifd.nil? or ifd_addr > num_dirent ifd_addr += 12 tag = *(ifd.unpack(endian)) # ...decode its tag type = *(ifd[2, 2].unpack(endian)) # ... and data type # Check the type for sanity. next if type > packspec.size or packspec[type].nil? case tag when 0x0100, 0xa002 # width @width = *(ifd[8, 4].unpack(packspec[type])) when 0x0101, 0xa003 # height @height = *(ifd[8, 4].unpack(packspec[type])) end end end
measure_XBM()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 238 def measure_XBM md = XBM_DIMENSIONS_RE.match(@data.read_o(1024)) @width = md.captures[0].to_i @height = md.captures[1].to_i end
measure_XPM()
click to toggle source
# File lib/pdf/writer/graphics/imageinfo.rb, line 247 def measure_XPM while line = @data.read_o(1024) md = XPM_DIMENSIONS_RE.match(line) if md @width = md.captures[0].to_i @height = md.captures[1].to_i break end end end