Rounded Corners in Rails
Here is a controller I wrote that spits out rounded corners. It utilizes RMagick and operates nearly identical (width and height limited to 256) to the Google implementation as discovered by xach on LiveJournal.
You can see it below (or see it in action), or grab it from here: http://furui.org/tools_controller.rb
If you use it or see it in the wild, post a comment here. Thanks!
-
# Rails Graphics Tools
-
# (c) 2006 Jeffrey Davis
-
-
class ToolsController < ApplicationController
-
-
# Require the RMagick library and include its namespace
-
require ‘RMagick’
-
include Magick
-
-
def roundedcorners
-
# Rounded Corners similar to Google’s implementation for Groups Beta
-
-
# Don’t render a layout.
-
render :layout => false
-
-
# Retrieve the background color
-
bgcolor = params[:bc]
-
# If the background color wasn’t specified, use a transparent color
-
if bgcolor == nil
-
bgcolor = ‘transparent’
-
end
-
# If this is not a CSS2 color, then it must be a hex value.
-
if bgcolor.match(‘[g-zG-Z]‘)
-
else
-
bgcolor = "#" + bgcolor
-
end
-
-
# Retrieve the color
-
fgcolor = params[:c]
-
# If this is not a CSS2 color, then it must be a hex value.
-
if fgcolor.match(‘[g-zG-Z]‘)
-
else
-
fgcolor = "#" + fgcolor
-
end
-
-
# Retrive the size of the image
-
width = params[:w]
-
height = params[:h]
-
-
# If size wasn’t specified, set it to the default of 8
-
if width == nil
-
width = 8
-
else
-
width = width.to_i
-
end
-
if height == nil
-
height = 8
-
else
-
height = height.to_i
-
end
-
-
# Create a new image and set the background color
-
img = Image.new(256,256) {
-
self.background_color = bgcolor
-
}
-
-
# Create a new drawing object
-
gc = Draw.new
-
-
# Draw a circle in the upper left corner
-
gc.fill(fgcolor)
-
gc.stroke(fgcolor)
-
gc.circle(0,0,0,255)
-
-
# Write the drawing to the image
-
gc.draw(img)
-
-
# Check the orientation of the corner, and flip/flop accordingly
-
case params[:a]
-
when ‘tl’
-
img.flip!
-
img.flop!
-
when ‘bl’
-
img.flop!
-
when ‘br’
-
when ‘tr’
-
img.flip!
-
else
-
img.flip!
-
img.flop!
-
end
-
-
# Scale the image to the correct width and height
-
img.scale!(width,height)
-
-
# Write the image to a blob
-
blob = img.to_blob() {
-
self.format = ‘PNG’
-
self.depth = 8
-
}
-
-
# Send the blob to the client
-
send_data blob, :type => ‘image/png’, :disposition => ‘inline’
-
end
-
end
Derek Said on December 18th, 2006 at 6:21 am quote
I’ve yet to test this out, but it looks interesting.
Here’s a nitpicky concern: how come you didn’t create this as a helper instead of a controller action?
Martin Smith Said on December 18th, 2006 at 7:17 am quote
Hi,
How much extra processing does this take, compared to the same page without the corners?
Martin
furui Said on December 18th, 2006 at 9:57 am quote
@Derek, That’s a good idea. I might rewrite it as a simple plugin or something, though. It’s a quick hack, actually.
@Martin, In development mode running on a 2.2 GHz Opteron with 512 MB of ram on FreeBSD 6.1 AMD64 via Mongrel, it takes 0.0242~ seconds to completely process each rounded corner. Or, so the logs say. So, that much extra time for each rounded corner.
Processing ToolsController#roundedcorners (for 64.xxx.xxx.xxx at 2006-12-18 00:19:13) [GET]
Session ID: xxx
Parameters: {“a”=>”tr”, “w”=>”50″, “bc”=>”red”, “c”=>”999999″, “action”=>”roundedcorners”, “controller”=>”tools”, “h”=>”50″}
Rendering tools/roundedcorners
Sending data
Completed in 0.02423 (41 reqs/sec) | Rendering: 0.00005 (0%) | 200 OK
Jaime Lassman Said on December 18th, 2006 at 11:55 am quote
What do I need to do to get this to work on my own server? If I copy the image and the ruby controller, I can’t make it work. What am I missing?
image http://www.myserver.com/corners/roundedcorners.png
controller file=http://www.myserver.com/corners/tools_controller.rb
the URL http://www.myserver.com/corners/roundedcorners?c=999999&bc=white&w=50&h=50&a=tr gives an error. What am I missing?
Jacob Radford Said on December 18th, 2006 at 3:52 pm quote
Can you take advantage of caching? Then the cost will only hurt on the first call, right?
furui Said on December 18th, 2006 at 7:17 pm quote
@Jaime, To use it, your server must support Ruby on Rails: http://www.rubyonrails.org/
It must also have the RMagick gem installed: http://rmagick.rubyforge.org/
The controller must be installed into a Rails application.
The image file is not necessary. The script generates the image on the fly.
@Jacob, I am going to experiment with fragment caching when the project I am working on approaches beta. At that time, I’ll probably post an updated version of this snippet. This was a rough and fast throw together implementation.
Octoberdan Said on January 5th, 2007 at 4:45 pm quote
Perhaps you should add validation and reject requests for obscenely large and therefore strenuous images. If this process continues to reside within and be offered by a controller, which is inherently publicly accessible, then a malicious user with ill intent could theoretically write a script that fires off thousands of requests for large images and create heavy lag if not crash something… And if you implement caching and neglect protection from abuse, then that person could change their script to loop with “w=#{n++}” and cause further trouble. I’m going to try out your code and see if I can exploit it while its on my server. I’ll report my findings… And by the way, I had to use Internet Explorer to post this comment, Firefox didn’t pass the “javascript test!”
furui Said on January 5th, 2007 at 9:30 pm quote
@Octoberdan,
Ah, right. I’ll update the code to set a limit when I get a chance. Thanks a lot!
Hmm, strange. I first tested the javascript anti-spam plugin with Firefox 2.0.0.1. I’ll try it with 1.5 later and if it doesn’t work, I’ll pull it.