Monday, January 09, 2017

CarrierWave and Prawn: how to blacklist png images with Adam7 interlacing

The Ruby on Rails Prawn pdf library does not support rendering of png images with Adam7 interlacing. So you have a few options. One is to convert the image into a format acceptable to Prawn. The other is to blacklist that kind of png. The CarrierWave file uploader library is fairly popular.
 class CustomUploader < CarrierWave::Uploader::Base  
 ...  
 before :cache, :invalidate_adam7  
 ...  
  # See https://github.com/prawnpdf/prawn/blob/ec9531b6eb0a61cfed0748a395679f053a2d62cd/lib/prawn/images/png.rb   
  # and https://github.com/carrierwaveuploader/carrierwave/blob/master/lib/carrierwave/uploader/content_type_blacklist.rb  
  # we invalidate png with interlace method Adam7 as it raises an error in pdf generation via Prawn  
  def invalidate_adam7(new_file)  
   content_type = new_file.content_type  
   return unless content_type == 'image/png'  
   strio = StringIO.new(new_file.read)  
   # set the strio to the start  
   strio.rewind  
   strio.read(8)  
   loop do  
    break if strio.eof?   
    chunk_size = strio.read(4).unpack("N")[0]  
    section = strio.read(4)  
    case section  
    when 'IHDR'  
     values = strio.read(chunk_size).unpack("NNCCCCC")  
     @interlace_method = values[6]  
    when 'IEND'  
     break  
    else  
     strio.seek(strio.pos + chunk_size)  
    end  
   end  
   strio.read(4)  
   if @interlace_method != 0  
    raise CarrierWave::IntegrityError, I18n.translate(:"carrierwave.errors.messages.adam7_error")  
   end  
  end  
 end