I'm trying to create a thumbnail sheet (a grid of thumbnails) using ImageMagick with filenames beneath each image. The filenames are long UUID style strings, and using the -title option they overflow into each other to create an unreadable mess. So I thought I'd truncate the names to only show the first n characters. My Bash script is below (running via Git Bash on Windows 11.) I'm not sure whether this is an error in my Bash code, or my use of ImageMagick.
magick montage -verbose -label "$(echo '%t' | cut -c -8)" -font Arial -pointsize 16 \
-background '#000000' -fill 'gray' \
-define jpeg:size=200x200 \
-geometry 200x200+2+2 -tile 8x0 \
-auto-orient \
$(ls -rt *.jpg) \
out.jpg
As far as I can tell the issue I have is with the $(echo '%t' ... part of the script in the first line; it doesn't seem to be piped into the cut command following it. If I use a literal string, eg. echo 'Hello world!', each thumbnail is labeled with what I'd expect, 'Hello wo'. But if I instead use %t (which is ImageMagick's format variable for exposing the base filename of the image) I get the full untruncated filename as if the cut command isn't being applied.
When I use a naked format variable (I've tried %f, the full filename, and %t, the base filename), without echo'ing it into cut, I get the expected untruncated filename. As mentioned, if I echo a literal string (Hello world!) piped into cut, I get the expected truncated output. It is only when I combine the two to echo %f or %t into cut that the truncation fails and I get the full filename. I've also tried piping the echo into sed instead of cut, but yet again the second command is ignored and I get the full filename.
EDIT: An extra little detail I forgot: if I do something funky with the %t, like $(echo 'xxx%t'), I get the filename preceded by xxx -- so it seems the echo is working as expected. But when I try to pipe it into cut, it doesn't truncate.
Any help gratefully received.
I'm not at a proper machine to test this on, but I think it's simpler if you use a two-stage approach. First, generate each of the images with its label, then pipe all those into a second
montagecommand to lay them all out together. In simple terms, that will look like this:I use
MIFFas the intermediate format because it can preserve and propagate any bit-depth, any transparency and all meta-data.So, your actual command will look more like this:
Remember not to put any debug code inside the
forloop that writes onstdoutbecause it will get sent to the finalmontagecommand and confuse it. So, if you want debug statements inside theforloop, usestderrlike this:Note that you may want to add
-extent 200x200to the command inside theforloop to ensure smaller, or different aspect-ratio images are padded up to a full 200x200.If, during the debug stage, you want to see the individual images that are getting sent through the pipe, you can write them to the filesystem as well by changing the
magickcommand in theforloop to write an extra copy: