Converting PDF to PNG with transparent background - ruby-on-rails

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.

Related

"No such file or directory" error on cropped ImageMagick image

I have a function in a DelayedJobs-run background process on my Rails app that receives Base64 image blobs, resizes and crops them, and then saves them:
image64 = Base64.decode64(screenshot)
image = MiniMagick::Image.read(image64)
image.resize "#{image.width * 0.5}x#{image.height * 0.5}"
image.crop("#{image.width}x250") if ("#{image.height}".to_i > 250)
Base64.encode64(image.to_blob)
The addition of the .crop call, however, stops this process working my production CentOS Linux server, resulting in this error from the .to_blob call:
Errno::ENOENT: No such file or directory # rb_sysopen - /tmp/mini_magick20170228-1709-t2rcyo
/path/app/vendor/bundle/ruby/2.4.0/gems/mini_magick-4.6.1/lib/mini_magick/image.rb:175:in `binread'
/path/app/vendor/bundle/ruby/2.4.0/gems/mini_magick-4.6.1/lib/mini_magick/image.rb:175:in `to_blob'
Without cropping, the function works. Running this in the foreground (i.e. in rails console) does not cause an issue.
Updating ImageMagick, ensuring /usr/bin is in PATH and sim-linking identify did not work (per this).
Any help is appreciated.
Per #mmichael, this question / answer shifted the problem. Specifically, changing
image.crop("#{image.width}x250")
to
image.crop("#{image.width}x250+0+0")
allows the .to_blob to happen without issue.
If anyone can explain the issue as to why this happens when run in the background only, I'll gladly accept your answer instead.

Extracting images from video in JRuby-1.7.13

I want to extract images from a m4v video sent from mobile to my rails server. These images will be later used for face recognization purposes. There is a gem called "streamio-ffmpeg" that does this job nicely and easily but the problem is that it does not support JRuby-1.7.13 that I am currently using on my server. It's a big application and upgrading the JRuby version not desirable at this moment.
Can someone please suggest JRuby1.7.13 compatible alternative solutions/gems to extract the images from a video file?
From the sourcecode, it looks like streamio-ffmpeg outputs the underlying command by default :
FFMPEG.logger.info("Running transcoding...\n#{command}\n")
So all you have to do is execute :
movie.screenshot("screenshot_%d.jpg", { vframes: 50, frame_rate: '6/2' }, validate: false)
on a system where streamio-ffmpeg is installed.
You look at the output, extract the command, and use it somewhere else with :
system("ffmpeg arguments_you_extracted_from_the_logs")
without having to install streamio-ffmpeg.

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.

ABCPDF Font Printing Layout - Machine Dependent

