render a Google Chart to a file

Anyone not familiar with Google Charts, it's simple, a PNG image is produced by a configured URL. E.g. follow the link:

You'll see a chart that is a PNG image.

Okay so I need to save one of these to a file. I tried using Rails "render" action, treating the URL as if it were a web page... I might be WAY off but I figure what I need is something like this:

  File.open( "chart.png", "w" ) do |the_file|     the_file.puts render(:url => "http://chart.apis.google.com/chart?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|ELECTRICAL|BUMPER\_PINTLEH|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12"\)   end

Basically I need to store the contents of what is produced by the image at that really long Google Charts URL shown above.

I apologize for my newbieness, and thank you for all the help!

Look at open-uri (require 'open-uri')

open('http://chart…') do |chart|    File.open('chart.png', 'w') {|f| f.write chart.read } end

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com

open('http://chart…') do |chart|    File.open('chart.png', 'w') {|f| f.write chart.read } end

This is wonderful, I knew nothing of open-uri. However, I cannot seem to get it pull an image. Using the Google link above, which produces a PNG image, I get the error "bad URI(is not URI?)".

Looking at the API for open-uri, I could not find any information about images.

I played around with it, I can beautifully retrieve web pages and save them to disk, but what about images?

Thanks for the help!

I managed to get what seems to be a PNG file saved using an actual URL to the image:

  File.open 'image.png', 'w' do |file|     open('http://link_to_image.png').path { |chunk| file.write chunk }   end

Notice the .png extension which is not present with the Google charts URL.

This did save image.png to the file system, however the image is invalid. So this did not work even for a straight link to a PNG image.

I'm not going to have to use ImageMagick am I? Please tell me no...

open('http://chart…') do |chart| File.open('chart.png', 'w') {|f| f.write chart.read } end

This is wonderful, I knew nothing of open-uri. However, I cannot seem to get it pull an image. Using the Google link above, which produces a PNG image, I get the error "bad URI(is not URI?)".

I think you have two problems, firstly you need to escape the uri, this seems to work but there is probably a nicer way of doing it:     open("http://chart.apis.google.com/chart#\{CGI\.escape\('?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12'\)\}"\) do |chart|       File.open('chart.png', 'w') {|f| f.write chart.read }     end

Unfortunately you do not end up with a png file. If you open the file with a text editor you will find it is a web page with loads of javascript. Presumably the javascript generates the png. I think you need an alternative approach.

Colin

Colin Law wrote:

    open("http://chart.apis.google.com/chart#\{CGI\.escape\('?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12'\)\}"\) do |chart|       File.open('chart.png', 'w') {|f| f.write chart.read }     end

I definitely understand the why you would want to escape the URI, but I'm not convinced that this approach will never work.

The URL with the escaped characters causes Google to reject it as invalid parameters, which is why you got all that HTML and Javascript. E.g. if you use your browser to open the result of the above URI with escaped characters:

http://chart.apis.google.com/chart%3Fcht%3Dbvg%26chbh%3Da%26chd%3Ds%3Avttusty%26chs%3D500x300%26chxt%3Dx%2Cy%26chxl%3D0%3A|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1%3A|0|2|4|6|8|10|12

You are redirected to the Google chart API. Retaining the original characters with:

you'll get a PNG image and nothing else.

Okay, so Google doesn't want the escaped characters, and the URI::open method doesn't want the plain characters... or does it? Is there no way around this? The thing is the characters used in the URL above are valid, or so I thought. I pass these kind of characters as parameters from controller to view all throughout my application, with full browser compatibility.

I tried using backslashes for all the characters, e.g. "\&" instead of "&" and the URI open method still rejects it.

I've seen some people successfully get images to save to the file system using URI, but I'm assuming all their code is outdated as I could not get it to work. Also, the image URL they were using actually pointed to a PNG image, with a PNG extension, whereas the Google Chart URL will return a PNG image.

I appreciate all the help!

Seems an inadequacy of Ruby URI library. Curb (Ruby libcurl bindings) works simply and easily though:

ruby-1.9.1-p376 > require 'open-uri' => true ruby-1.9.1-p376 > png = "http://chart.apis.google.com/chart? cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue| Wed>Thu>Fri>Sat>1:|0|2|4|6|8|10|12" => "http://chart.apis.google.com/chart? cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue| Wed>Thu>Fri>Sat>1:|0|2|4|6|8|10|12" ruby-1.9.1-p376 > open png URI::InvalidURIError: bad URI(is not URI?): http://chart.apis.google.com/chart?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12         from /home/xeno/.rvm/ruby-1.9.1-p376/lib/ruby/1.9.1/uri/ common.rb:156:in `split'         from /home/xeno/.rvm/ruby-1.9.1-p376/lib/ruby/1.9.1/uri/ common.rb:174:in `parse'         from /home/xeno/.rvm/ruby-1.9.1-p376/lib/ruby/1.9.1/uri/ common.rb:626:in `parse'         from /home/xeno/.rvm/ruby-1.9.1-p376/lib/ruby/1.9.1/open- uri.rb:32:in `open'         from (irb):3         from /home/xeno/.rvm/ruby-1.9.1-p376/bin/irb:15:in `<main>' ruby-1.9.1-p376 > require 'curb' => true ruby-1.9.1-p376 > c = Curl::Easy.perform png => #<Curl::Easy http://chart.apis.google.com/chart?cht=bvg&chbh=a&gt; ruby-1.9.1-p376 > File.open("png.png", "w") {|f| f.write c.body_str} => 5445 ruby-1.9.1-p376 >

