Class PDF::Writer::Graphics::ImageInfo
In: lib/pdf/writer/graphics/imageinfo.rb
Parent: Object
TechBook Transaction::Simple SimpleTable Complex Action FontDescriptor Procset Catalog FontEncoding Pages Destination Info Encryption Annotation Contents Outline Page Outlines Font ViewerPreferences Image Hash OHash QuickRef StdDev FontMetrics StrokeStyle ARC4 PolygonPoint ImageInfo lib/pdf/simpletable.rb lib/pdf/writer.rb lib/pdf/techbook.rb lib/pdf/quickref.rb lib/pdf/charts/stddev.rb Charts Math lib/pdf/writer/ohash.rb lib/pdf/writer/fontmetrics.rb lib/pdf/writer/strokestyle.rb lib/pdf/writer/arc4.rb lib/pdf/writer/graphics.rb lib/pdf/writer/object.rb lib/pdf/writer/object/image.rb External lib/pdf/writer/object/font.rb lib/pdf/writer/object/outlines.rb lib/pdf/writer/object/contents.rb lib/pdf/writer/object/annotation.rb lib/pdf/writer/object/destination.rb lib/pdf/writer/object/viewerpreferences.rb lib/pdf/writer/object/info.rb lib/pdf/writer/object/fontencoding.rb lib/pdf/writer/object/page.rb lib/pdf/writer/object/catalog.rb lib/pdf/writer/object/outline.rb lib/pdf/writer/object/encryption.rb lib/pdf/writer/object/procset.rb lib/pdf/writer/object/action.rb lib/pdf/writer/object/pages.rb lib/pdf/writer/object/fontdescriptor.rb Object OffsetReader EN Lang lib/pdf/writer/graphics/imageinfo.rb Graphics Writer PDF dot/m_33_0.png

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.

Methods

Classes and Modules

Module PDF::Writer::Graphics::ImageInfo::Formats

Constants

Type = Formats
JPEG_SOF_BLOCKS = %W(\xc0 \xc1 \xc2 \xc3 \xc5 \xc6 \xc7 \xc9 \xca \xcb \xcd \xce \xcf)
JPEG_APP_BLOCKS = %W(\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef)
XBM_DIMENSIONS_RE = %r{^\#define\s*\S*\s*(\d+)\s*\n\#define\s*\S*\s*(\d+)}mi
XPM_DIMENSIONS_RE = %r<"\s*(\d+)\s+(\d+)(\s+\d+\s+\d+){1,2}\s*">m

External Aliases

formats -> type_list
format -> get_type
height -> get_height
width -> get_width

Attributes

bits  [R] 
channels  [R] 
format  [R] 
height  [R] 
info  [R] 
width  [R] 

Public Class methods

[Source]

    # File lib/pdf/writer/graphics/imageinfo.rb, line 44
44:     def formats
45:       Formats.constants
46:     end

Receive image & make size. argument is image String or IO

[Source]

    # File lib/pdf/writer/graphics/imageinfo.rb, line 54
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

Private Instance methods

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 102
102:   def  discover_formatdiscover_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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 192
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 135
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 171
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 264
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 147
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 209
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 259
259:         def measure_PSD
260:                 @width, @height = @data.read_o(26).unpack("x14NN")
261:         end

The same as SWF, except that the original data is compressed with Zlib. Disabled for now.

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 292
292:   def measure_SWC
293:   end

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 272
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 296
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 238
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

[Source]

     # File lib/pdf/writer/graphics/imageinfo.rb, line 247
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

[Validate]