class Object
Public Instance Methods
writeGIF(**_kwargs) { |lambda| ... }
click to toggle source
TODO do not store first frame – use background color
this would help with add[diff:...] for the first frame
# File lib/simple_gif/size.rb, line 5 def writeGIF **_kwargs kwargs = {filename: "temp.gif", background: [255,255,255]}.merge _kwargs file = File.open kwargs[:filename], "wb:ASCII-8BIT" current = history = width = height = nil yield lambda{ |frame| width, height = frame.is_a?(Array) ? [frame.first.size, frame.size] : [kwargs[:width], kwargs[:height]] history, current = [], Array.new(width * height, kwargs[:background]) unless history step = {} if frame.is_a? Array current = frame.flatten(1).zip(current).map.with_index{ |(color, cur), i| step[i] = color if cur != color color } else for (i, j), color in frame k = i * width + j step[k] = current[k] = color if current[k] != color end end history << step unless step.empty? # p history.size } ensure file.write "GIF89a" # Logical Screen Descriptor file.write [width, height].pack "SS" file.write "\xF7\x00\x00" # Global Color Table color_table = history.flat_map(&:values).uniq raise "sorry, can't have more than 255 colors" if color_table.size > 255 color_table[255] = [([*0..255].reverse - color_table.map(&:first))[0]] * 3 color_table.each{ |i| file.write (i || [255,255,255]).pack "CCC" } # Comment Extension block file.write "\x21\xFE\x1F" file.write "SimpleGIF (c) Nakilon@gmail.com" file.write "\x00" # Application Extension block file.write "\x21\xFF\x0B" file.write "NETSCAPE2.0" file.write "\x03\x01\x00\x00\x00" for step in history#.drop 1 ### Graphic Control Extension file.write "\x21\xF9\x04\x01" file.write [100/(kwargs[:fps] || 2)].pack "S" file.write "\xFF\x00" left, right = step.map{ |k,| k % width }.minmax top, bottom = step.map{ |k,| k / width }.minmax # Image Descriptor file.write "\x2C" file.write [left, top, right-left+1, bottom-top+1].pack "S*" file.write "\x00" # Image Data file.write "\x08" indices = Array.new((right-left+1) * (bottom-top+1), 255) step.each{ |k,v| indices[ k - width*top - left - \ (left + width - right - 1)*(k/width - top) ] = color_table.index v } result = [] table = (0..257).zip tree = (0..257).map{[]} s = [] indices.zip do |b| sb = s + b next s = sb if sb.inject(tree){ |t,i| t && t[i] } result << [table.index(s), (table.size - 1).to_s(2).size] table << sb sb.inject(tree){ |i,j| i[j] ||= [] } s = b end x = [[256, 9], *result, table.index(s), 257]. map{ |i, bs| "%0#{bs || result.last.last}b" % i }. reverse.join.reverse. scan(/.{1,8}/).map{ |i| i.reverse.to_i 2 } begin chunk = x[0,255] file.write [chunk.size, *chunk].pack "C*" end while x = x[255..-1] file.write "\x00" end file.write "\x3B" file.close `open -a "/Applications/Google Chrome.app" '#{kwargs[:filename]}'` \ if kwargs[:open] end