Search code examples
rubyruby-on-rails-3svgimagemagickrmagick

Rails: SVG to PNG using imagemagick/RMagick


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 &quot;Arial&quot;\" 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.... :(


Solution

  • 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!!