Is there a way to compose a batch of images with imagemagick? - image-processing

I have a series of PNG images (ABC_a.png, ABC_b.png, XYZ_a.png, XYZ_b.png, BCA_a.png, BCA_b.png etc.) and would like to compose every image of the same code (i.e. the name of an image without _a or _b) within a folder.
Manually, the code would look like this:
magick composite ABC_b.png ABC_a.png ABC.png
magick composite XYZ_b.png XYZ_a.png XYZ.png
magick composite BCA_b.png BCA_a.BCA BCA.png
...
... where a partly transparent image _b would be placed "on top of" _a and the name of the output file losing its _a/_b suffix.
I looked around and tried several apporaches via mogrify or for loops (FOR %i IN (*.png) DO magick composite ...) but couldn't get it automated. Perhaps it would help to use two separate folders and working with the same image names (without the suffix), but I'm not sure...
I appreciate any tips. Please be aware that I'd need to work within the Windows CMD or PowerShell to make it happen.

There can be used the following batch file for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ImageMagick=magick.exe"
if exist "*!*_a.png" goto ExtendedVersion
setlocal EnableDelayedExpansion
for %%I in (*_a.png) do (
set "FileNameA=%%~nI"
set "FileName=!FileNameA:~0,-2!%%~xI"
if not exist "!FileName!" "!ImageMagick!" composite "!FileNameA:~0,-1!b%%~xI" "!FileNameA!%%~xI" "!FileName!"
)
endlocal
goto EndBatch
:ExtendedVersion
echo INFO: Extended version required because of a PNG file with exclamation marks.
for %%I in (*_a.png) do (
set "FileNameA=%%~nI"
setlocal EnableDelayedExpansion
set "FileName=!FileNameA:~0,-2!%%~xI"
if not exist "!FileName!" "!ImageMagick!" composite "!FileNameA:~0,-1!b%%~xI" "!FileNameA!%%~xI" "!FileName!"
endlocal
)
:EndBatch
endlocal
There is defined first the required execution environment with the first two command lines.
Next the environment variable ImageMagick is defined with the file name of this program. It would be best to add the full path because in this case cmd.exe would not need to search for magick.exe in current directory and next in all directories in string value of environment variable PATH using the file extensions in string value of environment variable PATHEXT before each execution of ImageMagick. The usage of the fully qualified file name of ImageMagick would avoid hundreds or even thousands of file system accesses on more than ten PNG files to process.
The IF condition in the fourth command line quickly checks if there is any PNG file with case-insensitive _a in the file name before the file extension .png containing one or more exclamation marks in the file name. The extended version of the processing loop is required if this condition is true.
The standard version enables first required delayed expansion. Then a FOR loop is used to process one PNG file after the other with case-insensitive _a in the file name before the file extension .png.
The current file name without file extension .png is assigned first to the environment variable FileNameA.
Next a string substitution is used to get from the string value of the environment variable FileNameA the file name without the last two characters _a concatenated with the file extension .png assigned to the environment variable FileName.
If there is not already a PNG file not ending with _a in the file name before the file extension, there is next executed ImageMagick with first argument being the corresponding _b.png file determined by using again a string substitution with using the file name string assigned to the environment variable FileName without last character a concatenated with b and the file extension .png and the_a.png file with the file extension as second argument and the file name without _a as third argument.
The command ENDLOCAL after the loop restores the previous environment before enabling delayed expansion and the command GOTO instructs the Windows Command Processor to continue processing the batch file with the command line below the label EndBatch which contains one more ENDLOCAL to restore the environment on starting the batch file processing.
The extended version is nearly the same as the standard version. The difference is that delayed variable expansion is not enabled on assigning the file name of the current _a.png file without the file extension to the environment variable FileNameA. That avoids interpreting the exclamation mark(s) in the file name as beginning/end of a delayed expanded variable reference resulting in a manipulation of the file name string before assigning it to the environment variable as it would happen with delayed expansion already enabled.
The extended version enables next delayed variable expansion inside the loop, does the same as the standard version and restores finally the previous environment before processing the next _a.png file.
The extended version is slower because of the environment variables list copy and the other operations made in background by every execution of SETLOCAL as explained in full details in this answer. The command ENDLOCAL in the loop is required to avoid a stack overflow on processing lots of PNG files.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
echo /?
endlocal /?
for /?
goto /?
if /?
set /?
setlocal /?

