So I was working on a project (KnoFolio.net) with a super cool web designer dude I know (Andrew Coyle) and there was something in his user studio design that I had a bit of trouble with. His design had this image as the avatar:
and he wanted any user uploaded image to be filtered out in a similar way. At first I was all like WTF no way is that happening. I know I've blogged about image processing before but this seemed out of scope for the project. Then after a couple of weeks working on the project I got to the page that needed this and I had already decided to use Paperclip for image uploading to Amazon S3 and I knew that I could do some filtering in there with ImageMagick but had no idea how to go about making something like this.
So I took to reading up on some ImageMagick and paperclip docs; I quickly learned that I can (without writing my own image processor cause that sounds shitty) indeed use any of ImageMagick's commands to edit the image. Paperclip just calls the convert command so I can add anything to that I want. So I took to testing in terminal and quickly found that the -page command was what I wanted (Paging Dr. Faggot). It allows me to put any additional images on top of the original image; next I took to photoshop to get what I needed.
Photoshop
Andrew had kindly given me the pattern he was using for this in a psd so I took this and made it into an image that I could layer on top of a user uploaded picture to get our effect.
Layer 1 (gradient -to fill transparency- and additional spacing added for demonstration) was simply a white covering over the negative space of the image, this essentially removes all the extra stuff in the background of the image that would otherwise be outside of our splat pattern.
I then put a simple gray at about 40% opacity behind this layer so that when placed on top of the user image it would show the image but add some gray coloring. What I ended up with was (pattern -to fill transparency- and additional spacing added for demonstration):
I played around with this on the command line awhile and finally came up with the perfect command:
The holy command
convert original_image.png -resize 120x135^ -gravity center -extent 120x135 -colorspace gray -page -10-10 profile_cover.png -layers merge +repage -flatten -transparent -resize 180x182 output.png
Which when run on an image like this one:
Outputed this:
But lets break down the command and figure out what all is happening
This first part:
convert original_image.png -resize 120x135^ -gravity center -extent 120x135
takes original_image.png; resizes it to 120x135. The ^ tells it to fill the space even if it has to exceed one of the dimensions givien. The -gravity center tells image magick to resize from the middle of the image instead of one of the corners (I think top left is default) and the -extent 120x135 crops the image off at that size since we may have resized it to larger in the resize command before
Next I convert the user image to gray scale
-colorspace gray
Then I layer the top image I created in photoshop; the -10-10 places this image -10 pixels up and -10 pixles left of the original image
-page -10-10 profile_cover.png
Now I take these two images that we've placed on top of each other and merge them; the +repage is required to reset the croping frame; otherwise we'd loose those -10-10 pixels since they're technically off frame of the original image.
-layers merge +repage
This gives us this image (Gradient border added for demonstration):
We're so close now; just need to convert whitespace to transparent space and resize down to our desired size:
+repage -resize 180x182 output.png
Put it in paperclip already!
Ok, now that this works great in terminal lets get it into paperclip. We just need to use the convert_options in our Avatar model right? You couldn't be stupider! Yes it starts there but thats not all. This is what my attachment definition looks like for a single size:
has_attached_file :attachment,
:styles => {
:normal => :png,
},
:convert_options => {
:normal => ' -resize 120x135^ -gravity center -extent 120x135 -colorspace gray -page -10-10 profile_cover.png -layers merge +repage -flatten -transparent white -resize 180x182'
}
Notice the file type png definition; this screwed me a bit. I had only tested with png24 files before so everything worked great but then after I deployed this out somebody thought it'd be fun to upload a jpg. Well it was pretty ugly since by default paperclip maintains filetype and just dumbly converted my nice transparent clean image into an ugly minotaur eating beast.
Some Caveats
As you'll notice the images I was testing are actually headshots and have no background -thats because I striped it out. The whole thing works best that way. It does still function with a background; its just not as clean. Browse the gallery and user profiles on KnoFolio.net for examples!