Class: Jif::Gif

Inherits:
Object
  • Object
show all
Defined in:
lib/jif.rb

Constant Summary collapse

END_OF_HEADER_AND_LFD =

Header and LFD are a fixed size

103
GIF_TRAILER =

0x3B

"00111011"
IMAGE_SEPARATOR =

0x2C

"00101100"
EXTENSION_INTRODUCER =

0x21

"00100001"
GRAPHICS_CONTROL_EXTENSION_LABEL =

Extension Labels

"11111001"
PLAIN_TEXT_LABEL =

0x01

"00000001"
APPLICATION_EXTENSION_LABEL =

0xFF

"11111111"
COMMENT_EXTENSION_LABEL =

0xFE

"11111110"

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file_name) ⇒ Gif

Returns a new instance of Gif.



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
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/jif.rb', line 22

def initialize(file_name)
  s = File.binread(file_name)
  bits = s.unpack("B*")[0]
  raise "Error: Unable to parse file. Gif must be GIF89a, found: #{b_to_h(bits[0..47])}" unless b_to_h(bits[0..47]) == "0x474946383961"

  @header = bits[0..47]
  @logical_screen_descriptor = bits[48..103]
  @canvas_width = logical_screen_descriptor[0..15]
  @canvas_height = logical_screen_descriptor[16..31]
  @packed_field = logical_screen_descriptor[32..39]
  @background_color_index = logical_screen_descriptor[40..47]
  @pixel_aspect_ratio = logical_screen_descriptor[48..74]
  @global_color_table_flag = packed_field[0]
  @color_resolution = packed_field[1..3]
  @sort_flag = packed_field[4]
  @size_of_global_color_table = packed_field[5..7]

  bits = bits[(END_OF_HEADER_AND_LFD + 1)..-1]
  if @global_color_table_flag == "1"
    @global_color_table = color_table_parser(bits, @size_of_global_color_table)
    bits = bits[@global_color_table.size..-1]
  end

  @tail = [] # An Array of hashes containing the remainder of the file broken into blocks
  until (bits[0..7] == GIF_TRAILER)
    if bits[0..7] == EXTENSION_INTRODUCER
      case bits[8..15]
      when GRAPHICS_CONTROL_EXTENSION_LABEL
        graphics_control_extension = graphics_control_extension_parser bits
        @tail.push graphics_control_extension
        bits = bits[graphics_control_extension[:total_block_size]..-1]
      when PLAIN_TEXT_LABEL, APPLICATION_EXTENSION_LABEL
        extension = extension_parser bits
        @tail.push extension
        bits = bits[extension[:total_block_size]..-1]
      when COMMENT_EXTENSION_LABEL
        comment_extension = comment_extension_parser bits
        @tail.push comment_extension
        bits = bits[comment_extension[:total_block_size]..-1]
      end
    elsif bits[0..7] == IMAGE_SEPARATOR
      image_descriptor = image_descriptor_parser bits
      bits = bits[image_descriptor[:total_block_size]..-1]
      local_color_table = nil
      if image_descriptor[:packed_field][:local_color_table_flag] == "1"
        local_color_table = color_table_parser(bits, image_descriptor[:packed_field][:size_of_local_color_table])
        bits = bits[local_color_table.size..-1]
      end
      image_data = image_data_parser bits
      data = {
        image_descriptor: image_descriptor,
        local_color_table: local_color_table,
        image_data: image_data,
      }
      @tail.push data

      bits = bits[data[:image_data][:total_block_size]..-1]
    else
      raise "Error: Unknown block header: #{bits[0..7]}"
    end
  end
end

Instance Attribute Details

#background_color_indexObject

Returns the value of attribute background_color_index.



17
18
19
# File 'lib/jif.rb', line 17

def background_color_index
  @background_color_index
end

#canvas_heightObject

Returns the value of attribute canvas_height.



17
18
19
# File 'lib/jif.rb', line 17

def canvas_height
  @canvas_height
end

#canvas_widthObject

Returns the value of attribute canvas_width.



17
18
19
# File 'lib/jif.rb', line 17

def canvas_width
  @canvas_width
end

#color_resolutionObject

Returns the value of attribute color_resolution.



17
18
19
# File 'lib/jif.rb', line 17

def color_resolution
  @color_resolution
end

#global_color_tableObject

Returns the value of attribute global_color_table.



17
18
19
# File 'lib/jif.rb', line 17

def global_color_table
  @global_color_table
end

#global_color_table_flagObject

Returns the value of attribute global_color_table_flag.



17
18
19
# File 'lib/jif.rb', line 17

def global_color_table_flag
  @global_color_table_flag
end

#headerObject

Returns the value of attribute header.



17
18
19
# File 'lib/jif.rb', line 17

def header
  @header
end

#logical_screen_descriptorObject

Returns the value of attribute logical_screen_descriptor.



17
18
19
# File 'lib/jif.rb', line 17

def logical_screen_descriptor
  @logical_screen_descriptor
end

#packed_fieldObject

Returns the value of attribute packed_field.



17
18
19
# File 'lib/jif.rb', line 17

def packed_field
  @packed_field
end

#pixel_aspect_ratioObject

Returns the value of attribute pixel_aspect_ratio.



17
18
19
# File 'lib/jif.rb', line 17

def pixel_aspect_ratio
  @pixel_aspect_ratio
end

#size_of_global_color_tableObject

Returns the value of attribute size_of_global_color_table.



17
18
19
# File 'lib/jif.rb', line 17

def size_of_global_color_table
  @size_of_global_color_table
end

#sort_flagObject

Returns the value of attribute sort_flag.



17
18
19
# File 'lib/jif.rb', line 17

def sort_flag
  @sort_flag
end

#tailObject

Returns the value of attribute tail.



17
18
19
# File 'lib/jif.rb', line 17

def tail
  @tail
end

Instance Method Details

#rebuild(new_file_name = "out.gif") ⇒ Object



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/jif.rb', line 85

def rebuild(new_file_name="out.gif")
  bit_string = @header
  bit_string += @logical_screen_descriptor
  bit_string += @global_color_table if @global_color_table
  @tail.each do |block|
    if block[:image_descriptor]
      bit_string += image_descriptor_builder block[:image_descriptor]
      bit_string += block[:local_color_table] if block[:local_color_table]
      bit_string += image_data_builder block[:image_data]
    elsif block[:extension_introducer]
      case block[:label]
      when GRAPHICS_CONTROL_EXTENSION_LABEL
        bit_string += graphics_control_extension_builder block
      when PLAIN_TEXT_LABEL, APPLICATION_EXTENSION_LABEL
        bit_string += extension_builder block
      when COMMENT_EXTENSION_LABEL
        bit_string += comment_extension_builder block
      end
    else
      raise "Error: Unknown block header: #{bits[0..7]}"
    end
  end
  File.open(new_file_name, 'wb') do |out|
    out.write [bit_string].pack("B*")
  end
end