Related

Using command line to copy txt of many files and create new txt with all text

So as an early task at a new junior developer position I was asked to go through and update thousands of old parameter data types in various stored procs. I did all the updates and loaded them to the team server and now have to push them into our SQL server so they will compile.
Last night my boss eluded to how I could pull the modified procs into a directory, then use command line to copy all text and create a new txt file that could be opened in SQL to run a mass update basically in batch mode per database.
I have almost no command line experience, can someone give me a quick overview.
My Pseudocode:
Open command line window in my UpdatedProcs folder, copy text from all files in same directory, create new text file containing all of the text (name of new file doesn't matter). Then open in SQL, look for errors one last time, and finally run.
This seems simple but I know nothing about command line.
Thanks for your help.
Use a for /f loop. You don't even need to copy the files from the subdirectory first. This appends all of the text files in the Temp subfolder (C:\Test\Temp) into a file named summary.log in the current folder (C:\Test):
c:\Test>for /f "tokens=*" %a in ("dir temp\*.txt") do type %a >> .\summary.log
summary.log now contains all of the content of the text files in a single file. You can open it with Notepad or any other text editor.
To run from a batch file, simply change the %a to %%a in both places.
c:\Test>copy con mergefiles.bat
for /f "tokens=*" %%a in ("dir temp\*.txt") do type %%a >> .\summary.log
F6 or Ctrl+Z
c:\Temp>mergefiles
Enter
c:\Temp>notepad summary.log
Enter

How to manipulate components of pathnames in Tcl?

I'm writing a reporting script that's part of a portable testing package. The user can unzip the package anywhere on their system, which is fine, but it means I can't hardcode a path.
Let's say that on my system, this script lives at C:/projects/testpackage/foo/bar/script.tcl. I need to set a variable, packageLocation, the path to /testpackage. In this example, it would be C:/Projects/testpackage. But when the user gets the package, he or she could put it anywhere, like so:
C:/Users/whatever/testpackage.
So, how can I call two levels up from the location of my currently running script? In Batch, I could do
:: example.bat
cd %~dp0
cd ../..
set packageLocation=%cd%
In Tcl, I'm lost. I know that the current location of the running script can be called as $::argv0. I've tried using cd ../.., but to no avail. It tries to set packageLocation as "../..C:/Projects/testpackage/foo/bar/script.tcl."
Any help is appreciated. Thanks!
set where [file normalize [file dirname [info script]]]
set parts [file split $where]
set pkgloc [file join {*}[lrange $parts 0 end-2]]
Should do what you want.
It goes like this:
Obtains the directory name of the file from which the current script was read to be evaluated, then normalizes it (replaces ~, .. etc).
Splits obtained full pathname at path separators producing a list of path components.
Extracts a new list from the list of path components containing all them from the beginning except the last two, then joins them back to produce the final name.
If you have Tcl < 8.5, the last line will have to be rewritten:
set last [expr {[llength $parts] - 3}]
set pkgloc [eval [list file join] [lrange $parts 0 $last]]

Unable to concatenate defined string and the text within the path to image file

I got a problem with setting a path to image within the resource file (.rc).
For some reasone it was not possible to concatenate defined string and the text.
e.g.
File1:
#define Path "Brand_1"
File2:
#include File1
Logo BITMAP Path "\Logo.bmp"
Borland resource compiler (5.4) throws error message: 39: Cannot open file: Brand_1
EDIT:
My question would be: Is is possible to combine the path for loading image using resource string variable and a string (file name).
Also, project I'm working on relates to a file (Logo.bmp) being present in two locations. I would like to have a switch (.bat file) to generate a different resouce file depending on requirements.
Thanks.
BRCC32 accepts -i as search path seperated by semicolon, so you could create a bat file like this
compile_res.bat
brcc32 -ic:\mypath1;c:\mypath2 resource_script
and you define your resource_script as normal, for ex:
resource_script.rc
myImg BITMAP Logo.bmp
myDOC RCDATA mydoc.doc
when you run the compile_res.bat, it will run the brcc32.exe with the search path, and having the bat file saves you from retyping the search path every time.
You're not concatenating anything. You're compiling to Logo BITMAP "Brand_1" "\Logo.bmp", and "Brand_1" isn't a valid path to a bitmap file.
#define in the resource compiler acts sort of like find/replace in a text processor - not exactly, but close enough in this case.
You might get by (untested) with removing the quotes and space between them, as long as there are no space characters in either the path or filename; otherwise, you're probably out of luck. (Not sure what you're trying to accomplish, anyway.)

