class HexaPDF::ImageLoader::PNG

def separate_alpha_channel(offset, decode_parms)

is not very fast but gets the job done as fast as possible in plain Ruby.
Since we need to decompress the PNG chunks and extract the color/alpha bytes this method

alpha data, both deflate encoded with predictor.
Separates the color data from the alpha data and returns an array containing the image and
def separate_alpha_channel(offset, decode_parms)
  bytes_per_colors = (decode_parms[:BitsPerComponent] * decode_parms[:Colors] + 7) / 8
  bytes_per_alpha = (decode_parms[:BitsPerComponent] + 7) / 8
  bytes_per_row = (decode_parms[:Columns] * decode_parms[:BitsPerComponent] *
    (decode_parms[:Colors] + 1) + 7) / 8 + 1
  image_data = ''.b
  mask_data = ''.b
  flate_decode = @document.config.constantize('filter.map', :FlateDecode)
  source = flate_decode.decoder(Fiber.new(&image_data_proc(offset)))
  data = ''.b
  while source.alive? && (new_data = source.resume)
    data << new_data
    while data.length >= bytes_per_row
      i = 1
      image_data << data.getbyte(0)
      mask_data << data.getbyte(0)
      while i < bytes_per_row
        bytes_per_colors.times {|j| image_data << data.getbyte(i + j) }
        i += bytes_per_colors
        bytes_per_alpha.times {|j| mask_data << data.getbyte(i + j) }
        i += bytes_per_alpha
      end
      data = data[bytes_per_row..-1]
    end
  end
  image_data = Filter.string_from_source(flate_decode.encoder(Fiber.new { image_data }))
  mask_data = Filter.string_from_source(flate_decode.encoder(Fiber.new { mask_data }))
  [image_data, mask_data]
end