Rounding corners of pictures with ImageMagick - ruby-on-rails

in my Rails app I want to have a similar profile section like Facebook where uploaded images are automatically thumbnailed and corner-rounded. I'm using the convert utility to downsize images into thumbnails, but is there an option to round their corners too? Thanks.

Universal solution
This solution works with transparent and non-transparent pictures. To add 15 pixels radius rounded corners to original_picture.png which is a 100x100 picture:
convert -size 100x100 xc:none -draw "roundrectangle 0,0,100,100,15,15" mask.png
convert original_picture.png -matte mask.png \
-compose DstIn -composite picture_with_rounded_corners.png
This solution was given by PM here: https://stackoverflow.com/a/1916256/499917
Elegant solution, does not work with transparent pictures
This solution works without any intermediate picture. How nice! But it will disrupt your original picture's transparency. So use only when you are sure that your picture is not transparent.
Suppose you want rounded corners with 15px radius:
convert original_picture.png \
\( +clone -alpha extract \
-draw 'fill black polygon 0,0 0,15 15,0 fill white circle 15,15 15,0' \
\( +clone -flip \) -compose Multiply -composite \
\( +clone -flop \) -compose Multiply -composite \
\) -alpha off -compose CopyOpacity -composite picture_with_rounded_corners.png
For convenience, here is what you will typically do in Ruby or some other languages:
in_pic = "original_picture.png"
out_pic = "picture_with_rounded_corners.png"
radius = 15
cmd = "convert #{in_pic} \\( +clone -alpha extract " +
"-draw 'fill black polygon 0,0 0,#{radius} #{radius},0 fill white circle #{radius},#{radius} #{radius},0' " +
"\\( +clone -flip \\) -compose Multiply -composite " +
"\\( +clone -flop \\) -compose Multiply -composite " +
"\\) -alpha off -compose CopyOpacity -composite #{out_pic}"
`#{cmd}`
Source: http://www.imagemagick.org/Usage/thumbnails/#rounded

Facebook doesn't modify pictures to have rounded corners. Instead, they use HTML and CSS to apply this image over each user picture: http://www.facebook.com/images/ui/UIRoundedImage.png
If you inspect UIRoundedImage.png, you'll find that each "square" consists of a transparent center, and opaque corners that are meant to match the background on which the user picture will rest. For instance, if the user picture is on a white background, then white opaque rounded corners will be overlaid on the user picture.
The CSS technique for using just a specific part of UIRoundedImage.png is called "CSS sprites". You can read more about it here: http://www.alistapart.com/articles/sprites/

Here are some rounded corners examples: http://www.imagemagick.org/Usage/thumbnails/#rounded_border. You'll need to create a mask of some sort (either by hand or using the drawing tools) and then overlay it onto your image.

Here's the code I wrote to round corners with ImageMagick using Perl. It should port to Ruby fairly easily:
http://article.gmane.org/gmane.comp.video.graphicsmagick.apis/322

Related

Is there a way to darken an image except for a rounded rectangle in ImageMagick?

To demonstrate.
Original:
After ImageMagick:
I have some ideas:
Duplicate the image, crop the duplicate, then flatten the images together
Reverse mask?
Does anyone have any suggestions?
Although this has been successfully answered, I'll offer another simple approach using IMv6...
convert pasta.jpg -fill white \
\( +clone -evaluate set 25% -draw "roundrectangle 20,20 80,80 15,15" \) \
-compose multiply -composite result.png
After reading in the input image, in parentheses it clones the input and uses -evaluate to set the entire clone to 25% gray. A white "roundrectangle" is drawn on that gray image in the area you want to preserve. The mask looks like this...
Then after the parentheses, that mask and the input image are composited with -compose multiply. That leaves the white rectangle area as it was in the original input, and the rest of the image is multiplied by 0.25, leaving it darkened. The result...
This command should work just the same in IMv7 by changing "convert" to "magick". And it should work as well on Windows CLI by changing the continued-line backslashes "\" to carets "^", and removing any backslashes before the parentheses, so this "\(...\)" to this "(...)".
You can do that in Imagemagick by darkening the whole image, creating a round rectangle mask image, then composite the original with the darkened using the mask image.
Input:
convert pasta.jpg \
\( -clone 0 -brightness-contrast -75,0 \) \
\( -clone 0 -fill white -colorize 100 -fill black -draw "roundrectangle 20,20 80,80 15,15" -alpha off \) \
-compose over -composite \
pasta_rect.jpg
Result:

