Rounded corners with Paperclip
When applying a new design to one of our projects, we were in a need of a Paperclip style with rounded corners. Luckily for us we had Paperclip’s :convert_options and strong ImageMagick-fu.
After trying out some different CSS hacks, and jQuery plugins for getting the rounded corner effects we wanted, we turned to Paperclip. Since this particular style of a photo was only to be used at one place in the new design, we could apply the rounded corners directly to the image.
I googled around a bit and found a fork of Paperclip by shadow11 with some changes that never made it into the official Paperclip repository. His approach was to add the rounded corner code into Paperclip itself, and provide a argument to has_attached called rounded. IMO that’s probably nice-to-have if you do a lot of rounded corners on your attachments, but probably not something most people need. So I went ahead and copy-pasted out the juicy parts from his commit.
Firstly, we need to make sure that the style we are applying rounded corners to is a PNG file, since that’s the only file-format we have on the web that’s capable of transparancy (which we’ll use for the rounded corners effect). So my initial User model (borrowed from the Paperclip example) looks like this:
1 2 3 4 5 |
class User < ActiveRecord::Base has_attached_file :avatar, :styles => { :medium => ["300x300>", :png], :thumb => "100x100>" } end |
So, in order to get some corners stripped of this new PNG style, we need to utilize Paperclip’s convert_options, which allows us to give extra parameters to the ImageMagick convert command that Paperclip uses for resizing. The extra flags that does this job is as follows (I’m no ImageMagick pro-user, but a good copy-paster, and it actually works):
\( +clone -threshold -1 -draw 'fill black polygon 0,0 0,5 5,0 fill white circle 5,5 5,0' \( +clone -flip \) -compose Multiply -composite \( +clone -flop \) -compose Multiply -composite \) +matte -compose CopyOpacity -composite |
This adds a 5 pixel rounding to all four corners of our image, replacing the old ones with a transparent background.
In order to get this into my Avatar, all I had to do was to include this code in the hash being sent to has_attached (THE Paperclip command). While testing, I actually Proc’ed the convert_options and ended up with the code below, but that’s really not necessary, you probably want to roll your own something on this part. But here’s the full User model that’s working:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class User < ActiveRecord::Base has_attached_file :avatar, :styles => { :medium => ["300x300>", :png], :thumb => "100x100>" }, :convert_options => {:medium => Proc.new{self.convert_options}} def self.convert_options trans = "" px = 20 trans << " \\( +clone -threshold -1 " trans << "-draw 'fill black polygon 0,0 0,#{px} #{px},0 fill white circle #{px},#{px} #{px},0' " trans << "\\( +clone -flip \\) -compose Multiply -composite " trans << "\\( +clone -flop \\) -compose Multiply -composite " trans << "\\) +matte -compose CopyOpacity -composite " end end |
And that’s all. The medium style of my attached Avatar is now rounded with nice 20px corners. Looking forward to implement this (in a cleaner way) on the project tomorrow.
Simone Carletti commented about 12 hours later (August 11, 2009 11:16)
I didn’t know it was possible to obtain such this kind of image transformations with Paperclip before reading this post. That’s a really nice example of :convert_options advanced usage.
Thanks!
Ken-guru commented about 14 hours later (August 11, 2009 12:48)
Easy and concise, I like it.
Just used it now in a project and it made a world of difference.
Lars commented about 15 hours later (August 11, 2009 13:43)
Here’s the result of the above processing:
Dave Giunta commented about 17 hours later (August 11, 2009 15:36)
That’s definitely some crazy ImageMagick-fu! Nice work! In other news, that is one pimp-daddy bathroom!
Jeff Casimir commented about 19 hours later (August 11, 2009 17:49)
I like it, but I don’t get it. Trying to make sense of why you have to draw a black polygon first, then a white circle second. I guess it has to do with the flip/flopping and Multiply compositions — you know why people hate on the complexities of ImageMagick.
Meno commented 17 days later (August 28, 2009 13:40)
Looks like i’m not as good in copy pasting than you. If i try this with my installation it fails. I got ImageMagick 6.5.3-Q8 for windows and paperclip 2.3.
Is it possible, that it’s just not working with my versions?
Lars commented 21 days later (September 01, 2009 15:15)
I’m running at Ubuntu with ImageMagick 6.4.5-Q16 and Paperclip 2.2.9 – if you pastie a dump of your error, I could have a look. Might be some difference with either ImageMagick or Paperclip on Windows too?
Bookis commented about 1 month later (September 18, 2009 22:39)
I had quite a lot of trouble getting this method to work for png’s with transparency already in them. Although the solution is pretty simple I thought I would paste it for anyone else who knows nothing about ImageMagick:
def self.convert_options trans = "" px = 16 trans << "\\( +clone -alpha extract " trans << " \\( +clone -threshold -1 " trans << "-draw ‘fill black polygon 0,0 0,#{px} #{px},0 fill white circle #{px},#{px} #{px},0’ " trans << "\\( +clone -flip \\) -compose Multiply -composite " trans << "\\( +clone -flop \\) -compose Multiply -composite " trans << "\\) -composite \\) +matte -compose CopyOpacity -composite " endThanks for the this rounding corners method. It’s awesome.
Joost commented 5 months later (January 18, 2010 16:18)
Nice work, but I have a question. Why are the files so big? Like the example above here. The image is 240kb big. Is it some setting in imagemagick? Anyone have a solution for this. thx a lot!
Ctaloc commented 5 months later (February 01, 2010 02:15)
Nice dud, ty.
Write a comment