Captioning all frames of a gif - image-processing

I have a simple bash script to caption still images (jpg, png...) but it completely fails when given an animated gif. The error is convert: unable to write pixel cache '/tmp/magick-[random chars]': No space left on device # error/cache.c/WritePixelCachePixels/5854. There are many questions similar to mine, however they use specific coordinates to determine where the text should be placed (at least, I think). My script creates a dynamically sized caption area for the text to be written to. The image is appended to the bottom of the caption area (or the caption area is prepended to the top of the image, however you want to think about it.)
#!/bin/bash
input=$1
caption=$2
output=$3
wd=`convert $input -format "%w" info:`
convert \( -size ${wd}x -background white -gravity north -fill black -font FuturaBT-ExtraBlackCondensed -pointsize $(($wd/17)) \
caption:"$caption" \) \
$input \
-append $output

You can also do this in Imagemagick.
convert anim.gif -coalesce \
-gravity north -background white \
-splice 0x18 -font Arial -pointsize 12 -annotate +0+0 'THIS IS A TEST OF CAPTIONING TEXT' \
-layers Optimize anim3.gif

In Imagemagick you will need to create a text image from your caption and then use -layers composite to apply it to your animation.
Input GIF Animation:
Imagemagick 6 Unix Syntax:
convert \( anim.gif -coalesce \) null: \( -size 100x -background white -gravity north -fill black caption:"THIS IS A TEST OF CAPTIONING TEXT ON AN ANIMATION" \) -compose over -layers composite -layers optimize anim2.gif
For Windows, remove the \s
For Imagemagick 7, change convert to magick.

Related

How to handle multiple elements with imagemagick cli?

We need to put 'information bar's to thousands of image files. For like a week or so i'm trying to learn imagemagick but i just couldn't figure this many elements out so i wanted to ask for a help here.
I get the idea of '-/+append'ing elements and swapping between them but when it comes to 3x3 matrix cells and text/image mixings, i just can't do it. As an example, i can get the 3 rows appended and a column next to it but i can't get to the next step of 'appending 2 more rows together then put them as a column block again' because when i try, all those append gets right or bottom as a whole image.. Well, you will get the idea when you see my brief image below..
magick.exe -size 150x100 -gravity center caption:"txt2" caption:"txt3" caption:"txt4" \
-append -size 94x294 xc:white -border 3 -swap 0,1 \
+append outoutout.jpg
FYI, height/width of rows/columns are there just for example not important.. And here comes MSPaint skills:
You have to create each section separately using parenthesis processing. Then if you want append them appropriately. Alternately, you can create a background image and compose ... -composite each image into its correct location.
Here is an example in ImageMagick using the second method.
Unix Syntax:
magick -size 400x400 xc:white \
\( barn.jpg -crop 400x200+0+0 +repage \) \
-geometry +0+0 -compose over -composite \
\( -size 100x200 xc:white -shave 5x5 -bordercolor black -border 5 \) \
-gravity northwest -geometry +0+200 -compose over -composite \
\( -size 100x200 -background white -gravity center -fill black \
-font Candice label:"Text1\n\nText2\n\nText3" \) \
-gravity northwest -geometry +100+200 -compose over -composite \
\( -size 100x200 -background skyblue -gravity center -fill red \
-font Arial label:"First_line\n\n\nSecond_line" \) \
-gravity northwest -geometry +300+200 -compose over -composite \
result.png
See for example:
parenthesis processing
appending
convert ... -composite

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 "^".

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

Chain 2 imagemagick commands

I would like to add a logo and some text to an image.
I can achieve this through the following:
// Add logo
composite -geometry +10+20 logo.png input.jpg \
output_with_logo.jpg
// Add text
convert output_with_logo.jpg -font Arial -pointsize 20 \
-draw "fill black text 20,50 'Test'" \
final.jpg
However I'm wondering if I can chain these 2 commands together so I can work from the same source file at once, instead of saving out staged versions of the image.
I've tried:
convert -font Arial -pointsize 20 \
-draw "fill black text 20,50 'Test'" \
-composite -geometry +10+20 input.jpg logo.png \
final.jpg
However this creates 2 "Test" strings on the image
Like this:
convert input.jpg logo.jpg -geometry +10+20 -composite -font Arial -pointsize 20 -draw "fill black text 20,50 'Test'" final.jpg
Rather than use the composite command which won't let you add text, use the convert command and its -composite operator which does the same thing. So, I am saying:
composite A.jpg B.jpg result.jpg = convert A.jpg B.jpg -composite result.jpg
Then, once you have done the compositing, you can add the text afterwards - exactly as you had it.

Appending a label of variable width to one with a fixed size

I am trying to use an Imagemagick command to create a single-letter text label, give it a shadow, place it on the left side of a fixed-size canvas area, and then append this it another label of fixed height but unknown width. So, the desired result is a single letter on the left side of the final transparent PNG, and another label set about 100px to the right of the origin, e.g. this mockup:
I have all of this working in the following command, except that the shadowed text label is not in a fixed size box (should be 100px by 25px). Here's the result:
I think that what I need to do is to turn off the -trim option somehow, but I'm not sure how to do that. +trim is not a valid option, and +repage doesn't do it.
convert \
\( -background transparent \
\( -gravity west -fill lavender -font Constantia.ttf \
-pointsize 12 label:'x' -trim \
\( +clone -background black -shadow 100x3+0+0 -channel A -level 0,50% \
+channel \) \
+swap +repage -gravity center -composite \) \
-size 100x25 -gravity west \) \
\( -size x25 -fill black -background transparent -font MyriadPro-Semibold.otf \
-pointsize 15 label:'Long legend for x' -gravity west \) \
+append -strip legend_test.png
(The trim option is needed to get the height down to 25px--the shadow operation generates too large a vertical extension otherwise. EDIT: And I guess I was wrong above--even w/o the -trim anywhere in the command, the fixed-size image I'm hoping for doesn't work out.)
Hm, looks like there isn't much of a community for ImageMagick left here. I posted to the ImageMagick phpBB board and was able to put together an answer. Briefly:
The -trim option is not an option that affects every image after it is invoked. Instead, it is essentially a command that executes immediately.
The -extent option can be used to increase or decrease an image to a desired size. Apparently the -size command, which I used in my original code, can only be used to set the initial size of an image, not to change the size of an image that already exists.
Here is the final working command:
convert \
\( -background transparent -extent 100x25 -gravity west \
\( -fill lavender -font Constantia.ttf \
-pointsize 12 label:'x' -trim -extent 100x25 -gravity west \
\( +clone -background black -shadow 100x3+0+0 -channel A -level 0,50% \
+channel \) \
+swap +repage -gravity center -composite \) \
-background transparent -extent x25 \) \
\( -size x25 -fill black -background transparent -font MyriadPro- Semibold.otf \
-pointsize 15 label:'Long legend for x' -gravity west \) \
+append -strip legend_test.png

Resources