ImageMagick: How to create torn page effect for specifc edges?

The ImageMagick documentation provides guidance on how to create torn page effects (https://www.imagemagick.org/Usage/thumbnails/#torn). However, in their implementation, all edges are torn. Suppose I wish to tear off only the bottom or top part of the image. How can I achieve such a thing using ImageMagick?
Simply grow the top & sides by using -extent operator.
convert zelda.png -background pink -extent 148x138-10-10 extent.png
(Adding pink background for visibility on stack)
Apply the effect from the Usage documentation.
convert extent.png \( +clone -alpha extract -virtual-pixel black \
-spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \) \
-alpha off -compose Copy_Opacity -composite torn.png
Then crop back to original image size.
convert torn.png -crop 128x129+10+10 output.png
Update
If you do not want to use geometry, you can use a combination of -border, -shave & -chop.
convert zelda.png -bordercolor pink -border 10x10 -gravity South -chop 0x10 extent.png
convert extent.png \( +clone -alpha extract -virtual-pixel black \
-spread 10 -blur 0x3 -threshold 50% -spread 1 -blur 0x.7 \) \
-alpha off -compose Copy_Opacity -composite torn.png
convert torn.png -shave 10x -chop 0x10 output.png
.. And of course, this all can be done with one command.
convert zelda.png -bordercolor pink -border 10x10 -gravity South -chop 0x10 \
\( +clone -alpha extract -virtual-pixel black -spread 10 -blur 0x3 -threshold 50% \
-spread 1 -blur 0x.7 \) -gravity Forget -alpha off -compose Copy_Opacity -composite \
-shave 10x -chop 0x10 output.png
There are several ways to create a torn edge effect using ImageMagick. Here is another example command using IM version 6 and *nix syntax. This should apply a torn effect to just the top edge of any input image while keeping the original dimensions of the image.
convert input.png -alpha set -background black -fill white \
\( +clone -colorize 100 -gravity south -chop 0x6 -splice 0x6 \
-spread 6 -paint 2 +transparent white -blur 0x0.5 \) \
-background none -compose dstin -composite torn.png
That creates a white mask inside the parentheses. Then a small amount of the "torn" edge is chopped off and a black strip is spliced on to replace it. The random-ish torn edge is created using "-spread" and "-paint" between the white and black areas of the mask. After that, outside the parentheses, that mask is used to apply the transparent torn area to the input image.
To apply the effect to the bottom edge, just change the "-gravity north" to "-gravity south".
To make the torn edge on the left or right, change the gravity setting to "west" or "east", and change the values of the "-chop" and "-splice" operations from "0x6" to "6x0".
This should work the same way using ImageMagick version 7 by changing the "convert" command to "magick".
To use it in Windows, remove the backslashes that escape the parentheses from "\(...\)" to "(...)", and change the continued line backslashes "\" to carets "^".

Imagemagick arbitrary size/ratio gradient

Is it possible to apply a smooth diagonal gradient overlay from left bottom corner to right upper corner preserving original colors as below?
Might sound as a simple task but the actual image size is not known in prior.
Perhaps this is what you want. Using Imagemagick 6, I create a diagonal gradient with blue in the lower left corner and red in upper right corner and then blend 20%/80% with the original with the gradient.
Imagemagick automatically gets the dimensions of the (cloned/copied) image from %w and %h using the -sparse-color barycentric syntax for creating a gradient. See https://imagemagick.org/Usage/canvas/#diagonal_gradients
input:
convert input.jpg \
\( +clone -sparse-color barycentric '0,%h blue %w,0 red' +write gradient.jpg \) \
-define compose:args=20,80 -compose blend -composite \
result.jpg
In the above, I saved the gradient image just to show it has been created properly:
Alternately, you can set the alpha channel of the gradient to 20% and use compose over.
convert input.jpg \
\( +clone -sparse-color barycentric '0,%h blue %w,0 red' -alpha set -channel alpha -evaluate set 20% +channel \) \
-compose over -composite \
result2.jpg

How can I combine these commands to achieve circular crop in ImageMagick?

How can I combine these commands to achieve circular crop in ImageMagick?
So this command works:
convert -size 200x200 xc:none -fill samia.jpg -draw "circle 100,100 100,1" circle_thumb.png
The above will take a picture and make a circular crop out of it BUT the crop will be based on the upper left corner of the picture not the center of the picture.
This command also works for cropping:
convert *.jpg -resize 200x200^ -gravity Center -crop 200x200+0+0 +repage out.png
The above will make a square crop of an image based on the center of the image.
So what I want to do is to combine both commands.
My aim:
A command that takes a picture as input and makes a circular crop of it based on the center of the picture, not based on the upper left corner of the picture.
Anyone with IM skills who can show a dude how to resolve this?
Vesa
Ubuntu 15.10
Update:
I tried Mark Setchell's solution below but got the following error message:
axx#axx-VPCEA3S1E:~/Desktop/circular-crop$ magick samia.png \( +clone -threshold 101% -fill white -draw 'circle %[fx:int(w/2)],%[fx:int(h/2)] %[fx:int(w/2)],%[fx:80+int(h/2)]' \) -channel-fx '| gray=>alpha' circle.png
magick: no decode delegate for this image format `PNG' # error/constitute.c/ReadImage/509.
magick: no image to apply a property "%w" # warning/property.c/GetMagickPropertyLetter/2561.
magick: unknown image property "%w" # warning/property.c/InterpretImageProperties/3499.
magick: no image to apply a property "%h" # warning/property.c/GetMagickPropertyLetter/2449.
magick: unknown image property "%h" # warning/property.c/InterpretImageProperties/3499.
magick: no image to apply a property "%m" # warning/property.c/GetMagickPropertyLetter/2480.
magick: unknown image property "%m" # warning/property.c/InterpretImageProperties/3499.
axx#axx-VPCEA3S1E:~/Desktop/circular-crop$
This question gets asked a lot.
Given an image larger than circle.
convert -size 300x300 plasma: input.png
We can draw a shape, convert values to alpha channel, and compose it over the input image.
convert input.png \
-gravity Center \
\( -size 200x200 \
xc:Black \
-fill White \
-draw 'circle 100 100 100 1' \
-alpha Copy \
\) -compose CopyOpacity -composite \
-trim output.png
Now if your planing to crop many resources, I would highly suggest creating a mask once. The reuse the mask as needed.
convert -size 200x200 xc:Black -fill White -draw 'circle 100 100 100 1' -alpha Copy mask.png
for f in $(ls *.jpg)
do
convert $f -gravity Center mask.png -compose CopyOpacity -composite -trim ${f}_output.png
done
Not sure about cropping circles, but if you want to make all but a central circle transparent, you can do this...
Start image
Extract a circle with radius 80, using:
magick start.png \( +clone -threshold 101% -fill white -draw 'circle %[fx:int(w/2)],%[fx:int(h/2)] %[fx:int(w/2)],%[fx:80+int(h/2)]' \) -channel-fx '| gray=>alpha' circle.png

Replace Colors in Image with Transparency

How do I replace a color in an image which contains transparency with ImageMagick, but afterwards retain the transparency of the original image.
This is very useful for batch-changing of colors in icons.
Updated Answer
Option 1
A simpler option might be like this:
convert start.png -alpha deactivate -fill blue -opaque red -alpha activate result.png
which changes this:
to this:
Option 2
Another option, which uses an in-memory copy of the image, can also avoid the need to create 2 processes and write an intermediate file to disk:
convert start.png -write MPR:orig \
-alpha off -fill blue -opaque red \
MPR:orig -compose CopyOpacity -composite result.png
Option 3
Yet another method, that uses clone instead of MPR:
convert start.png \
\( +clone -alpha off -fill blue -opaque red \) \
+swap -compose CopyOpacity -composite result.png
Original Answer
If I create an image that contains transparency like this:
convert -size 400x400 xc:none -fill red -draw "rectangle 10,10 100,100" -fill blue -draw "rectangle 200,200 300,300" -bordercolor black -border 5 start.png
I'll get this (I am showing it overlaid on a checkerboard just to visualise the transparency):
If I now run this
convert start.png -fill yellow -opaque red result.png
I'll get this (again overlaid on a checkerboard):
Not sure why you need a more complicated, 2-stage process - or have I misunderstood your question?
convert file-in.png -alpha off -fill REPLACEMENT -opaque COLOR file-out.png
then
convert file-out.png file-in.png -compose CopyOpacity -composite PNG32:file-final.png

Resources