gif2c: Better handling of 'transparent over last frame', 'transparent gif here'. Also frame delays are now included.

This commit is contained in:
Fabian Schlenz 2019-05-23 21:15:10 +02:00
parent 1a4873aed6
commit deb3a753c8

61
tools/gif2c.rb Normal file → Executable file
View File

@ -18,7 +18,9 @@ def compress(data, use_cutoff=true)
data.each do |x| data.each do |x|
if x == last if x == last
count += 1 count += 1
else end
if x!=last || count==255
if use_cutoff if use_cutoff
if count <= cutoff if count <= cutoff
count.times { result << last } count.times { result << last }
@ -57,9 +59,18 @@ image_file=ARGV[0]
name=ARGV[1] name=ARGV[1]
frames = Magick::ImageList.new(image_file) frames = Magick::ImageList.new(image_file)
puts "Found #{frames.count} frames." STDERR.puts "Found #{frames.count} frames."
print "Getting colors..." STDERR.puts "Getting delays..."
ticks_per_second = frames.ticks_per_second
times = [] ; frames.each{|f| times << (1000.0 / ticks_per_second * f.delay).round}
individual_frame_times = true
if times.uniq.count==1
individual_frame_times = false
times = times[0, 1]
end
STDERR.print "Getting colors..."
colors = [] colors = []
frames.each do |frame| frames.each do |frame|
frame.columns.times do |x| frame.columns.times do |x|
@ -71,22 +82,25 @@ frames.each do |frame|
end end
colors = colors.uniq colors = colors.uniq
puts " Found #{colors.count} colors." STDERR.puts " Found #{colors.count} colors."
transparent = colors.select{|c| c.end_with? "00"} transparent = colors.select{|c| c.end_with? "00"}
puts "#{transparent.count} color(s) being transparent." STDERR.puts "#{transparent.count} color(s) being transparent."
colors = (["#00000012", "#000000FF"] + (colors - transparent)).uniq # color[0] is "keep the color from the previous frame"
puts "Using #{colors.count} colors." # color[1] is "background color"
colors = (["#00000012", "#00000013"] + (colors - transparent)).uniq
STDERR.puts "Using #{colors.count} colors."
raise "Number of colors has to be 255 or less!" if colors.count>255 raise "Number of colors has to be 255 or less!" if colors.count>255
puts STDERR.puts
puts puts
puts "uint32_t #{name}_colors[] = {#{colors.map{|c| "0x" + c[1, 6]}.join(", ")}};" puts "uint32_t #{name}_colors[] = {#{colors.map{|c| "0x" + c[1, 6]}.join(", ")}};"
p_frame = nil p_frame = nil
frames_data = [] frames_data = []
times = []
frames.each_with_index do |frame, index| frames.each_with_index do |frame, index|
data = [] data = []
if index==0 # first frame if index==0 # first frame
@ -94,7 +108,7 @@ frames.each_with_index do |frame, index|
frame.columns.times do |x| frame.columns.times do |x|
color = frame.pixel_color(x, y).to_color(Magick::AllCompliance, true, 8, true) color = frame.pixel_color(x, y).to_color(Magick::AllCompliance, true, 8, true)
if transparent.include? color if transparent.include? color
data << 0 data << 1
else else
data << colors.index(color) data << colors.index(color)
end end
@ -116,23 +130,32 @@ frames.each_with_index do |frame, index|
end end
end end
end end
frames_data << data time = (1000.0 / ticks_per_second * frame.delay).round
if frame==0 || data.uniq!=[0]
times << time
frames_data << data
else
old_time = times.pop
times << old_time + time
end
p_frame = frame p_frame = frame
end end
data = frames_data.map{|d| compress(d, true)} data = frames_data.map{|d| compress(d, true)}
puts "uint8_t #{name}_data[] = {\n #{data.map{|d| d.join(",")}.join(",\n ")}\n};" puts "uint8_t #{name}_data[] = {\n #{data.map{|d| d.join(",")}.join(",\n ")}\n};"
puts "uint16_t #{name}_delays[] = {#{times.join(",")}};"
s=0 s=0
puts "uint16_t #{name}_offsets[] = {#{(data.map{|d| t=s; s+=d.count; t} + [s]).join(",")}};" puts "uint16_t #{name}_offsets[] = {#{(data.map{|d| t=s; s+=d.count; t} + [s]).join(",")}};"
puts "AnimationData #{name} = {&#{name}_colors[0], &#{name}_data[0], &#{name}_offsets[0], #{colors.count}, #{frames_data.count}, 16, 16};" puts "AnimationData #{name} = {&#{name}_colors[0], &#{name}_data[0], &#{name}_offsets[0], &#{name}_delays[0], #{individual_frame_times}, #{colors.count}, #{frames_data.count}, #{frames.first.columns}, #{frames.first.rows}};"
puts puts
puts STDERR.puts
puts "Space usage:" STDERR.puts "Space usage:"
puts " Colors: %6d bytes." % [s1=colors.count * 3] STDERR.puts " Colors: %6d bytes." % [s1=colors.count * 4] # colors are 3-bytes, but we have to use uint32_t, which takes up 4 bytes.
puts " Data: %6d bytes." % [s2=data.flatten.count] STDERR.puts " Data: %6d bytes." % [s2=data.flatten.count]
puts " Offsets: %6d bytes." % [s3=data.count * 2] STDERR.puts " Delays: %6d bytes." % [s5=times.count * 3 + 1]
puts " TOTAL: %6d bytes." % [s1+s2+s3] STDERR.puts " Offsets: %6d bytes." % [s3=data.count * 2]
puts "Original size: %6d bytes." % [s4=File.new(image_file).size] STDERR.puts " TOTAL: %6d bytes." % [s1+s2+s3+s5]
puts "Difference: %6d bytes." % [s1+s2+s3 - s4] STDERR.puts "Original size: %6d bytes." % [s4=File.new(image_file).size]
STDERR.puts "Difference: %6d bytes." % [s1+s2+s3+s5 - s4]