Use following method to get image in file from any url

Net::HTTP.start("#{DOMAIN_URL}") { |http|         resp = http.get(PARAMS)         open( "#{OUTPUT_DIR}/#{file_name}.png", 'wb' ) { |file|           file.write(resp.body)         } }

Where DOMAIN_URL: http://chart.apis.google.com PARAMS: /chart?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12

Thanks Brijesh Shah

Colin Law wrote:

   open("http://chart.apis.google.com/chart#\{CGI\.escape\(&#39;?cht=bvg&amp;chbh=a&amp;chd=s:vttusty&amp;chs=500x300&amp;chxt=x,y&amp;chxl=0:|Sun|Mon|Tue&gt;Wed&gt;Thu&gt;Fri&gt;Sat&gt;1:|0|2|4|6|8|10|12&#39;\)\}&quot;\) do |chart|      File.open('chart.png', 'w') {|f| f.write chart.read }    end

I definitely understand the why you would want to escape the URI, but I'm not convinced that this approach will never work.

The URL with the escaped characters causes Google to reject it as invalid parameters, which is why you got all that HTML and Javascript. E.g. if you use your browser to open the result of the above URI with escaped characters:

http://chart.apis.google.com/chart%3Fcht%3Dbvg%26chbh%3Da%26chd%3Ds%3Avttusty%26chs%3D500x300%26chxt%3Dx%2Cy%26chxl%3D0%3A|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1%3A|0|2|4|6|8|10|12

You are redirected to the Google chart API. Retaining the original characters with:

http://chart.apis.google.com/chart?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12

you'll get a PNG image and nothing else.

Okay, so Google doesn't want the escaped characters, and the URI::open method doesn't want the plain characters... or does it? Is there no way around this? The thing is the characters used in the URL above are valid, or so I thought. I pass these kind of characters as parameters from controller to view all throughout my application, with full browser compatibility.

I tried using backslashes for all the characters, e.g. "\&" instead of "&" and the URI open method still rejects it.

I've seen some people successfully get images to save to the file system using URI, but I'm assuming all their code is outdated as I could not get it to work. Also, the image URL they were using actually pointed to a PNG image, with a PNG extension, whereas the Google Chart URL will return a PNG image.

I appreciate all the help!

You just need a URI that's technically valid, not just one that browsers understand. URI.parse and thus open-uri is rather more strict than the other tools suggested.

Here's an irb session that shows the right way to get a valid URI for the chart you want.

$ irb -ruri -ropen-uri -rcgi

orig = 'http://chart.apis.google.com/chart?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0

:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12' => "http://chart.apis.google.com/chart?cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12&quot;

md = %r{(https?:)//((?i:[-a-z0-9.]+))(/[^?]+)\??(.*)}.match(orig)

=> #<MatchData:0x391070>

scheme, host, path, query_string = md.captures

=> ["http:", "chart.apis.google.com", "/chart", "cht=bvg&chbh=a&chd=s:vttusty&chs=500x300&chxt=x,y&chxl=0:|Sun|Mon|Tue|Wed>Thu>Fri>Sat>1:|0|2|4|6|8|10|12"]

query_string.split('&').map{|pair| pair.split('=')}

=> [["cht", "bvg"], ["chbh", "a"], ["chd", "s:vttusty"], ["chs", "500x300"], ["chxt", "x,y"], ["chxl", "0:|Sun|Mon|Tue|Wed|Thu|Fri|Sat|1:|0|2|4|6|8|10|12"]]

u = URI.parse "#{scheme}//#{host}"

=> #<URI::HTTP:0x37cf44 URL:http://chart.apis.google.com>

u.path = path

=> "/chart"

u.query = query_string.split('&').map{|pair|

pair.split('=')}.map{|n,v| "#{n}=#{CGI.escape(v)}"}.join('&') => "cht=bvg&chbh=a&chd=s%3Avttusty&chs=500x300&chxt=x%2Cy&chxl=0%3A%7CSun%7CMon%7CTue%7CWed%7CThu%7CFri%7CSat%7C1%3A%7C0%7C2%7C4%7C6%7C8%7C10%7C12"

open(u.to_s) do |chart|

?> File.open('chart.png', 'w') {|f| f.write chart.read }

  end

=> 5445

File.exist?('chart.png')

=> true

Note that if you are building up the URI yourself, you could just create it with valid escaping on the query string rather than pulling it apart and escaping it as you put it back together.

-Rob

Rob Biedenharn http://agileconsultingllc.com Rob@AgileConsultingLLC.com