render a Google Chart to a file

44 views
Skip to first unread message

Adam Ziemba

unread,
Mar 11, 2010, 6:04:42 PM3/11/10
to rubyonra...@googlegroups.com
Anyone not familiar with Google Charts, it's simple, a PNG image is
produced by a configured URL. E.g. follow the link:

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 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!
--
Posted via http://www.ruby-forum.com/.

Rob Biedenharn

unread,
Mar 11, 2010, 9:49:31 PM3/11/10
to rubyonra...@googlegroups.com

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
R...@AgileConsultingLLC.com

Adam Ziemba

unread,
Mar 18, 2010, 2:50:02 PM3/18/10
to rubyonra...@googlegroups.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!

Adam Ziemba

unread,
Mar 18, 2010, 3:02:23 PM3/18/10
to rubyonra...@googlegroups.com
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 Law

unread,
Mar 18, 2010, 5:10:00 PM3/18/10
to rubyonra...@googlegroups.com
On 18 March 2010 18:50, Adam Ziemba <li...@ruby-forum.com> 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

>
> 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!
> --
> Posted via http://www.ruby-forum.com/.
>

> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To unsubscribe from this group, send email to rubyonrails-ta...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
>
>

Adam Ziemba

unread,
Mar 18, 2010, 9:00:58 PM3/18/10
to rubyonra...@googlegroups.com
Colin Law wrote:

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%7CSun%7CMon%7CTue%7CWed%7CThu%7CFri%7CSat%7C1%3A%7C0%7C2%7C4%7C6%7C8%7C10%7C12

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!

pharrington

unread,
Mar 18, 2010, 9:23:59 PM3/18/10
to Ruby on Rails: Talk
On Mar 18, 9:00 pm, Adam Ziemba <li...@ruby-forum.com> wrote:
> 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%3...

>
> 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=5...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!
> --
> 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?):

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

Brijesh Shah

unread,
Mar 19, 2010, 1:10:59 AM3/19/10
to rubyonra...@googlegroups.com
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

Rob Biedenharn

unread,
Mar 19, 2010, 8:17:36 AM3/19/10
to rubyonra...@googlegroups.com

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.

Reply all
Reply to author
Forward
0 new messages