I am using ABCPDF to print a PDF file to a local printer via EMF file. I've based this very closely on ABC PDF's sample "ABCPDFView" project. My application worked fine on my Windows 7 and Windows XP dev boxes, but when I moved to a Windows 2003 test box, simple embedded fonts (like Times New Roman 12) rendered completely wrong (wrong spot, and short and squat, almost like the DPI's were crazily wrong).
Note that I've hardcoded the DPI to 240 here b/c I'm using a weird mainframe print driver that forces 240x240. I can discount that driver as the culprit as, if I save the EMF file locally during print, it shows the same layout problems. If I render to PNG or TIFF files, this looks just fine on all my servers using this same code (put .png in place of .emf). Finally, if I use the ABCPDFView project to manually add in a random text box to my PDF, that text also renders wrong in the EMF file. (Side note, if I print the PDF using Acrobat, the text renders just fine)
Update: I left out a useful point for anyone else having this problem. I can work around the problem by setting RenderTextAsText to "0" (see code below). This forces ABCPDF to render the text as polygons and makes the problem go away. This isn't a great solution though, as it greatly increases the size of my EMF files, and those polygons don't render nearly as cleanly in my final print document.
Anyone have any thoughts on the causes of this weird font problem?
private void DoPrintPage(object sender, PrintPageEventArgs e)
{
using (Graphics g = e.Graphics)
{
//... omitted code to determine the rect, used straight from ABC PDF sample
mDoc.Rendering.DotsPerInch = 240 ;
mDoc.Rendering.ColorSpace = "RGB";
mDoc.Rendering.BitsPerChannel = 8;
mDoc.SetInfo(0, "RenderTextAsText", "0");//the magic is right here
byte[] theData = mDoc.Rendering.GetData(".emf");
using (MemoryStream theStream = new MemoryStream(theData))
{
using (Metafile theEMF = new Metafile(theStream))
{
g.DrawImage(theEMF, theRect);
}
}
//... omitted code to move to the next page
}
Try upgrading to the new version of abcpdf 8, it has its own rendering engine based on Gecko and so you can bypass issues like this when abcpdf is using the inbuilt server version of IE for rendering.
I was originally RDPing in with 1920x1080 resolution, by switching to 1024x768 res for RDP, the problem went away. My main program runs as a service, and starting this service from an RDP session w/ 1024x768 fixes it.
I have an email out w/ ABC PDF to see if they can explain this and offer a more elegant solution, but for now this works.
Please note that this is ABC PDF 7, I have no idea if this issue applies to other versions.
Update: ABC PDF support confirmed that its possible the service is caching the display resolution from the person that started the process. They confirmed that they've seen some other weird issues with Remote Desktop and encouraged me to use this 1024x768 workaround and/or start the service remotely.

Where do the temp files go when using MiniMagick in a Ruby on Rails app?

I'm using MiniMagick to perform some image resizing on images uploaded through a multi-part form. I need to generate a few different types of images from the originally uploaded file. Here's the code that's performing the image processing:
// Generates a thumbnail image
mm = MiniMagick::Image.open(Rails.root.join('public', 'uploads', new_url))
mm.resize(thumbnail_dimensions.join("x"))
mm.write(Rails.root.join('public', 'uploads', "t_"+new_url))
// Generates cropped version
mm_copy = MiniMagick::Image.open(Rails.root.join('public', 'uploads', new_url))
mm_copy.crop('200x200')
mm_copy.write(Rails.root.join('public', 'uploads', "c_"+new_url))
new_url is the path to the image in the public folder. The thumbnail routine works perfectly. When the app goes to start processing the cropped version, that is where things start breaking and I can't for the life of me figure it out. I receive the following error when from this code:
No such file or directory - /tmp/mini_magick20110627-10055-2dimyl-0.jpg
I read some stuff about possible race conditions with the garbage collector in Rails but I wasn't able to resolve the issue. I tried this from the console as well and can create MiniMagick instances but receive the No such file error there as well. At this point, I have no idea where to go so I'm hoping someone here has some helpful suggestions. Thanks for your help!
Details:
OS: Ubuntu (Lucid Lynx)
Rails Version: 3.0.7
Ruby Version: 1.8.7
MiniMagick Version: 3.3
Did you installed ImageMagick?
If not,
try sudo apt-get install ImageMagick,
and then restart your webrick server
it's probably the race condition which is mentioned here:
https://ar-code.lighthouseapp.com/projects/35/tickets/6-race-condition-with-temp_file
here's one fix:
http://rubyforge.org/tracker/index.php?func=detail&aid=9417&group_id=1358&atid=5365
alternatively, and probably easier, you could try this:
// Generates a thumbnail image
mm = MiniMagick::Image.open(Rails.root.join('public', 'uploads', new_url))
mm_copy = mm.clone # clone the opened Image, instead of re-opening it
mm.resize(thumbnail_dimensions.join("x"))
mm.write(Rails.root.join('public', 'uploads', "t_"+new_url))
// Generates cropped version
mm_copy.crop('200x200')
mm_copy.write(Rails.root.join('public', 'uploads', "c_"+new_url))

Resources