Rails: SVG to PNG using imagemagick/RMagick - ruby

I've been struggling to get SVG string conversion to PNG image in Rails 3.2 application, using Rmagick and ImageMagick installed.
SVG stream
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><svg height=\"500\" version=\"1.1\" width=\"535\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xml:space=\"preserve\" viewBox=\"0 0 535 500\" preserveAspectRatio=\"xMinYMin\" preserveaspectratio=\"xMinYMin\" style=\"overflow: hidden; position: absolute;\"><image x=\"0\" y=\"0\" width=\"535\" height=\"500\" preserveAspectRatio=\"none\" xlink:href=\"/home/kamesh/apps/tuosystems/develop/public/system/product_images/67bf5f8332fbe4584c64eae7be25b70a80473d3d.jpg\" id=\"productImage\" laservice=\"true\" style=\"-webkit-tap-highlight-color: rgba(0, 0, 0, 0);\"></image><desc style=\"-webkit-tap-highlight-color: rgba(0, 0, 0, 0);\"></desc><defs><link xmlns=\"http://www.w3.org/1999/xhtml\" href=\"/home/kamesh/apps/tuosystems/develop/app/assets/stylesheets/fonts.css\" type=\"text/css\" rel=\"stylesheet\"/></defs><text x=\"0\" y=\"0\" text-anchor=\"middle\" font=\"10px "Arial"\" stroke=\"none\" fill=\"#00ffff\" transform=\"matrix(2.6709,0,0,2.6709,253.5,162)\" font-size=\"32px\" fix-storke-scale=\"true\" id=\"id1408688358639\" font-weight=\"normal\" font-style=\"normal\" font-family=\"SfCollegiate\" stroke-width=\"1\" style=\"-webkit-tap-highlight-color: rgba(0, 0, 0, 0); text-anchor: middle; font-style: normal; font-variant: normal; font-weight: normal; font-size: 32px; line-height: normal; font-family: SfCollegiate; cursor: pointer;\"><tspan dy=\"9\" style=\"-webkit-tap-highlight-color: rgba(0, 0, 0, 0);\">BMCC</tspan></text><svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" width=\"535\" height=\"543px\" viewBox=\"0 0 587 543\" enable-background=\"new 0 0 587 543\" xml:space=\"preserve\"><g id=\"Layer\">\t<polygon fill=\"#CC0000\" points=\"470,0 532,0 587,55 587,117 \t\"></polygon>\t<g>\t\t<path fill=\"#FFFFFF\" d=\"M504.561,13.174l5.748-5.749l-2.068-2.068l1.326-1.326l5.643,5.643L513.883,11l-2.058-2.058l-5.748,5.749\t\t\tL504.561,13.174z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M513.099,21.712l1.124-3.903l-1.103-1.103l-2.514,2.514l-1.506-1.506l7.074-7.075l3.309,3.309\t\t\tc1.475,1.475,1.421,3.352,0.106,4.667c-1.241,1.241-2.716,1.124-3.66,0.541l-1.092,4.296L513.099,21.712z M518.052,17.056\t\t\tc0.583-0.583,0.487-1.4-0.106-1.994l-1.591-1.591l-1.909,1.909l1.591,1.591C516.63,17.564,517.447,17.66,518.052,17.056z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M515.921,24.534l7.074-7.075l1.506,1.506l-7.074,7.075L515.921,24.534z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M523.716,32.329l0.753-1.644l-3.033-3.033l-1.645,0.752l-1.707-1.707l9.8-4.349l1.888,1.888l-4.349,9.8\t\t\tL523.716,32.329z M527.322,24.799l-4.146,1.941l2.205,2.205L527.322,24.799z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M526.018,34.631l7.074-7.075l1.517,1.517l-5.749,5.749l2.99,2.99l-1.325,1.326L526.018,34.631z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M536.624,45.237l4.179-9.97l0.7,0.7l-3.818,8.973l8.962-3.829l0.7,0.7l-9.97,4.179L536.624,45.237z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M541.313,49.926l7.074-7.075l4.486,4.486l-0.552,0.552l-3.882-3.882l-2.62,2.62l3.808,3.808l-0.551,0.552\t\t\tl-3.808-3.808l-2.801,2.8l3.882,3.882l-0.551,0.552L541.313,49.926z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M551.441,60.055l0.943-4.911l-1.56-1.56l-2.927,2.928l-0.604-0.604l7.074-7.075l2.641,2.641\t\t\tc1.22,1.22,1.378,2.927,0.084,4.221c-1.283,1.283-2.896,1.093-3.998,0.075l-0.923,5.017L551.441,60.055z M556.458,55.059\t\t\tc0.891-0.891,0.891-2.143-0.053-3.086l-1.984-1.984l-3.044,3.044l1.984,1.984C554.305,55.96,555.567,55.95,556.458,55.059z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M554.199,60.818l0.848-0.064c-0.064,0.976,0.169,2.227,1.188,3.246c1.442,1.442,2.663,1.05,3.268,0.446\t\t\tc2.078-2.079-3.245-5.239-0.774-7.71c1.156-1.156,2.927-0.849,4.21,0.434c1.05,1.05,1.485,2.228,1.4,3.395l-0.849,0.042\t\t\tc0.106-1.124-0.339-2.122-1.134-2.917c-0.944-0.944-2.196-1.114-2.96-0.351c-1.814,1.813,3.425,5.059,0.784,7.7\t\t\tc-0.912,0.912-2.608,1.401-4.519-0.509C554.495,63.363,554.092,62.005,554.199,60.818z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M559.757,68.37l7.074-7.075l0.604,0.604l-7.074,7.075L559.757,68.37z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M565.389,66.938c2.068-2.068,5.017-2.302,7.095-0.224c2.068,2.068,1.847,5.029-0.222,7.097\t\t\tc-2.067,2.068-5.028,2.29-7.097,0.222C563.087,71.955,563.321,69.007,565.389,66.938z M571.625,73.175\t\t\tc1.793-1.792,2.005-4.211,0.308-5.908c-1.707-1.707-4.115-1.485-5.908,0.308c-1.781,1.782-2.015,4.201-0.308,5.908\t\t\tC567.414,75.179,569.844,74.957,571.625,73.175z\"></path>\t\t<path fill=\"#FFFFFF\" d=\"M575.284,83.897l1.622-10.533l-6.077,6.078l-0.604-0.604l7.074-7.075l0.615,0.615l-1.559,10.426\t\t\tl5.992-5.993l0.604,0.604l-7.074,7.075L575.284,83.897z\"></path>\t</g>\t<g opacity=\"0.15\">\t\t<path d=\"M88.701,103.649l36.314-36.314l7.785,7.785l-29.509,29.509l15.353,15.353l-6.806,6.806L88.701,103.649z\"></path>\t\t<path d=\"M117.068,132.016l36.314-36.314l7.73,7.73l-36.314,36.314L117.068,132.016z\"></path>\t\t<path d=\"M142.167,157.114l22.323-50.306l8.765,8.765l-17.802,37.949l37.947-17.804l8.765,8.765l-50.306,22.323L142.167,157.114z\"></path>\t\t<path d=\"M169.227,184.175l36.314-36.314l25.697,25.697l-6.806,6.806l-17.967-17.967l-7.622,7.622l17.586,17.586l-6.806,6.806\t\t\tl-17.586-17.586l-8.275,8.275l17.967,17.967l-6.806,6.806L169.227,184.175z\"></path>\t\t<path d=\"M226.068,241.016l3.865-8.439l-15.571-15.571l-8.439,3.865l-8.765-8.765l50.306-22.323l9.692,9.692l-22.322,50.306\t\t\tL226.068,241.016z M244.58,202.36l-21.288,9.963l11.324,11.324L244.58,202.36z\"></path>\t\t<path d=\"M258.736,273.684l5.771-20.036l-5.662-5.661l-12.903,12.903l-7.731-7.731l36.315-36.314l16.986,16.987\t\t\tc7.567,7.567,7.296,17.205,0.545,23.956c-6.37,6.37-13.938,5.771-18.783,2.776l-5.609,22.05L258.736,273.684z M284.162,249.782\t\t\tc2.994-2.994,2.504-7.187-0.545-10.235l-8.166-8.166l-9.8,9.8l8.167,8.166C276.866,252.396,281.059,252.886,284.162,249.782z\"></path>\t\t<path d=\"M281.061,296.008l29.509-29.509l-10.617-10.617l6.806-6.806l28.965,28.965l-6.806,6.806l-10.563-10.563l-29.509,29.509\t\t\tL281.061,296.008z\"></path>\t\t<path d=\"M331.422,346.369l17.259-17.259l-23.03-23.03l-17.259,17.259l-3.104-3.104l36.314-36.314l3.104,3.104l-16.225,16.225\t\t\tl23.03,23.03l16.225-16.225l3.104,3.104l-36.314,36.314L331.422,346.369z\"></path>\t\t<path d=\"M352.819,367.767l33.483-33.483l-11.868-11.868l2.831-2.831l26.895,26.895l-2.831,2.831L389.46,337.44l-33.483,33.483\t\t\tL352.819,367.767z\"></path>\t\t<path d=\"M405.088,420.035l32.395-32.395l-45.625,19.164l-1.197-1.197l19.109-45.68l-32.395,32.395l-3.103-3.103l36.314-36.314\t\t\tl4.628,4.628l-17.858,42.575l42.521-17.912l4.683,4.683l-36.314,36.314L405.088,420.035z\"></path>\t\t<path d=\"M416.523,431.471l36.314-36.314l3.157,3.157l-33.483,33.483l17.586,17.586l-2.831,2.831L416.523,431.471z\"></path>\t\t<path d=\"M448.429,452.813h4.137c-0.979,5.662,0.328,10.672,5.01,15.354c5.281,5.281,12.903,5.28,17.857,0.326\t\t\tc5.499-5.499,5.063-12.685-0.163-17.911c-3.321-3.321-7.241-5.063-12.358-5.282l-1.361-3.32l19.056-19.056l20.961,20.961\t\t\tl-2.831,2.831l-17.857-17.857l-14.21,14.21c3.538,0.054,8.274,1.524,12.031,5.281c6.098,6.098,7.568,15.625,0.001,23.192\t\t\tc-7.241,7.241-17.26,6.152-23.956-0.544C448.701,464.955,447.339,458.911,448.429,452.813z\"></path>\t</g></g></svg></svg>"
For converting svg string to svg image (after some path adjustment):
def get_svg_image(svg_data)
replace_path = LIVEARTPRODUCTS["product_#{#liveart_id.to_s}"]["path"] if LIVEARTPRODUCTS["product_#{#liveart_id.to_s}"]
replace_image = replace_path ? replace_path : "/liveart_images/default_products/cool-t-shirt_White_front.jpg"
svg_data = svg_data.gsub(replace_image, "#{params["edited_image"].split("?")[0]}") if params["edited_image"].present?
svg_data = svg_data.gsub("/system/product_images/", "#{Rails.root}/public/system/product_images/");
svg_data = svg_data.gsub("/liveart_images/default_products", "#{Rails.root}/public/liveart_images/default_products")
svg_data = svg_data.gsub("/liveart_images/uploads", "#{Rails.root}/public/liveart_images/uploads")
svg_data = svg_data.gsub("/liveart_images/graphic_images", "#{Rails.root}/public/liveart_images/graphic_images")
svg_data = svg_data.gsub("/assets/fonts.css", "#{Rails.root}/app/assets/stylesheets/fonts.css")
ilist = Magick::ImageList.new
svg_image = ilist.from_blob(svg_data)
end
Have called this method in controller as:
require 'RMagick'
def save_design
svg_data = (getting from some json got from submit)
svg_image = get_svg_image(svg_data)
# write svg image as png image
png_file = Tempfile.new(["#{rand(9999).to_s}",'.png'])
svg_image.write(png_file.path)
# Create new product image from new temp image formed
#pi = ProductImage.new
#pi.image = png_file
respond_to do |format|
if (#pi.save)
format.json
else
format.json {render :json => {status => 'error', message => 'Internal error occurred'}}
end
end
end
This above code is working fluently on one my development machine.
Machine Config:
Fedora: 16
Rails: 3.2
Ruby: 1.9.2-p320
ImageMagick: 6.7.0-10 (installed yum install ImageMagick-devel)
gem RMagick: 2.13.2
But, on another Ubuntu machine, (also staging and production):
Ubuntu: 14.04
Rails: 3.2
Ruby: 1.9.2-p320
ImageMagick: 6.7.7-10 (installed sudo apt-get install imagemagick libmagickwand-dev librsvg2-dev)
gem RMagick: 2.13.2
But, Only Blank image is getting created only with text in fonts applied. No linked Image is included in SVG and PNG image finally created.
Image included in above SVG string as:
/home/user_name/apps/project1/develop/public/system/product_images/67bf5f8332fbe4584c64eae7be25b70a80473d3d.jpg
Tried to change access rights and reinstalling all libraries, but not yet fruitful.... :(

Issue was in the path for the images while replacing relative path to absolute path.
Just corrected path for the images in above SVG. ImageMagick was able to find images embedded in SVG and Final image is created.
ImageMagick requires absolute directory and file path to file or image, if its embedded in SVG stream.
Thanks!!
Keep Rocking!!

Related

Composite manipulated images with RMagick

I'm trying to create a composite image from two original images, a background and an overlay which I manipulate using RMagick like follows:
background = ImageList.new("foo.png")
overlay_original = ImageList.new("bar.png")
overlay_resized = overlay_original.resize_to_fit(400,400)
overlay_cropped = overlay_resized.crop(NorthWestGravity, 400, 200)
new_image = ImageList.new
new_image = new_image.composite_layers(background)
new_image = new_image.composite_layers(overlay_cropped)
When I do this it gives me the following error: ArgumentError: no images in this image list
When I just try to check the length of the background and overlay_cropped image lists (background.length and overlay_cropped.length) it tells me the background image list has 1 image, but that overlay_cropped has no images:
NoMethodError: undefined method length' for bar.png PNG 640x1096=>400x200 400x400+0+0 DirectClass 8-bit:Magick::Image
Any ideas on what I'm doing wrong? I"m guessing the answer is pretty obvious.
Issue resolved by changing it to the following:
marketing_image = marketing_image.composite(background, NorthWestGravity, 0, 0, OverCompositeOp)
marketing_image = marketing_image.composite(overlay_cropped, NorthWestGravity, 327, 126, OverCompositeOp)

Rmagick - image with transparent background from text

I am trying to create an image file from text using Rmagick in ruby. Additionally I need it's background transparent. My code:
canvas = Image.new(400, 60)
watermark_text = Draw.new
watermark_text.annotate(canvas, 0,0,0,0, text) do
self.gravity = WestGravity
self.pointsize = 50
self.font = "whatever.ttf"
self.fill = 'black'
self.stroke = "none"
end
canvas.write(#path)
It works, but the background of the image is white and I need it to be transparent. Any ideas? File is saved as png.
When you create an image, the default background is white. You can tell rmagick you want a different background:
canvas = Image.new(400, 60) do |c|
c.background_color= "Transparent"
end

RMagick transparency not working when compositing one image over another

In the following code I'm trying to overlay a transparent square over the image of some mountains. I thought it would work, but by setting background_color = 'none' it doesn't make the image transparent!
The result is a black square over the top left corner - desired result is the black square should be transparent.
require 'open-uri'
require 'RMagick'
image_url = 'http://farm9.staticflickr.com/8446/7937080514_62d7749860.jpg'
bg = Magick::ImageList.new
open(image_url, 'rb') do |f|
bg.from_blob(f.read)
end
layer = Magick::Image.new(200, 200) {
self.background_color = 'none'
}
bg.each do |frame|
frame.composite!(layer, 0, 0, Magick::OverCompositeOp)
frame.strip!
end
bg.write('out.jpg')
Here's my output image:
Edit: I'm on Mac, Lion, ruby 1.9.3p125, ImageMagick 6.7.5-7
Edit 2: This works fine on Heroku! But not on my machine. Heroku has the same version of ImageMagick. Strange :|
For some reason layer.alpha? == false. So I did sq.alpha(Magick::ActivateAlphaChannel) and then it worked!
Reference: http://www.imagemagick.org/RMagick/doc/image1.html#alpha

How to select color of a specific pixel in Rails?

Is it possible to somehow do the following in rails?
Get the color of a specific pixel from a image (for example at location 10px by 10px)
Delete all occurrences of that color from the image (gets replaced with transparent pixels)
Crop image to exclude any outer transparent pixels
Any advise would be greatly appreciated!
Rails? No.
Ruby? Yes.
Check out RMagick: http://rmagick.rubyforge.org/
Here's the code of how I did it using RMagick (thanks Alex Wayne for pointing me to RMagick)...
require 'RMagick'
img = Magick::Image.read("sample.jpg").first
bgcolor = img.pixel_color(1,1)
img.format = "PNG"
img.fuzz = 0.05
img.trim!
img.resize_to_fit!(100, 40)
bg = Magick::Image.new(100,40) { self.background_color = bgcolor }
img = bg.composite(img, Magick::CenterGravity, Magick::OverCompositeOp)
img.write("modified.png")
For my initial requirement (to just remove the outer colors or blank borders), the following is all you need:
require 'RMagick'
img = Magick::Image.read("sample.jpg").first
img.trim!
img.write("sample.jpg")

Can't get gravity to work with RMagick and 'caption'

I'm using RMagick 2.12.2 with ImageMagick 6.5.6-10 on Snow Leopard. I'm trying to put captions on a collection of photos, and I'm getting the caption to work (i.e. it appears on the image), but I can't get the gravity parameter to work correctly.
No matter what I set it to, I end up with some variation on NorthGravity.
For instance: Setting it to SouthWestGravity gives me NorthWestGravity. Setting it to SouthEastGravity gives me NorthEastGravity. Setting it to CenterGravity gives me NorthGravity.
In other words, I can't get the caption to come down off the top of the image.
I'd consider using "annotate," but I need "caption" so the lengthy caption text for each image will wrap.
What am I doing wrong?
Here's the code:
#!/usr/bin/env ruby
require "rubygems"
require "yaml"
require "RMagick"
include Magick
base_dir = "/Users/mike/Desktop/caption_test"
photo_log = File.open("#{base_dir}/photo_log.yaml" )
YAML::load_documents(photo_log) do |doc|
caption = doc["photo-caption"]
filename = doc["file"]
canvas = ImageList.new.from_blob(open("#{base_dir}/#{filename}") { |f| f.read } )
canvas << Magick::Image.read("caption:#{caption}") {
self.gravity = SouthWestGravity
self.size = "#{canvas.first.columns}"
self.font = "Helvetica Neue"
self.pointsize = 12
self.background_color = "#fff"
}.first
canvas.flatten_images.write("#{base_dir}/images/#{filename}")
end
You've probably long since moved on, but the I found a pretty simple answer to this--use
canvas.append(true).write("#{base_dir}/images/#{filename}")
In other words, you want the append option (use 'true' to stack vertically).
I think your problem is that you're applying the gravity to the dimensions of the caption image rather than the dimensions of the underlying image. Your caption will East/West align itself within its width but because it makes it own height, North/South always just mean North.
You probably want to specify the gravity on the flatten_images call instead which looks possible...

Resources