Make a relative path in batch file

I have a batch file that I wont know what drive letter it will be as I will be moving around alot.
For example:
The adobe files reside in: J:\Files\New folder\USB\Adob
The batch file is executed from: J:\Files\New folder\USB\USBSTICK
So I tried the code:
xcopy /s /y "%~dp0\..\..\USB\Adob\*" "C:\Program Files\"
But it will not copy the files. How can I get it dynamic?
As the drive letter seems to be the relative part of your scenario. I believe this should work better for you, unless I have misunderstood you.
xcopy /s /y "%~d0\Files\New folder\USB\Adob\*" "C:\Program Files\"
For more variables that you can use follow these steps:
From CMD, type for /? and read at the bottom.
%~I - expands %I removing any surrounding quotes (")
%~fI - expands %I to a fully qualified path name
%~dI - expands %I to a drive letter only
%~pI - expands %I to a path only
%~nI - expands %I to a file name only
%~xI - expands %I to a file extension only
%~sI - expanded path contains short names only
%~aI - expands %I to file attributes of file
%~tI - expands %I to date/time of file
%~zI - expands %I to size of file
%~$PATH:I - searches the directories listed in the PATH
environment variable and expands %I to the
fully qualified name of the first one found.
If the environment variable name is not
defined or the file is not found by the
search, then this modifier expands to the
empty string
The modifiers can be combined to get compound results:
%~dpI - expands %I to a drive letter and path only
%~nxI - expands %I to a file name and extension only
%~fsI - expands %I to a full path name with short names only
%~dp$PATH:I - searches the directories listed in the PATH
environment variable for %I and expands to the
drive letter and path of the first one found.
%~ftzaI - expands %I to a DIR like output line
In the above examples %I and PATH can be replaced by other valid
values. The %~ syntax is terminated by a valid FOR variable name.
Picking upper case variable names like %I makes it more readable and
avoids confusion with the modifiers, which are not case sensitive.
From my understanding of your hierarchy, this would also work:
xcopy /s /y "..\Adob\*" "C:\Program Files\"
since J:\Files\New folder\USB is a common prefix, and you're running the batch file from J:\Files\New folder\USB\USBSTICK, this should work no matter what drive letter you're dealing with.
I'm not sure that I fully understand your problem. But it seems to me that there are several solutions that would solve the problem as I understand it.
If the paths are always fixed, but only the drive letter may vary, you could just use a relative path:
xcopy /s /y "..\Adob\*" "C:\Program Files\"
Calling the batch program from any drive would then work as expected provided the batch file always exists in USBSTICK which exists in the same dir as Adob.
If the source path can vary, just replace the varying part with a parameter, and call the batch file with the correct path:
xcopy /s /y "%1\*" "C:\Program Files\"
Calling the batch program from any drive AND location would then work as expected when you supply it with the correct path:
xcopybatch J:\Files\New folder\USB\Adob
Try without the "\", as it is part of %~dp0. I mean, the contents of %~dp0 will always end with a "\".
Example:
xcopy /s /y "%~dp0..\..\USB\Adob\*" "C:\Program Files\"
Edit
Just in case ...
is Adob\* or Adob\*.* ??

DOS batch: get last folder from relative path

I have the following values in a DOS batch file (for example...):
..\Apple\Jones
..\Banana\Smith
..\Pear\Wilson
I need to extract the last name values ("Jones", "Smith", "Wilson") from each value. What one technique can I use that will always give me these substring values?
According to this topic : What is the best way to do a substring in a batch file?
I suggest you to use
%~n0
I already wrote a function for that. You give it any path and it returns you only it's filename or pathname. Works for any path: Url, Windows path, Unix path, etc...
Copy this function at the end of your batch script: (Instructions below)
rem ===========================================================================
:Name_From_Path
SetLocal
set _TMP_FOLDERNAME=%1
for %%g in ("%_TMP_FOLDERNAME%") do set _TMP_FOLDERNAME=%%~nxg
EndLocal & set _Name_From_Path=%_TMP_FOLDERNAME%
goto :EOF
rem ===========================================================================
Usage:
CALL :Name_Of_Path ..\Apple\Jones
ECHO %_Name_From_Path%
Result: Jones

Resources