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!

On Mar 11, 2010, at 6:04 PM, Adam Z. wrote:

might be
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 B. http://agileconsultingllc.com
[email protected]

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!

On 18 March 2010 18:50, Adam Z. [email protected] wrote:

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

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…

Colin L. 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!

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 S.

On Mar 18, 9:00 pm, Adam Z. [email protected] wrote:

invalid parameters, which is why you got all that HTML and Javascript.
you’ll get a PNG image and nothing else.

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!

Posted viahttp://www.ruby-forum.com/.

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 `’
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>
ruby-1.9.1-p376 > File.open(“png.png”, “w”) {|f| f.write c.body_str}
=> 5445
ruby-1.9.1-p376 >

On Mar 18, 2010, at 9:00 PM, Adam Z. wrote:

I’m not convinced that this approach will never work.

valid, or so I thought. I pass these kind of characters as parameters
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
irb> 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”
irb> md = %r{(https?:)//((?i:[-a-z0-9.]+))(/[^?]+)??(.*)}.match(orig)
=> #MatchData:0x391070
irb> 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”]
irb> 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”]]
irb> u = URI.parse “#{scheme}//#{host}”
=> #<URI::HTTP:0x37cf44 URL:http://chart.apis.google.com>
irb> u.path = path
=> “/chart”
irb> 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”
irb> open(u.to_s) do |chart|
?> File.open(‘chart.png’, ‘w’) {|f| f.write chart.read }
irb> end
=> 5445
irb> 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 B. http://agileconsultingllc.com
[email protected]