What I'm trying to do is use ImageMagick to create a border on an image.
It's a simple process, I can do it manually with hard-coded values, but I want it to be smart.
What it needs to do, is to be able to simply define what image you want the border on, then the script is to run through, get the dimensions of the image, then resize the border image I have to those dimensions, and slap the border on the top.
To do so, from my basic understanding, I'll have to store the width and height from the image as variables. The closest I've gotten (actually getting the info) is
identify "image.png"
That spits out the info that I need, but I need to store the width/height into variables to use them in later processes.
I found the following code from https://superuser.com/questions/323970/how-can-i-get-the-image-dimensions-of-a-targa-file-through-a-batch-script
(NOTE: My .bat file is called "imagecheck.bat"
identify -format "imagecheck2.bat %w %h" image.png > temp.bat
temp.bat
From what the poster of that code said, it will get the width and height (%w and %h) from image.png, then store it in imagecheck2.bat as variables that I can access as %1 (for %w) and %2 (for %h)
So, with that being said, inside imagecheck2.bat, I had
#echo off
echo The parameters were: %1 and %2
pause
And it prints out
The parameters were: and
This should be such a simple thing; any ideas what I'm missing?
Thanks in advance.
Here is a way that this can be done without the use of any auxiliary files.
for /f "tokens=1-2" %%i in ('identify -ping -format "%%w %%h" logo:') do set W=%%i & set H=%%j
echo width: %W%
echo height: %H%
Replace "logo:" with the filename of your image.
That said, I strongly recommend not using MS Batch, as the more complex your program gets, the more ridiculous the code will get.
By the way, the use of the -ping flag in that identify command greatly speeds up the operation because it tells identify not to load the whole image into memory, just enough of it to figure out the dimensions.
Rather than using ImageMagick, you can simply pull the width and height out of the PNG. They are in known locations and each is a 4-byte integer in network byte order (most significant byte first). The offsets from the beginning of the file are
signature: bytes 0-7
IHDR length: bytes 8-11
"IHDR": bytes 12-15
width: bytes 16-19
height: bytes 20-23
Related
I am using the following command within a batch script to, hopefully, eventually programmatically create simple video slideshows with transitions:
melt 131.jpg 132.jpg 133.jpg ttl=75 -attach crop center=1 -filter luma cycle=75 duration=25 -transition mix -consumer avformat:out.mp4 frame_rate_num=30 frame_rate_den=1
Most of this command is an adaptation for Windows of this command on the MLT website blog (with the exception of the part that scales and transforms the image). For some reason when I run this, however, the output video file is 25 minutes long!
I have two main questions:
a. How do I properly control the duration of each image in the video? I have experimented quite a bit with changing the parameters and I have a semi-decent understanding of what they all mean (I am a newbie to MLT but I figured that there's no way to do something like this easily in FFMPEG alone). The only way I have found to decrease the duration with any amount of control is to increase the output framerate to absurd numbers (which, of course, is not ideal as it's a massive waste of time and energy and still doesn't really solve the issue).
b. How do I use a wildcard to input all the .jpg files in a folder on Windows? I tried adding *.jpg but that didn't work and I don't know how else to do it within a batch script (I tried using the following code to get the file names as a variable, but I wasn't able to get string concatenation working correctly because it only outputs the final file name)
set files=
for /r %%i in (*.jpg) do (
echo %%i
set files=%files% "%%i"
)
echo %files%
Thank you for any suggestions!
When you specify a .jpg file, melt automatically chooses a producer internally. Depending on your environment and version, that producer will either be the qimage or pixbuf producer.
Both producers offer a "ttl" parameter to specify the duration of the image (in frames) for image sequences
https://mltframework.org/plugins/ProducerQimage/#ttl
https://mltframework.org/plugins/ProducerPixbuf/#ttl
In the example you linked, an image sequence is created by using the special syntax: photos/.all.jpg ttl=75
In your example, you specify a specific file name. So an image sequence is not created. Instead, a new producer is created for each file. The default length for a producer is 15000 frames.
https://github.com/mltframework/mlt/blob/master/src/framework/mlt_producer.c#L102
The length can be specified in the command line.
melt 131.jpg length=100 132.jpg length=100 133.jpg length=100
Change
set files=%files% "%%i"
to
CALL set "files=%%files%% "%%i""
This uses a subsidiary process to concatenate your filenames.
I have no idea about the solution to your other question.
I have two separate folders with equal number of images from microscopy (134 images in each folder). These are two different dyes for a specific cells. What i want to do is merging each image from one folder with its corresponding image from another folder i.e. first image of the folder a with first image of folder b and so on.
i have been trying to do this work, but since each image has a different name, i can not finish this job successfully by Batch processing. Can anyone help?
Thnkas
I need to merge channels from the two images on the left to get the image on the right by using ImageJ --> Image --> Color --> Merge channels
Using C1 (red) and C3 (blue) in the settings.
[1]: https://i.stack.imgur.com/OUKkg.jpg
As you didn't raise any objection to my suggestion of using ImageMagick, I will show you how to do it using that.
As you didn't provide any images, let's assume you have two directories called A and B with PNG files in A that you want to use as the red channel and PNG files in B that you want to use as the blue channel. I'll assume you want a zero/blank green channel.
./A/image1.png
./A/image2.png
./B/image1.png
./B/image2.png
Now, go into A and the basic command for one file is:
cd A
magick image1.png ( +clone -fx 0 ) ../B/image1.png -combine result.png
That says... "load image1.png, make a copy of it and fill the copy with zeroes, load ../B/image1.png and combine them assuming the first is red, the second is green and the third is blue, and save them as result.png".
Hopefully you can get that working. If it does what you want, we can work on a batch version. I don't use Windows, so I would write this on Linux:
#!/bin/bash
for f in *png ; do
echo "Combining $f (as Red), zero (as Green) and ../B/$f (as Blue) to make res-$f"
magick $f \( +clone -fx 0 \) ../B/$f -combine res-$f
done
I know a dangerously small amount of Windows BATCH script, so I'll do my best to guess how it will look. Save it as GO.BAT:
FOR %%G IN (*.png) DO (
ECHO %%G
magick %%G ( +clone -fx 0 ) ../B/%%G -combine res-%%G
)
If I load your "image" into Photoshop and cut out the salient parts and trim the 112 pixels off the second image to make it the same size as the first and then reverse the order and combine them using the commands suggested, I get:
I have made this script that is supposed to change the color of text depending on how much space your C drive has. But it only changes to the color mentioned. For example if I put
:Red
and then
:Blue,
it would only go to red and ignore the blue section.
This is the code for my script. Please let me know how to fix it if you can.
#echo off
title Disk Space Calculator
:Welcome
echo Welcome to the Disk Space Calculator (DSC)! This program will change colour depending on disk space. For example...
echo 2TB - 1TB Cyan
echo 1TB - 750GB Blue
echo 750GB - 500GB Green
echo 500GB - 250GB Yellow
echo 250GB - 100GB Orange
echo 100GB or less Red
echo This program is recommended for disk with 2TB or less.
echo Please not that available space will be measured in bytes.
pause
goto Calculation
:Calculation
cls
FOR /F "tokens=3 USEBACKQ" %%F IN (`dir /-c /w C:`) DO set "size=%%F"
echo Your disk has %size% bytes of space
if %size%=="2199023255552" goto Cyan
if %size%=="1099511627776" goto Blue
if %size%=="805306368000" goto Green
if %size%=="536870912000" goto Yellow
if %size%=="268435456000" goto Orange
if %size%=="107374182400" goto Red
:Cyan
color b
pause
exit
:Blue
color 1
pause
exit
:Green
color a
pause
exit
:Yellow
color e
pause
exit
:Orange
color 6
pause
exit
:Red
color 4
pause
exit
Color (Understanding Control Flow)
As Compo mentioned, all your size tests against the constants do not match and therefore the control flow does not branch to any of your defined "color jump points". The control flow just continues to execute the next statements which are in the following :Cyan section in your given example. Then that color is applied and the execution stops at the exit statement of the Cyan section.
Usually you put a "default branch" after the rows of many comparisons to avoid the control flow pass by into unwanted parts of your script.
Example Snippet:
[...]
if "%size%" == "536870912000" goto Yellow
if "%size%" == "268435456000" goto Orange
if "%size%" == "107374182400" goto Red
goto nomatch
:nomatch
echo Your drive size '%size%' did not match any of the known constants.
pause
exit
:Cyan
[...]
In the "nomatch" section you often times print some help about the usage of your script or some copyright and version info, as you like.
Drive Sizes (Computing with large numbers)
Your project is not the easiest to be realized with a batch script.
Unfortunately batch scripts are restricted to integer artithmetics. This means, the largest number you can process in integer comparisons is 2^32 (One Integer has 32 Bit) which is short over 4 billion (exactly 4,294,967,296).
Your attempt on comparing drive sizes of Gigabyte to Terabyte scale in numbers representing single Bytes will always result in an error message, if the number of bytes exceed this 4 billion limit which is only about 4 GB - what a bummer! :(
The only way to check on large drive sizes inside a batch file is to get the values in Mega- or Gigabytes scale. Even a 2TB drive would "just" have about 2000 GB which is well within the range of 4 billion. Doing 2TB in Megabytes would be 2,000,000 MB which would stay under the limit as well and gives a little more accurate numbers, but not down to the last byte.
Now, to "recompute" the long numbers into shorter Gigabyte values you need to resort to String manipulation. The idea is that 2TB in Bytes (=2199023255552) can be shortened by the last 9 digits and the result is roughly in GB, in this case the result would be 2199 GB.
To cut the numbers last digits refer to this principle: %variablename:~X,Y% which is documented in the help for set (type set /? inside a cmd.exe window to see the documentation).
The mentioned syntax allows cutting strings from a starting position X with a length of Y characters (or digits for that matter). Conveniently, you also can specify negative lengths, which means "to the last but Y characters". You would therefore use somehting like set size_gb=%size:~0,-9% to cut your size String (the first digit has the index position 0).
If you have numbers smaller than 1 Gigabyte the result would be an empty String ("") since you essentially cut away every digit.
With this knowledge you can build up something like this
if not "%size:~0,-9%" == "" (
set size_gb=%size:~0,-9%
echo Size in GB is: %size_gb%
)
I hope you can get your script to work from there on your own. I wish you best of luck and much fun on learning and experiencing new things with your project :)
By the way: Also check out if /? on the command line to read the documentation about comparisons. You might want to compare sizes with "greater than" logic (GTR, >=) instead of just "equal to" (EQU, ==).
I just started coding with Batch a couple weeks ago, a couple hours a day while at work.
I'm writing a script to auto-launch and auto-create dated files. I thought it would be nice to try something "fun".
What I'm trying to do is have my main script save a configuration file with the Batch color code to call upon later/first start and change itself to the previously saved color code. Preferably with a text file.
I've tried using the global variable thing. I think our IT has that disabled as I cannot share variable states between scripts. I haven't tried to enable it. I should also mention we are on Windows 7.
I have since gone the route of creating a colors.bat with the below example code within. I have applied the redirection to my main script to save the file after asking the user for a color code that gets applied to a variable. Right now this Batch file is called upon at a first start in the main script, later I will add a statement to check if the file exists or not.
color 5e
Instead I would prefer a text file that can be called upon or perhaps even a file without a container to prevent backend editing.
However I can't seem to get my script to apply the code inside the text file properly. Below are examples that have failed to apply the color change. Inside the "colors.txt" file is just the Batch compatible color code of "5e" and nothing else.
type colors.txt | color
echo Test
color <colors.txt
echo Test
The above code I have tried with varying placements of the spaces as well.
I've been at this for a few hours now reading up on Batch and Redirection and really anything else of interest. I tried at one point putting the color code as the file name and then trying the Parameter stuff like " %~n1 ". I couldn't figure that out at all.
I hope none of that was confusing. But I'll reiterate, the script as it is right now works. I want to use a .txt container instead of .bat or better yet no container at all. Or even get the global variables enabled, whichever is the best route. I want to call upon this file at script start to apply the color code.
If you have any other questions let me know.
Thanks.
It is fairly straight forward
#echo off
setlocal enabledelayedexpansion
if exist colors.txt (
goto setcolor
) else (
set /p color="Choose color: "
echo !color! > colors.txt
attrib colors.txt +r
endlocal
goto setcolor
)
:setcolor
for /F %%i in (colors.txt) do color %%i
echo Test
pause
The above code check if colors.txt exists, if not it will prompt you for a preferred colour and background colour. Save the code to file and then set it, next time the file will be found and it will just set the colour without re-prompting. We also set attrib +r to make file read-only, if you want to prevent people from editing it, there are ways around it though.
EDIT:
enabledelayedexpansion do cmd /? and you will see
/V:ON
Enable delayed environment variable expansion using ! as the
delimiter. For example, /V:ON would allow !var! to expand the
variable var at execution time. The var syntax expands variables
at input time, which is quite a different thing when inside of a FOR
loop.
I got pretty good at programming in batch. I know its not made for games but i try. I even got that far that i could create a map where things happen. Problem is, i have to specify each and every block. I need relative coordinates.
Here is an example of my Mapping.
set a1=O
set a2=O
set a3=O
set a4=O
set b1=O
set b2=O
set b3=O
set b4=O
set c1=O
set c2=O
set c3=O
set c4=O
:mapping
echo %a1%%a2%%a3%%a4%
echo %b1%%b2%%b3%%b4%
echo %c1%%c2%%c3%%c4%
This will result in:
OOOO
OOOO
OOOO
With this i can create Maps. So for a block to change i have to do "set a2=X"
resulting in
OXOO
OOOO
OOOO
But when creating large games it gets very intense when trying to map.
Is there any way i could get relative coordinates to work?
I was able to create Flappy Bird with this! Here is a Pastebin link to the code of it: http://pastebin.com/h34xdSd8
You can look at it and try it out if you want.(If you do so then exclude the line "if %run% neq true exit", change .exe in line 227 to .bat and create a file named Keyboard.bat with this code: http://pastebin.com/J3EkMR4q.) Its hand written too.
and with that code you can see how hard it is..
Please help, i need relative coordiantes.
Edit:
for %%a in (a b c d e f g) do for /L %%i in (1,1,21) do set %%a%%i=0
This Code worked for me. It will Setup all my Blocks.
One more Problem though. Is there any easy way to use this to move objects? Like when pressing left that my Characted moves one block to the left without me having to specify that block, so relative.
for coordinates you can try:
set /a x=12
set /a y=12
set "q_%x%_%y%=X"
this sets q_12_12 to X.
You can use for for the definition and echoing of the variables (try for /? for help with for).