2

I'm struggling to attach a Vips:Image object to an ActiveStorage object.

I use Vips to compress a PNG image. I'm then looking to save this compressed PNG version into a second ActiveStorage attachment. The code is failing when attempting to attach. All I get is: Process finished with exit code -1073741819 (0xC0000005)

# compress the image and save the compressed version of the file as a PNG
# both img and img_to_compress are active storage attachments
def compress_charlie(img, img_to_compress)

  # load the image as a Vips Image object
  vips_img = Vips::Image.new_from_buffer (URI.open(img.url) { |f| f.read }), ''

  # do compression, etc ... not bothering to show this code as it has no impact on the issue I have

  # save the compressed png
  img_to_compress.attach(
    io: StringIO.new(vips_img .write_to_buffer('.png')),
    filename: img.filename
  )

end

Any help is appreciated, Charlie

Ruby 3.1 Rails 7.0.1

1 Answers1

1

You're decompressing and recompressing twice. How about (untested):

def convert_to_png(img, img_to_compress)
  # load the image as a Vips Image object
  vips_img = Vips::Image.new_from_buffer (URI.open(img.url) { |f| f.read }), ''

  # save as a PNG string
  png = StringIO.new(vips_img.write_to_buffer('.png')),

  img_to_compress.attach(io: png, filename: img.filename)
end

pngsave_buffer gives you a String with binary encoding, you don't need to save a second time. Try this test program:

require "vips"

x = Vips::Image.new_from_file ARGV[0]
y = x.pngsave_buffer

puts "y.class = #{y.class}"

I see:

$ ./pngsave.rb ~/pics/k2.jpg
y.class = String

If the image is already a PNG you'll be wasting a lot of time, of course. You could add something to detect the format and skip the conversion.

jcupitt
  • 10,213
  • 2
  • 23
  • 39
  • Thank you for the response. I edited the above code to remove the compression logic - the logic here is far from being finalized and not optimal :) I tried your convert method and same error: Process finished with exit code -1073741819 (0xC0000005) – Charlie Prezzano Jan 22 '22 at 18:27
  • I pushed the code out of DEV and into TEST, and it looks like it is working ... curious if the issue is my environment ... and it looks like it is. – Charlie Prezzano Jan 22 '22 at 18:39
  • That's weird. Does that tiny test prog work in your dev environment? Might be worth checking if you have a very old libvips, or one that's been built with some important stuff missing. – jcupitt Jan 22 '22 at 18:47
  • I cannot get any 'attach' action to work in my Dev Env (RunyMine on Windows). I know this code worked at some point in time - I've upgraded to Ruby 3.1, Rails 7.01 in the past month. 0xC0000005 is the error code for an Access Violation exception. Windows throws that exception when code tries to access invalid memory. Perhaps it was a Windows update that triggered this? To note I am having the issue on Windows 10 and Windows 11. Good times. – Charlie Prezzano Jan 22 '22 at 21:29
  • I'll update my progress here in case anyone has the same issue and stumbles up on this ... reverting back active_storage.variant_processor to mini_magick fixes the error. Looks like my local installation of Vips is the issue. – Charlie Prezzano Jan 22 '22 at 21:47
  • Unsure why, but Rails.application.config.active_storage.track_variants = false is correcting some of the issues I am having. I'm still struggling and using Rails v7.1.0.alpha is getting me past a few remaining issues, but not all. I'm giving up and going back to MiniMagick. I'll take another look at vips in a few months. – Charlie Prezzano Jan 24 '22 at 16:00
  • The root issue is Ruby 3.1.0 ... switching to 3.0.3 fixes it. To note, I found an issue with MiniMagick too. I received a permission denied error message when deleting a temp file. – Charlie Prezzano Jan 24 '22 at 18:39