views:

734

answers:

3

Is there any way to make nice round corners with python? Currently PIL and GD2 are used in my project. Both of them have an arc() method, that allows you to draw a quater-circle, but the quater-circle is not antialiased, so the image looks crispy.

Is there any neat way to make antialiased/smooth round corners?

+10  A: 

What I usually do is use an image as a mask, like this one for example:

border.png

alt text

border = Image.open('border.png')
source = border.convert('RGB')
img.paste(source, mask=border)

The mask can be resized to fit the dimensions you want. Just make sure to use the Image.ANTIALIAS method.

You can refer to the tutorial I wrote a while ago for more details (shameless plug)

If you want more control over the size and the radius then you need to use arc or pieslice. I don't know about you but this rounded rectangle I created with PIL looks smooth enough to me:

alt text

Here is the code I used to draw it

Maybe you should check phatch: http://photobatch.wikidot.com/tutorials It is written in Python and PIL and can apply round corners to photos.

alt text

Here is a link to the code used to apply round corners: http://bazaar.launchpad.net/~stani/phatch/trunk/annotate/head:/phatch/actions/round.py

That also looks smooth enough to me.

Nadia Alramli
Yellow rectangle on a white background—not the easiest colours to see how smooth it might be.
Craig McQueen
@Craig, fair enough :)
Nadia Alramli
Thanks for the idea with copying over round corners.Yes, i need to control size and radius and these corners do not look smooth to me, because I apply them to photos.
DataGreed
I added more details to the answer
Nadia Alramli
Wow, thanx for phatch - i'll check it out.
DataGreed
+2  A: 

You'll have to supersample: draw the arc to a larger image and scale it down.

eg. a white, smoothly semi-transparent bottom-right 16x16 border, with 4x4x square supersampling:

>>> import Image, ImageDraw
>>> im= Image.new('RGBA', (16*4, 16*4), (255, 255, 255, 0))
>>> dr= ImageDraw.ImageDraw(im)
>>> dr.pieslice((-64, -64, 64, 64), 0, 340, fill=(255,255,255,255))
>>> im= im.resize((16, 16), Image.ANTIALIAS)
>>> im.save('border-se.png')
bobince
That's what i use now, but this method makes the modified image look blurry :(
DataGreed
I apply corners to photos and the photos should look like they used to + with smooth round corners
DataGreed
OK, then swap the transparency round in the above (so you're painting transparent-white (255,255,255,0) onto opaque-white (255,255,255,255). Now you've got a corner stencil. You can than get the photo and use `photoim.paste(cornerim, position, cornerim)` to put the white corner stencil on top of the bottom-right part of the photo. Flip the stencil with `transpose()` and do again for each of the corners. (If you need to make the output transparent that's a little bit more work, you'd have to make a separate complete mask image the same size as the photo then paste the photo and mask together.)
bobince
Nice solution, though i need transparent corners :) But thank you, anyway
DataGreed
+1  A: 

So, okay, i found the solution.

I used the supersampling method bobince proposed before, but i found that the images become blurry. So, I would not provide the full code, but i'll explain my solution.

It may seem kind of idiotistic, but i haven't found any other way to do it without involving any other libraries.

With PIL you draw white (or whatever color you need, involving transparent ones) corners on the image. Then you copy it. You should now have two images with crispy non-antialiased white round corners.

Now you should use scale-up -> scale-down supersampling (see bobince's answer above for details) method to make one of the images smooth (i used 8x scaling).

Now you have two images - one with crispy corners and another one with smooth corners, but with blurry picture.

You have now to make corners on crispy image transparent and paste the whole image on the smooth one. I used the Image.composite(crispy_image, smooth_image, crispy_image) method in PIL library to do this.

Voila!

DataGreed