Process Images in Sub-Directories

Questions and postings pertaining to the usage of ImageMagick regardless of the interface. This includes the command-line utilities, as well as the C and C++ APIs. Usage questions are like "How do I use ImageMagick to create drop shadows?".
Post Reply
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Process Images in Sub-Directories

Post by FUrn »

I'm using the following ImageMagick Windows code to transform all images into square images:

Code: Select all

for filename in *.jpg; do
    magick "$filename" -gravity Center -background White -extent "%[fx:max(w,h)]x%[fx:max(w,h)]" "converted-$filename"
done
When I run this 'convert.sh' file, it processes all images stored in the same directory as my .sh file. However I have a large number of sub-directories containing images, and I'd like to maintain this directory structure. How do I adapt the above code to process all images in sub-directories too?

I came across using a FOR /R loop as a possible solution, but am not sure how to merge this into the code I'm currently using? I'd need it to process images in sub-directories and maintain the folder structure (i.e. not move process images to the root folder).

Apologies if this is a rather simple question, but I'm quite new to ImageMagick and command line image processing! Thanks for bearing with me...
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Process Images in Sub-Directories

Post by fmw42 »

You code is Unix code, not Windows scripting. So are you using Windows 10 Unix? For loops are different in Unix than in Windows. In either case, you will need to loop over each subdirectory and process as above.

Please, always provide your IM version and platform when asking questions, since syntax may differ.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Process Images in Sub-Directories

Post by snibgo »

Your "for filename in *.jpg; do" is in a bash script.

"for /R" is a Windows command.

I suggest that you don't try to mix the two languages, bash and Windows. This is possible but can be confusing, especially if you don't know both languages.

For your problem, I suggest you nest your bash commands inside an outer bash loop. That loop might be something like "for VAR in $(ls -d */)".
snibgo's IM pages: im.snibgo.com
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Process Images in Sub-Directories

Post by FUrn »

Sorry - I’m quite new to command line processing!
I’m using IM7 on Windows, and this is indeed a Bash script.
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Process Images in Sub-Directories

Post by FUrn »

snibgo wrote: 2019-03-31T16:57:38-07:00 For your problem, I suggest you nest your bash commands inside an outer bash loop. That loop might be something like "for VAR in $(ls -d */)".
Thanks for this. Would you be so kind as to explain the loop you’ve written out? I’d like to understand it, both to advance my knowledge but also to adapt it to the case at hand if need be.
User avatar
fmw42
Posts: 25562
Joined: 2007-07-02T17:14:51-07:00
Authentication code: 1152
Location: Sunnyvale, California, USA

Re: Process Images in Sub-Directories

Post by fmw42 »

FUrn wrote: 2019-03-31T17:00:46-07:00 Sorry - I’m quite new to command line processing!
I’m using IM7 on Windows, and this is indeed a Bash script.
So are you using Windows 10 Unix? If not, then bash scripting should not work.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Process Images in Sub-Directories

Post by snibgo »

"VAR" is a poor choice of name. Use "ONEDIR" instead.

Try running "ls -d */". This writes a list of directories. Putting it inside "$(...)" runs the command, replacing it within the outer command by its output, the list of directories. "for ONEDIR in $(ls -d */) ..." is a loop that will set ONEDIR to each directory in turn.

EDIT: You might also use "pushd $ONEDIR" and "popd".

I suggest you find bash documentation. On my computer (Windows 8.1 with Cygwin) when running bash, "man ls" gives the manual entry for "ls", and "man bash" gives bash builtins, including "$(...)" and "for" and "pushd" and "popd".
snibgo's IM pages: im.snibgo.com
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Process Images in Sub-Directories

Post by FUrn »

snibgo wrote: 2019-03-31T17:22:59-07:00 "VAR" is a poor choice of name. Use "ONEDIR" instead.

Try running "ls -d */". This writes a list of directories. Putting it inside "$(...)" runs the command, replacing it within the outer command by its output, the list of directories. "for ONEDIR in $(ls -d */) ..." is a loop that will set ONEDIR to each directory in turn.

EDIT: You might also use "pushd $ONEDIR" and "popd".

I suggest you find bash documentation. On my computer (Windows 8.1 with Cygwin) when running bash, "man ls" gives the manual entry for "ls", and "man bash" gives bash builtins, including "$(...)" and "for" and "pushd" and "popd".
Thanks snibgo. My code is now:

Code: Select all

for ONEDIR in $(ls -d */); do
    for filename in *.jpg; do
        magick "$filename" -gravity Center -background White -extent "%[fx:max(w,h)]x%[fx:max(w,h)]" "$filename"
    done
done
However I'm getting an error stating 'magick.exe: unable to open image '*.jpg': Invalid argument @ error/blob.c/OpenBlob/3490.'
As a test, I'm running this in a folder with 2 sub-directories, with each sub-directory containing 4 JPG files. There are no JPGs in the root directory.
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Process Images in Sub-Directories

Post by snibgo »

You've created an outer loop but it has no effect. Your "for filename in *.jpg; do" will loop through all the JPEGs in the same (outer) folder, and there aren't any.

One solution is to have "pushd $ONEDIR" as the first action in the outer loop, and "popd" as the last.
snibgo's IM pages: im.snibgo.com
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Process Images in Sub-Directories

Post by FUrn »

Sorry snibgo, but I really am a beginner at this...please do bear with me. I've tried this:

Code: Select all

for ONEDIR in $(ls -d */); do
    pushd $ONEDIR
    for filename in *.jpg; do
        magick "$filename" -gravity Center -background White -extent "%[fx:max(w,h)]x%[fx:max(w,h)]" "$filename"
    done
    popd
done
But still no luck - I'm getting the error: 'pushd: Sub-Folder: No such file or directory'.
FYI my directory structure is as follows. The root folder is called 'Test (Sub Folders)', and the sub-directories are named 'Sub-Folder 1' and 'Sub-Folder 2'. Inside each of the sub-directories are 4 JPG images.

Can you please let me know where I'm going wrong? Again, apologies for my lack of knowledge in this area...
snibgo
Posts: 12159
Joined: 2010-01-23T23:01:33-07:00
Authentication code: 1151
Location: England, UK

Re: Process Images in Sub-Directories

Post by snibgo »

You have spaces in your folder names. I expect my bash code can be changed to allow this, but I suggest you change your folder names to exclude spaces. Spaces in directory or file names are a real pain.
snibgo's IM pages: im.snibgo.com
FUrn
Posts: 20
Joined: 2018-10-30T09:49:10-07:00
Authentication code: 1152

Re: Process Images in Sub-Directories

Post by FUrn »

Worked like a charm, snibgo.
Thanks so much!
Post Reply