class PDF::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
44 def formats
45   Formats.constants
46 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
54 def initialize(data, format = nil)
55   @data   = data.dup rescue data
56   @info   = {}
57 
58   if @data.kind_of?(IO)
59     @top = @data.read(128)
60     @data.seek(0, 0)
61       # Define Singleton-method definition to IO (byte, offset)
62     def @data.read_o(length = 1, offset = nil)
63       self.seek(offset, 0) if offset
64       ret = self.read(length)
65       raise "cannot read!!" unless ret
66       ret
67     end
68   elsif @data.is_a?(String)
69     @top = @data[0, 128]
70       # Define Singleton-method definition to String (byte, offset)
71     @data.extend(PDF::Writer::OffsetReader)
72   else
73     raise "argument class error!! #{data.type}"
74   end
75 
76   if format.nil?
77     @format = discover_format
78   else
79     match = false
80     Formats.constants.each { |t| match = true if format == t }
81     raise("format is failed. #{format}\n") unless match
82     @format = format
83   end
84 
85   __send__("measure_#@format".intern) unless @format == Formats::OTHER
86 
87   @data = data.dup
88 end
type_list()
Alias for: formats

Private Instance Methods

discover_format() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
102 def discover_format
103   if    @top        =~ %r{^GIF8[79]a}
104     Formats::GIF
105   elsif @top[0, 3]  == "\xff\xd8\xff"
106     Formats::JPEG
107   elsif @top[0, 8]  == "\x89PNG\x0d\x0a\x1a\x0a"
108     Formats::PNG
109   elsif @top[0, 3]  == "FWS"
110     Formats::SWF
111   elsif @top[0, 4]  == "8BPS"
112     Formats::PSD
113   elsif @top[0, 2]  == 'BM'
114     Formats::BMP
115   elsif @top[0, 4]  == "MM\x00\x2a"
116     Formats::TIFF
117   elsif @top[0, 4]  == "II\x2a\x00"
118     Formats::TIFF
119   elsif @top[0, 12] == "\x00\x00\x00\x0c\x6a\x50\x20\x20\x0d\x0a\x87\x0a"
120     Formats::JP2
121   elsif @top        =~ %r{^P[1-7]}
122     Formats::PPM
123   elsif @top        =~ %r{\#define\s+\S+\s+\d+}
124     Formats::XBM
125   elsif @top        =~ %r{/\* XPM \*/}
126     Formats::XPM
127   elsif @top[0] == 10
128     Formats::PCX
129   else
130     Formats::OTHER  # might be WBMP
131   end
132 end
measure_BMP() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
192 def measure_BMP
193   # Skip the first 14 bytes of the image.
194   @data.read_o(14)
195   # Up to the next 16 bytes will be used.
196   dim = @data.read_o(16)
197 
198   # Get the "size" of the image from the next four bytes.
199   size = dim.unpack("V").first # <- UNPACK RETURNS ARRAY, SO GET FIRST ELEMENT
200 
201   if size == 12
202    @width, @height, @bits = dim.unpack("x4vvx3C")
203   elsif size > 12 and (size <= 64 or size == 108)
204    @width, @height, @bits = dim.unpack("x4VVv")
205   end  
206 end
measure_GIF() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
135 def measure_GIF
136   @data.read_o(6) # Skip GIF8.a
137   @width, @height, @bits = @data.read_o(5).unpack('vvC')
138   if @bits & 0x80 == 0x80
139     @bits = (@bits & 0x07) + 1
140   else
141     @bits = 0
142   end
143   @channels = 3
144 end
measure_JPEG() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
171 def measure_JPEG
172   c_marker = "\xff" # Section marker.
173   @data.read_o(2)   # Skip the first two bytes of JPEG identifier.
174   loop do
175     marker, code, length = @data.read_o(4).unpack('aan')
176     raise "JPEG marker not found!" if marker != c_marker
177 
178     if JPEG_SOF_BLOCKS.include?(code)
179       @bits, @height, @width, @channels = @data.read_o(6).unpack("CnnC")
180       break
181     end
182 
183     buffer = @data.read_o(length - 2)
184 
185     if JPEG_APP_BLOCKS.include?(code)
186       @info["APP#{code.to_i - 0xe0}"] = buffer
187     end
188   end
189 end
measure_PBM()
Alias for: measure_PPM
measure_PCX() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
264 def measure_PCX
265         header = @data.read_o(128)
266         head_part = header.unpack('C4S4')
267         @width  = head_part[6] - head_part[4] + 1
268         @height = head_part[7] - head_part[5] + 1
269 end
measure_PGM()
Alias for: measure_PPM
measure_PNG() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
147 def measure_PNG
148   @data.read_o(12)
149   raise "This file is not PNG." unless @data.read_o(4) == "IHDR"
150     # The file information is in the IHDR section.
151     #   Offset  Bytes Meaning
152     #    0      4     Width
153     #    5      4     Height
154     #    9      1     Bit Depth
155     #   10      1     Compression Method
156     #   11      1     Filter Method
157     #   12      1     Interlace Method
158   ihdr = @data.read_o(13).unpack("NNCCCCC")
159   @width                      = ihdr[0]
160   @height                     = ihdr[1]
161   @bits                       = ihdr[2]
162   @info[:color_type]          = ihdr[3]
163   @info[:compression_method]  = ihdr[4]
164   @info[:filter_method]       = ihdr[5]
165   @info[:interlace_method]    = ihdr[6]
166 
167 
168 end
measure_PPM() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
209   def measure_PPM
210     header = @data.read_o(1024)
211     header.gsub!(/^\#[^\n\r]*/m, "")
212     md = %r{^(P[1-6])\s+?(\d+)\s+?(\d+)}mo.match(header)
213 
214     @width  = md.captures[1]
215     @height = md.captures[2]
216 
217     case md.captures[0]
218     when "P1", "P4"
219       @format = "PBM"
220     when "P2", "P5"
221       @format = "PGM"
222     when "P3", "P6"
223       @format = "PPM"
224 #   when "P7"
225 #     @format = "XV"
226 #     header =~ /IMGINFO:(\d+)x(\d+)/m
227 #     width = $1.to_i; height = $2.to_i
228     end
229   end
Also aliased as: measure_PGM, measure_PBM
measure_PSD() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
259 def measure_PSD
260         @width, @height = @data.read_o(26).unpack("x14NN")
261 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
292 def measure_SWC
293 end
measure_SWF() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
272 def measure_SWF
273         header = @data.read_o(9)
274         raise "This file is not SWF."  unless header.unpack('a3')[0] == 'FWS'
275 
276         bits    = Integer("0b#{header.unpack('@8B5')}")
277         header << @data.read_o(bits * 4 / 8 + 1)
278 
279         str     = *(header.unpack("@8B#{5 + bits * 4}"))
280         last    = 5
281         x_min   = Integer("0b#{str[last, bits]}")
282         x_max   = Integer("0b#{str[(last + bits), bits]}")
283         y_min   = Integer("0b#{str[(last + (2 * bits)), bits]}")
284         y_max   = Integer("0b#{str[(last + (3 * bits)), bits]}")
285         @width  = (x_max - x_min) / 20
286         @height = (y_max - y_min) / 20
287 end
measure_TIFF() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
296 def measure_TIFF
297     # 'v' little-endian
298     # 'n' default to big-endian
299   endian = (@data.read_o(4) =~ /II\x2a\x00/o) ? 'v' : 'n'
300 
301               packspec = [
302                       nil,           # nothing (shouldn't happen)
303                       'C',           # BYTE (8-bit unsigned integer)
304                       nil,           # ASCII
305                       endian,        # SHORT (16-bit unsigned integer)
306                       endian.upcase, # LONG (32-bit unsigned integer)
307                       nil,           # RATIONAL
308                       'c',           # SBYTE (8-bit signed integer)
309                       nil,           # UNDEFINED
310                       endian,        # SSHORT (16-bit unsigned integer)
311                       endian.upcase, # SLONG (32-bit unsigned integer)
312               ]
313 
314     # Find the IFD location.
315               ifd_addr    = *(@data.read_o(4).unpack(endian.upcase))
316     # Get the number of entries in the IFD.
317               ifd         = @data.read_o(2, ifd_addr)
318               num_dirent  = *(ifd.unpack(endian))         # Make it useful
319               ifd_addr    += 2
320               num_dirent  = ifd_addr + (num_dirent * 12)  # Calc. maximum offset of IFD
321 
322   loop do
323     break if @width and @height
324 
325     ifd = @data.read_o(12, ifd_addr)  # Get directory entry.
326     break if ifd.nil? or ifd_addr > num_dirent
327     ifd_addr += 12
328 
329     tag   = *(ifd.unpack(endian))       # ...decode its tag
330     type  = *(ifd[2, 2].unpack(endian)) # ... and data type
331 
332       # Check the type for sanity.
333     next if type > packspec.size or packspec[type].nil?
334 
335     case tag
336     when 0x0100, 0xa002 # width
337       @width  = *(ifd[8, 4].unpack(packspec[type]))
338     when 0x0101, 0xa003 # height
339       @height = *(ifd[8, 4].unpack(packspec[type]))
340     end
341   end
342       end
measure_XBM() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
238     def measure_XBM
239 md = XBM_DIMENSIONS_RE.match(@data.read_o(1024))
240 
241 @width  = md.captures[0].to_i
242 @height = md.captures[1].to_i
243     end
measure_XPM() click to toggle source
    # File lib/pdf/writer/graphics/imageinfo.rb
247     def measure_XPM
248 while line = @data.read_o(1024)
249   md = XPM_DIMENSIONS_RE.match(line)
250   if md
251     @width  = md.captures[0].to_i
252     @height = md.captures[1].to_i
253     break
254   end
255 end
256     end