| Class | PDF::Writer::Graphics::ImageInfo |
| In: |
lib/pdf/writer/graphics/imageinfo.rb
|
| Parent: | Object |
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.
| 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 |
| formats | -> | type_list |
| format | -> | get_type |
| height | -> | get_height |
| width | -> | get_width |
| bits | [R] | |
| channels | [R] | |
| format | [R] | |
| height | [R] | |
| info | [R] | |
| width | [R] |
Receive image & make size. argument is image String or IO
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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.
# File lib/pdf/writer/graphics/imageinfo.rb, line 292
292: def measure_SWC
293: end
# 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
# 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
# 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