Class: ImageSpec::Parser::SWF

Inherits:
Object
  • Object
show all
Defined in:
lib/image_spec/parser/swf.rb

Constant Summary collapse

CONTENT_TYPE =
'application/x-shockwave-flash'

Class Method Summary collapse

Class Method Details

.attributes(stream) ⇒ Object



7
8
9
10
# File 'lib/image_spec/parser/swf.rb', line 7

def self.attributes(stream)
  width, height, version = dimensions(stream)
  {:width => width, :height => height, :content_type => CONTENT_TYPE, :version => version, :dimensions => [width, height], :file_size => size(stream)}
end

.detected?(stream) ⇒ Boolean

Returns:

  • (Boolean)


12
13
14
15
# File 'lib/image_spec/parser/swf.rb', line 12

def self.detected?(stream)
  stream.rewind
  stream.read(3) =~ /(F|C)WS/ ? true : false
end

.dimensions(stream) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/image_spec/parser/swf.rb', line 17

def self.dimensions(stream)
  # Read the entire stream into memory because the
  # dimensions aren't stored in a standard location
  stream.rewind
  contents = stream.read.force_encoding("ASCII-8BIT")

  # Our 'signature' is the first 3 bytes
  # Either FWS or CWS.  CWS indicates compression
  signature = contents[0..2]

  # SWF version
  version = contents[3].unpack('C').join.to_i

  # Determine the length of the uncompressed stream
  length = contents[4..7].unpack('V').join.to_i

  # If we do, in fact, have compression
  if signature == 'CWS'
    # Decompress the body of the SWF
    body = Zlib::Inflate.inflate( contents[8..length] )

    # And reconstruct the stream contents to the first 8 bytes (header)
    # Plus our decompressed body
    contents = contents[0..7] + body
  end

  # Determine the nbits of our dimensions rectangle
  nbits = contents.unpack('C'*contents.length)[8] >> 3

  # Determine how many bits long this entire RECT structure is
  rectbits = 5 + nbits * 4    # 5 bits for nbits, as well as nbits * number of fields (4)

  # Determine how many bytes rectbits composes (ceil(rectbits/8))
  rectbytes = (rectbits.to_f / 8).ceil

  # Unpack the RECT structure from the stream in little-endian bit order, then join it into a string
  rect = contents[8..(8 + rectbytes)].unpack("#{'B8' * rectbytes}").join()

  # Read in nbits incremenets starting from 5
  dimensions = Array.new
  4.times do |n|
    s = 5 + (n * nbits)     # Calculate our start index
    e = s + (nbits - 1)     # Calculate our end index
    dimensions[n] = rect[s..e].to_i(2)    # Read that range (binary) and convert it to an integer
  end

  # The values we have here are in "twips"
  # 20 twips to a pixel (that's why SWFs are fuzzy sometimes!)
  width   = (dimensions[1] - dimensions[0]) / 20
  height  = (dimensions[3] - dimensions[2]) / 20

  # If you can't figure this one out, you probably shouldn't have read this far
  return [width, height, version]
end

.size(stream) ⇒ Object



72
73
74
# File 'lib/image_spec/parser/swf.rb', line 72

def self.size(stream)
  stream.size
end