Skip to content

Instantly share code, notes, and snippets.

@Olathe
Last active December 19, 2015 00:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Olathe/5868725 to your computer and use it in GitHub Desktop.
Save Olathe/5868725 to your computer and use it in GitHub Desktop.
Linux PNGOUT script generator
#!/usr/bin/env ruby
require 'open3'
require 'tempfile'
ThreadCount = 2
Infinity = 1.0/0.0
Filenames = Dir['**/favicon.ico', '**/*.png'].map! { |filename| File.expand_path filename }
BestSizes = Hash.new { |h, filename| h[filename] = [Infinity, nil] }
def pngout args
args_old = args
args = args.dup
filename = args[1]
if File.extname(filename) == '.png'
temp_file = nil
else
temp_file = Tempfile.new(['pngout-needs-png-extension-', '.png'])
temp_file.close
FileUtils.cp filename, temp_file.path
args[1] = temp_file.path
end
exit_code = 1
while exit_code == 1
output, status = Open3.capture2e *args
exit_code = (output =~ /unsupported format/) ? 3 : status.exitstatus
end
unless temp_file.nil?
FileUtils.cp temp_file.path, filename if exit_code == 0
temp_file.unlink
end
if exit_code == 3
nil
else
Integer(output.scan(/Out:\s*(\d+)/m).last.first)
end
end
def process_file filename
puts "[#{ Time.now }] Starting to process #{ filename }"
args = ['pngout', filename, '-v', '-y', '-kt', '-k0']
[0, 2, 3, 4, 6].each do |c|
args << "-c#{ c }"
# Only continue trying this color type if it can work
unless pngout(args + ['-f0', '-s4', '-n1']).nil?
(((c == 0) or (c == 3)) ? [1, 2, 4, 8] : [nil]).each do |d|
args << "-d#{ d }" unless d.nil?
# Only continue trying this bit depth if it can work
if d.nil? or not pngout(args + ['-f0', '-s4', '-n1']).nil?
[0, 1, 2, 3, 4, 5].each do |f|
args << "-f#{ f }"
(f == 0 ? [0, 4] : [0]).each do |s|
args << "-s#{ s }"
# Try uncompressed once: some really small files do better.
if s == 4
args << '-n1'
pngout args
args.pop
else
best_size = Infinity
best_n = 1
n = 1
while n <= best_n + 3
args << "-n#{ n }"
size = pngout args
unless size.nil?
if size <= best_size
best_size = size
best_n = n
end
BestSizes[filename] = [size, args.dup] if size < BestSizes[filename].first
end
n += 1
args.pop
end
end
args.pop
end
args.pop
end
end
args.pop unless d.nil?
end
end
args.pop
end
size, args = BestSizes[filename]
if size == Infinity
puts "[#{ Time.now }] Cannot handle #{ filename }"
else
puts "[#{ Time.now }] Best: #{ size } bytes with #{ args.first } \"#{ filename }\" #{ args[2..-1].join(' ') }"
# Try the other -s settings once just in case they are smaller
(1..3).each { |temp_s| pngout(args[0..-3] + ["-s#{ temp_s }", args.last]) }
end
end
Array.new(ThreadCount) do
Thread.new do
filename = Filenames.shift
until filename.nil?
process_file filename
filename = Filenames.shift
end
end
end.each { |thr| thr.join }
File.open('compress-all', 'wb') do |script|
script.chmod(0755)
script.puts <<"END"
#!/usr/bin/env ruby
require 'open3'
require 'tempfile'
ThreadCount = #{ ThreadCount }
Args = [
END
BestSizes.keys.sort.each do |filename|
size, args = BestSizes[filename]
script.puts " #{ (args + ['-r']).inspect }," unless size == Infinity
end
script.puts <<'END'
]
FileCount = Args.length
FileSizes = Hash.new { |h, filename| h[filename] = File.size filename }
def pngout args
args = args.dup
filename = args[1]
if File.extname(filename) == '.png'
temp_file = nil
else
temp_file = Tempfile.new(['pngout-needs-png-extension-', '.png'])
temp_file.close
FileUtils.cp filename, temp_file.path
args[1] = temp_file.path
end
exit_code = 1
while exit_code == 1
output, status = Open3.capture2e *args
exit_code = (output =~ /unsupported format/) ? 3 : status.exitstatus
end
unless temp_file.nil?
FileUtils.cp temp_file.path, filename if exit_code == 0
temp_file.unlink
end
if exit_code == 3
nil
else
Integer(output.scan(/Out:\s*(\d+)/m).last.first)
end
end
Array.new(ThreadCount) do
Thread.new do
loop do
Args.shuffle.each do |args|
filename = args[1]
old_size = FileSizes[filename]
new_size = pngout args
if old_size > new_size
puts "[#{ Time.now }] #{ old_size } => #{ new_size } (#{ filename })"
FileSizes[filename] = new_size
end
end
end
end
end.each { |thr| thr.join }
END
end
puts "[#{ Time.now }] ./compress-all generated!"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment