class AppInfo::PngUncrush
Public Class Methods
decompress(input, output)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 63 def self.decompress(input, output) new(input).decompress(output) end
dimensions(input)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 67 def self.dimensions(input) new(input).dimensions end
new(filename)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 71 def initialize(filename) @io = PngReader.new(File.open(filename)) raise FormatError, 'not a png file' unless @io.png? end
Public Instance Methods
decompress(output)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 80 def decompress(output) content = _remap(_dump_sections) return false unless content write_file(output, content) rescue Zlib::DataError # perhops thi is a normal png image file false end
dimensions()
click to toggle source
# File lib/app_info/png_uncrush.rb, line 76 def dimensions _dump_sections(dimensions: true) end
Private Instance Methods
_dump_sections(dimensions: false)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 92 def _dump_sections(dimensions: false) pos = @io.header.size optimized = false [].tap do |sections| while pos < @io.size type = @io[pos + 4, 4] length = @io[pos, 4].unpack1('N') data = @io[pos + 8, length] crc = @io[pos + 8 + length, 4].unpack1('N') pos += length + 12 if type == 'CgBI' optimized = true next end if type == 'IHDR' width = data[0, 4].unpack1('N') height = data[4, 4].unpack1('N') return [width, height] if dimensions end break if type == 'IEND' if type == 'IDAT' && sections&.last&.first == 'IDAT' # Append to the previous IDAT sections.last[1] += length sections.last[2] += data else sections << [type, length, data, crc, width, height] end end end end
_remap(sections)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 132 def _remap(sections) new_png = String.new(@io.header) sections.map do |(type, length, data, crc, width, height)| if type == 'IDAT' buff_size = width * height * 4 + height data = inflate(data[0, buff_size]) # duplicate the content of old data at first to avoid creating too many string objects newdata = String.new(data) pos = 0 (0...height).each do |_| newdata[pos] = data[pos, 1] pos += 1 (0...width).each do |_| newdata[pos + 0] = data[pos + 2, 1] newdata[pos + 1] = data[pos + 1, 1] newdata[pos + 2] = data[pos + 0, 1] newdata[pos + 3] = data[pos + 3, 1] pos += 4 end end data = deflate(newdata) length = data.length crc = Zlib.crc32(type) crc = Zlib.crc32(data, crc) crc = (crc + 0x100000000) % 0x100000000 end new_png += [length].pack('N') + type + (data if length.positive?) + [crc].pack('N') end new_png end
deflate(data)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 176 def deflate(data) Zlib::Deflate.deflate(data) end
inflate(data)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 167 def inflate(data) # make zlib not check the header zstream = Zlib::Inflate.new(-Zlib::MAX_WBITS) buf = zstream.inflate(data) zstream.finish zstream.close buf end
write_file(path, content)
click to toggle source
# File lib/app_info/png_uncrush.rb, line 127 def write_file(path, content) File.write(path, content, encoding: Encoding::BINARY) true end