Rails 6 Axlsx Excel Gem - Images not displaying - ruby-on-rails

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

Related

Ruby on Rails - How to convert to images some elements from a word document

Context
In our platform we allow users to upload word documents, those documents are stored in google drive and then dowloaded again to our platform in HTML format to create a section where the users can interact with that content.
Rails 5.0.7
Ruby 2.5.7p206
selenium-webdriver 3.142.7 (latest stable version compatible with our ruby and rails versions)
Problem
Some of the documents have charts or graphics inside that are not processed correctly giving wrong results after all the process.
We have been trying to fix this problem at the moment we get the word document and before to send it to google drive.
I'm looking for a simple way to export the entire chart and/or table as an image, if anyone knows of a way to do this the advice would be much appreciated.
Edit 1: Adding some screenshots:
This screenshot is from the original word doc:
And this is how it looks in our systems:
Here are the approaches I have tried that haven't worked for me so far.
Approach 1
Using nokogiri to read the document and found the nodes that contain the charts (we've found that they are called drawing) and then use Selenium to navigate through the file and take and screenshot of that particular section.
The problem we found with this approach is that the versions our gems are not compatible with the latest versions of selenium and its web drivers (chrome or firefox) and it is not posible to perform this action.
Other problem, and it seems is due to security, is that selenium is not able to browse inside local files and open it.
options = Selenium::WebDriver::Firefox::Options.new(binary: '/usr/bin/firefox', headless: true)
driver = Selenium::WebDriver.for :firefox, options: options
path = "#{Rails.root}/doc_file.docx"
driver.navigate.to("file://#{path}")
# Here occurs the first issue, it is not able to navigate to the file
puts "Title: #{driver.title}"
puts "URL: #{driver.current_url}"
# Below is the code that I am trying to use to replace the images with the modified images
drawing_elements = driver.find_elements(:css, 'w|drawing')
modified_paragraphs = []
drawing_elements.each do |drawing_element|
paragraph_element = drawing_element.find_element(:xpath, '..')
paragraph_element.screenshot.save('paragraph.png')
modified_paragraph = File.read('paragraph.png')
modified_paragraphs << modified_paragraph
end
driver.quit
file = File.open(File.join(Rails.root, 'doc_file.docx'))
doc = Nokogiri::XML(file)
drawing_elements = doc.css('w|drawing')
drawing_elements.each_with_index do |drawing_element, i|
paragraph_element = drawing_element.parent
paragraph_element.replace(modified_paragraphs[i])
end
new_doc_file = File.write('modified_doc.docx', doc.to_xml)
s3_client.put_object(bucket: bucket, key: #document_path, body: new_doc_file)
File.delete('doc_file.docx')
Approach 2
Using nokogiri to get the drawing elements and the try to convert it directly to an image using rmagick or mini_magick.
It is only possible if the drawing element actually contains an image, it can convert that correctly to an image, but the problem is when inside of the drawing element are not images but other elements like graphicData, pic, blipFill, blip. It needs to start looping into the element and rebuilding it, but at that point of time it seems that the element is malformed and it can't rebuild it.
Other issue with this approach is when it founds elements that seem to conform an svg file, it also needs to loop into all the elements and try to rebuild it, but the same as the above issue, it seems that the element is malformed.
response = s3_client.get_object(bucket: bucket, key: #document_path)
docx = response.body.read
Zip::File.open_buffer(docx) do |zip|
doc = zip.find_entry("word/document.xml")
doc_xml = doc.get_input_stream.read
doc = Nokogiri::XML(doc_xml)
drawing_elements = doc.xpath("//w:drawing")
drawing_elements.each do |drawing_element|
node = get_chil_by_name(drawing_element, "graphic")
if node.xpath("//a:graphicData/a:pic/a:blipFill/a:blip").any?
img_data = node.xpath("//a:graphicData/a:pic/a:blipFill/a:blip").first.attributes["r:embed"].value
img = Magick::Image.from_blob(img_data).first
img.write("node.jpeg")
node.replace("<img src='#{img.to_blob}'/>")
elsif node.xpath("//a:graphicData/a:svg").any?
svg_data = node.xpath("//a:graphicData/a:svg").to_s
Prawn::Document.generate("node.pdf") do |pdf|
pdf.svg svg_data, at: [0, pdf.cursor], width: pdf.bounds.width
end
else
puts "unsupported format"
end
end
# update the file in S3
s3.put_object(bucket: bucket, key: #document_path, body: doc)
end
Approach 3
Convert the elements since its parents to a pdf file and then to an image.
Basically the same issue as in the approach 2, it needs to loop inside all the elements and try to rebuild it, we haven't found a way to do that.

How to improve dpi/resolution pdfkit

Currently using pdfkit, for the most part it's been great to use.
The only issue is line thickness. Borders on the source html look great, on the pdf generated look much thicker.
Also thickness varies in the document. On lines of the same width, it appears thicker in places. Even borders on the same div may appear thicker on the 3 of the 4 borders, even though they have the same CSS.
Any way to remedy this?
Well if you explore the extended help -H on wkhtmltopdf you would find a options called dpi
So perhaps you can set a dpi in pdfkit something like this
PDFKit.configure do |config|
config.wkhtmltopdf = '/path/to/wkhtmltopdf'
config.default_options = {
:page_size => 'Legal',
:print_media_type => true,
:dpi => [your dpi setting]
}
# Use only if your external hostname is unavailable on the server.
config.root_url = "http://localhost"
end
Note
Having said that it you examine the help deeply you would know that that it states
-d, --dpi <dpi> Change the dpi explicitly (this has no
effect on X11 based systems)
I clearly state it has no effect on system that based on X11 so I would rather see that of any help for you
Other options
So dpi options is hardly of use what are other options ?
Well in fact there is one check this link and trace to last comment and see some of that help in your quest (i.e try increasing the resolution of the xvfb in case if your running an xvfb server)
Hope this help

RMagick, Tempfile, Paperclip: how to save a image file with large dimensions and small kbs as a thumbnail?

I have a Rails rake task that is processing a batch of images. It strips out the white background (using RMagick), replaces it with a transparent layer, writes it to a tempfile and then saves it as a PNG on Amazon S3 (using Paperclip).
It works for the bulk of the images. However, it runs into an error for at least 1 image. Can someone help me figure out why and how to fix it?
Code sample:
require 'RMagick'
require 'tempfile'
include Magick
task :task_name => :environment do
x = Item.find(128) # image 128 is the one giving me trouble
sourceImage = Image.read(x.image_link_hires)
processedImage = sourceImage[0].transparent("white")
tempImageFile = Tempfile.new(["processed_image",".png"])
processedImage.write("png:" + tempImageFile.path)
x.image_transparent = tempImageFile
x.save!
end
The error message:
rake aborted! Validation failed: Image transparent C:/Users/Roger/AppData/Local/Temp/processed_image20130107-8640-1ck71i820130107-8640-i6p91w.png is not recognized by the 'identify' command., Image transparent C:/Users/Roger/AppData/Local/Temp/processed_
image20130107-8640-1ck71i820130107-8640-i6p91w.png is not recognized by the 'identify' command.
This message appears upon running the last line (the save operation).
Tempfile problem with small files?
I think the error has something to do with Tempfile not actually writing a file to the temp path. This error may have to do with small filesize? The specific image that it's having trouble with has an usually amount of white space, so the resulting filesize after processing is about 30k for an 800x800 pixel image.
How can I verify if this is the case? And if it is, how can I work around it?
Other observations:
When I write the trouble image to a normal file (rather than Tempfile), it saves successfully locally.
The task works fine for other images, which tend to be much bigger (~1-2MB)
After processedImage.write, I've checked tempImageFile.size. It says that it's 30kb as expected.
When I observe the temp file directory when the rake task runs, I can see the temp files being created when the task is run other images successfully. The files seem to show up when processedImage.write runs. However, for the trouble image, I don't see temp files ever being created.
Thanks for any advice.
Update 7 Jan 2013
I've investigated this more. I reran #1 above, but attempted to save onto S3 with Paperclip. This generated the same error message.
So now I believe the issue is that this is a small file in terms of bytes (32kb), but with a decent height and width (800x800). Paperclip is trying to save a thumbnail version of it, which is 90x90. Typically this generates a filesize that is <1% the original, which I assume is the source of the errors.
If anyone has an elegant workaround / fix for this, I'd appreciate hearing about it.

Converting PDF to PNG with transparent background

We have a Ruby on Rails application that needs to convert a PDF into a PNG with a transparent background. We're using rmagick 2.13.1. On our development machines the following code works exactly how we want it.
pages = Magick::Image.from_blob(book.to_pdf.render){ self.density = 300 }
page = pages[0]
image_file = Tempfile.new(['preview_image', '.png'])
image_file.binmode
image_file.write( page.to_blob { |opt| opt.format = "PNG" } )
We thens save the image_file and all is peachy. When we deployed to a review server on Heroku, though, the generated image has a white background. It turns out that Heroku's cedar stack is using imagemagick ImageMagick 6.5.7-8 2010-12-02 where we're using ImageMagick 6.7.5-7 2012-05-08 on our development machines.
I've scoured the net for older posts that might apply to the older version to try and figure out how to generate the transparent PNGs. It's surely supported, but, so far I haven't been able to figure out the right combination of settings.
To verify that it wasn't the PDF generation that was the problem, I downloaded a PDF generated on Heroku and successfully converted it using the above code (slightly modified to read the file in instead of generate it) to a transparent PNG.
Some of the things I've tried in various combinations are:
page.matte = true
page.format = "PNG32"
page.background_color = "none"
page.transparent_color = "white"
page.transparent("white")
So, the question is "is this possible?". If so, which settings do I need to set on the image before writing it out?
I'm also investigating including a compiled binary of a more up to date Imagemagick on Heroku.
Any help is appreciated.
This should no longer be an issue, as Heroku has ImageMagick versions 6.7-6.9 on their various stacks.

Imagemagick with greyscale images and 24 bit depth

I am using the Imagick library to work with ImageMagick in PHP. I am first reading an (JPEG) image from an external server with:
$img = new Imagick();
$img->readImage($source);
And then upload it to my Amazon S3 bucket with the following code:
$s3 = new AmazonS3();
$s3->create_object(BUCKET, $destination_path, array(
'body' => $img->getImageBlob(),
'length' => $img->getImageSize(),
'acl' => AmazonS3::ACL_PUBLIC,
'contentType' => 'image/jpeg'
));
Everything seems to be working fine, the files appear in my storage bucket and I can view them in my browser. However, when handling greyscale images, ImageMagick converts the image from 24 bit depth to 8 bit depth. I would like them to keep their 24 bit depth, how could I achieve this? I've tried the following, without success:
$img->setImageType(imagick::IMGTYPE_TRUECOLOR);
For colorized images, everything works fine, images keep their 24 bit depth.
Edit:
It seems that ImageMagick changes the image type from 6 (truecolor) to 2 (greyscale). Trying to overwrite this does not work, as tested with the following code:
$img = new Imagick();
$img->readImage($source);
$img->setImageType(6);
echo $img->getImageType();
which outputs 2
Use setType() before you load the image. So:
$img = new Imagick();
$img->setType(6); //or use imagick::IMGTYPE_TRUECOLOR instead of 6
$img->loadImage($source);
This will output an image with truecolor, even if the loaded picture uses graycolors only.

Resources