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