Prawn pdf 2 and Rmagick - ruby-on-rails

i've got trouble for croping a picture with Rmagick and then display with Prawn
Here is the code :
First a method to instantiate the image with RMagick :
def build_magick_image(path)
if path.instance_of?(StringIO)
Magick::Image.from_blob(path.read)
else
Magick::Image.read(path)
end.first
end
In my case i have an instance of StringIO.
Then i crop the picture :
img = build_magick_image(picture_path)
cropped_img = img.resize_to_fill(1735, 1560)
But now i can't find how to display it in my Prawn pdf.
My last try is :
pdf.image cropped_img, at: [image_x, image_y], height: image_height.mm , width: inner_page_width.mm
But obviously it doesn't work.
Can someone help me?
Thanks :)

I found your question when I was trying to figure out the same thing 😬 Here's the solution I came up with:
Wrap your image blob in a StringIO object, which will give Prawn the interface it needs. In your specific case:
cropped_img_sio = StringIO.open(cropped_img.to_blob)
pdf.image cropped_img_sio, at: [image_x, image_y], height: image_height.mm, width: inner_page_width.mm

Related

Rails 6 Axlsx Excel Gem - Images not displaying

I don't know if it's my fault or if it just doesn't work with Rails 6, but my images in the file are not displaying:
I tried:
img = File.expand_path(Rails.root+'app/assets/images/logo.jpg')
and also like described in the examples:
img = File.expand_path('../logo.jpg', __FILE__)
sheet.add_image(:image_src => img, :noSelect => true, :noMove => true) do |image|
image.start_at 5, 20
image.end_at 7, 22
end
The image is found (at least I don't get an error for this) but the only thing I see in the generated file (the rest of the creation works fine) is:
Could it be the image size not fitting in the cells? Or is it resizing automatically?
Any suggestions or ideas? I don't know what's wrong or what else I could try
Did you try setting height and width for the image? Have a look at this old answer https://stackoverflow.com/a/47982814/1796645 (potential duplicate question)
If you found a bug, then you could report it in https://github.com/caxlsx/caxlsx/issues

How can I display a svg in prawn without saving a .svg file before?

For this moment, I generate a svg file and then I read it and I display it in my pdf:
qr = Barby::QrCode.new('test')
outputter = Barby::CairoOutputter.new(qr).to_svg
File.open('myfile.svg', 'wb'){|f| f.write outputter }
pdf.svg IO.read('myfile.svg'), width: 50, height: 50
My question is: how can I display my svg without saving a .svg file before. I know there is a css property that allow that but I can't use css with prawn...
Any ideas?
It's working like that:
pdf.svg outputter, width: 50, height: 50
thanks #Mark Thomas

Get image dimensions using Refile

Using the Refile gem to handle file uploading in Rails, what is the best way to determine image height and width during / after it has been uploaded? There is no built in support for this AFAIK, and I can't figure out how to do it using MiniMagick.
#russellb's comment almost got me there, but wasn't quite correct. If you have a Refile::File called #file, you need to:
fileIO = #file.to_io.to_io
mm = MiniMagick::Image.open(fileIO)
mm.width # image width
mm.height # image height
Yes, that's two calls to #to_io >...< The first to_io gives you a Tempfile, which isn't what MiniMagick wants. Hope this helps someone!
-- update --
Additional wrinkle: this will fail if the file is very small (<~20kb, from: ruby-forum.com/topic/106583) because you won't get a tempfile from to_io, but a StringIO. You need to fork your code if you get a StringIO and do:
mm = MiniMagick::Image.read(fileio.read)
So my full code is now:
# usually this is a Tempfile; but if the image is small, it will be
# a StringIO instead >:[
fileio = file.to_io
if fileio.is_a?(StringIO)
mm = MiniMagick::Image.read(fileio.read)
else
file = fileio.to_io
mm = MiniMagick::Image.open(file)
end
Refile attachments have a to_io method (see Refile::File docs) which returns an IO object that you can pass to MiniMagick.
Assuming you have an Image model with a file attachment (id stored in a file_id string column) and width and height columns you can use the following callback:
class Image < ActiveRecord::Base
attachment :file
before_save :set_dimensions, if: :file_id_changed?
def set_dimensions
image = MiniMagick::Image.open(file.to_io)
self.width = image.width
self.height = image.height
end
end
Hope that helps.
You can use MiniMagick to do this (but need to be using the latest version).
image = MiniMagick::Image.open('my_image.jpg')
image.height #=> 300
image.width #=> 1300
This is all pretty well documented in the README.md for the gem: https://github.com/minimagick/minimagick

How to get uploaded image file size?

This is the problem. I am using Carrierwave to upload my images and now I am trying to get file size in KB for each version of my uploaded image. I've tried this but it gives me a wrong file size:
if #file
img = ::Magick::Image::read(#file.file).first
size = img.to_blob.size
end
If I remove to_blob and try only with img.size, I receive error that size is not a defined method. Is there a way to get an image size in Carrierwave uploader while uploading file? Thanks all :)
The Carrierwave wiki has a recipe for how to implement this:
https://github.com/carrierwaveuploader/carrierwave/wiki/How-to:-Store-the-uploaded-file-size-and-content-type

Ruby, RSVG and PNG streams

I'm trying to do an image conversion in a rails app from SVG to PNG. ImageMagick didn't work out for me, due to Heroku not able / wanting to upgrade IM at this time. I'm testing out some ideas of using RSVG2 / Cairo in dev but running into a roadblock.
I can easily convert and save the SVG to PNG like this:
#svg_test.rb
require 'debugger'
require 'rubygems'
require 'rsvg2'
SRC = 'test.svg'
DST = 'test.png'
svg = RSVG::Handle.new_from_file(SRC)
surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, 800, 800)
context = Cairo::Context.new(surface)
context.render_rsvg_handle(svg)
surface.write_to_png(DST)
But this only lets me write PNG files out. In the app, I need to be able to generate these on the fly, then send them down to the client browser as data. And I can't figure out how to do this, or even if its supported. I know I can call surface.data to get the raw data at least, but I don't know enough about image formats to know how to get this as a PNG.
Thanks
Ah ha! I was so close and its pretty obvious in hindsight. Simply call the surface.write_to_png function with a StringIO object. This fills the string object, which you can then get the bytes for. Here's the finished svg_to_png function I wrote, along with a sample controller that calls it. Hope this helps someone else somewhere.
ImageConvert function:
def self.svg_to_png(svg)
svg = RSVG::Handle.new_from_data(svg)
surface = Cairo::ImageSurface.new(Cairo::FORMAT_ARGB32, 800, 800)
context = Cairo::Context.new(surface)
context.render_rsvg_handle(svg)
b = StringIO.new
surface.write_to_png(b)
return b.string
end
Test controller:
def svg_img
path = File.expand_path('../../../public/images/test.svg', __FILE__)
f = File.open(path, 'r')
t = ImageConvert.svg_to_png(f.read)
send_data(t , :filename => 'test.png', :type=>'image/png')
end

Resources