I am using Image Magick to overlay a dimmed caption to an image, with IM automatically choosing the best fontsize:
convert -background '#0008' -fill white -geometry +0+330 -size 370x60 caption:$title $image +swap -composite $imageOutput
My problem is that there is not enough space around the text, I would like to add some "padding". I usually do that with the -border option but if I add this to my command above, the caption is not dimmed anymore.
Do you have a solution to create a dimmed caption with enough room around the text?
I have a solution, but it's a bit of a kludge because I had trouble extending or bordering a semi-transparent background. In the end, I just constructed the caption on a black background and bordered it in black, then I tweaked the alpha channel afterwards:
convert -background black -bordercolor black -fill white \
-size 370x60 caption:"This is the title" \
-trim -border 20 -channel A -fx '(lightness/2)+.5' \
-geometry +0+200 background.gif +swap -composite result.png
The only tricky part is -channel A -fx .... The first part means that we are only affecting/modifying the alpha/opacity channel. The 0.5 means that all pixels become at least 50% opaque, and (lightness/2) means that absolutely white pixels, i.e. your lettering, (which will have a lightness of 1) become fully opaque because 0.5+(1/2) totals to one. The point of this is to preserve the anti-aliasing around the edges of the letters to some degree.
Related
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:
I am trying to add a 10px red border to a transparent PNG using ImageMagick, while preserving any existing transparency that might exist within the image. Here is my source image:
If you download and view that image with an image viewer, you'll see that it has a transparent background.
According to everything I've read, the following Imagemagick command should add a 10px red border to the image:
convert input.png -bordercolor red -border 10 output.png
It actually does add the red border to the image, since the output dimensions are 20px larger in both directions. Unfortunately it also changes the background color of the image to red as well. Here is the output file:
I do not want the transparent area to be changed to red. I only want to add a red border around the transparent image.
I've tried using both ImageMagick version 6.9.10-23 (Ubuntu) and 7.1.0 (via CloudConvert API), with the same result. I've spent hours(!) trying to solve this.
What am I doing wrong?
I found the answer in this thread: https://legacy.imagemagick.org/discourse-server/viewtopic.php?t=31843 . Here are the two money quotes:
So, "-bordercolor red -border 2" should create an opaque red image 2
pixels larger than the input, and composite the input over this. As
your input is "-size 100x100 xc:none", the result should be 102x102
opaque red pixels. You might think this is "pretty obviously
incorrect", but it is the documented behaviour.
and
Nevertheless, you can get it to work to have the transparent inside,
if you add -compose copy before -bordercolor red -border 2 in both the
current IM 6 and IM 7. This just may have to be the way to do it from
here on, if there is a good reason for the changed behavior.
Here is the command that produces the result I am after:
convert -background transparent -bordercolor red -compose Copy -border 10 input.png output.png
Here's an answer that fully preserves the transparency
convert input.png +write mpr:INP -alpha extract -morphology dilate disk:10 \\( +clone -fill Black -colorize 100 \\) +swap -compose CopyOpacity -composite mpr:INP -compose Over -composite output.png
From https://legacy.imagemagick.org/Usage/crop/#extent
Here is a simple way to do that in Imagemagick. Change the compose setting from over to copy.
Input:
convert logo_transp.png -compose copy -bordercolor red -border 10 logo_transp_border.png
This is an example PNG image:
it's 50x40 but enlarged here to see it better.
The hex of bottom left and bottom right pixels is F9E4B7
I need to know how many pixels there are on vertical edges from the bottom left and right with almost this color, like 1% fuzz because they are not all exactly F9E4B7 but some are very slightly different.
In this case it would be 20px of each side:
I'll mark the areas which need to be counted just to make it perfectly clear:
I also need to be able to count how many pixels are exactly F9E4B7, which in this case would be 15 left and 20 right, I'll mark the slightly different areas so it's clear where the counter needs to stop:
The way to do that in Imagemagick is to use fuzz to change all your pixels close to that color to white and the rest black. The crop the first or last column and use -fx to get the count from mean*width*height. So for example for the left full column of the whole image, one has
Unix Imagemagick 6 syntax:
convert tan.png -alpha off \
-fuzz 1% -fill white -opaque "#F9E4B7" -fill black +opaque white \
-gravity west -crop 1x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
Windows Imagemagick Syntax:
convert tan.png -alpha off ^
-fuzz 1% -fill white -opaque "#F9E4B7" -fill black +opaque white ^
-gravity west -crop 1x+0+0 -format "%[fx:round(mean*w*h)]\n" info:
Result:
108
To get the right side, use -gravity east.
For exact count, use -fuzz 0
For Imagemagick 7, change convert to magick
Using imagemagick, I want to clean the left side of an image, i.e. make white without cropping. For example cleaning the left-most vertical strip of 25 pixels wide. I figured out how to crop to a given geometry, but I couldn't figure out how to clean without cropping.
Here is my start image, made like this:
convert -size 256x256 gradient:cyan-yellow image.png
Method 1
One way to do it would be to use -fx and set all pixels where the x-coordinate is less than 25 to 1.0 (i.e. white) and leave all other pixels as they are:
convert image.png -fx "i<25?1:u" result.png
Method 2
Another, faster way to do it might be to clone the original image, and scale it down to 25 pixels wide, fill it with white and composite that over the original image:
convert image.png \
\( +clone -scale 25x! -fill white -colorize 100 \) \
-composite result.png
The result is the same.
Method 3
A third way to do it might be to crop the image 25 pixels in from the left side, then splice 25 white pixels back on the left side:
convert image.png -crop +25+0 -background white -gravity west -splice 25x result.png
Method 4
Bit of a kludge, but nearer to what you asked. Here, I guess that your image height doesn't exceed 10,000 pixels and draw a rectangle:
convert image.png -fill white -draw "rectangle 0,0 24,9999" result.png
I guess the proper way to do this is to get the height first then use it:
#!/bin/bash
h=$(convert image.png -format "%[fx:h-1]" info:)
convert image.png -fill white -draw "rectangle 0,0 24,$h" result.png
Here is my code:
#! /usr/bin/env sh
# Generate test image.
convert -size 100x60 xc:blue -fill blue -stroke black -draw "circle 50,30 55,55" in.png
# Make background transparent.
convert in.png -fill none -draw 'matte 0,0 floodfill' -flop -draw 'matte 0,0 floodfill' -flop out.png
# Replace transparent background with green.
mogrify -background green -flatten out.png
# The wrong way.
convert in.png -transparent blue oops.png
mogrify -background green -flatten oops.png
It is based on this snippet: https://snippets.aktagon.com/snippets/558-how-to-remove-a-background-with-imagemagick
Starting with this:
I want to get this:
Not this:
Can I achieve this with a single convert command instead of a convert followed by a mogrify?
I am using ImageMagick 6.8.9-9.
Essentially, you are seeking a "floodfill", like this:
convert in.png -fill green -draw 'color 0,0 floodfill' result.png
That will look at the top-left pixel (0,0) and fill all similarly coloured pixels which are connected to it with green. If your background has slight variations in it, e.g. it's a JPEG, add some fuzz factor
convert in.jpg -fuzz 25% ...
Note that if your circle had touched the top and bottom edges, it would prevent the fill from flooding around to the right side of the diagram. So, let's say you had created your circle like this:
convert -size 100x60 xc:blue -fill blue -stroke black -draw "circle 50,30 50,0" in.png
And then you run the above command, you will get:
If that happens, you can add a single pixel wide border all the way around for the colour to "flow" through first, then flood-fill, and finally remove it later:
convert in.png -bordercolor blue -border 1 -fill green -draw 'color 0,0 floodfill' -shave 1x1 result.png