Reputation: 150
I have a batch file that processes scanned PDFs using ghostscript. One of the user prompts is for the resolution of the desired output. I wrote a crude autodetect routine like this:
for /f "delims=" %%a in ('findstr /C:"/Height 1650" %1') do set resdect=150
for /f "delims=" %%a in ('findstr /C:"/Height 3300" %1') do set resdect=300
for /f "delims=" %%a in ('findstr /C:"/Height 6600" %1') do set resdect=600
echo %resdect% DPI detected.
%1 is the filename passed to the batch script.
This should return the the highest resolution detected of some common sizes we see. My question to the community is: Is there a faster or more efficient way to do this other than search the file multiple times?
Upvotes: 0
Views: 166
Reputation: 150
For the record, the final code was:
setlocal enabledelayedexpansion
set resdetc=0
for /f "delims=" %%a in ('findstr /C:"/Height " %1') do (
set "line=%%a"
set "line=!line:*/Height =!"
for /f "delims=/ " %%b in ("!line!") do set "hval=!hval! %%b"
)
for %%a in (1650,3300,6600) do @(
echo " %hval% " | find " %%a " >nul && set /a resdetc=%%a/11
)
if %resdetc%==0 SET resDefault=3
if %resdetc%==150 SET resDefault=1
if %resdetc%==300 SET resDefault=3
if %resdetc%==600 SET resDefault=6
ECHO.
ECHO Choose your resolution
ECHO ----------------------
ECHO 1. 150 4. 400
ECHO 2. 200 5. 500
ECHO 3. 300 6. 600
ECHO.
IF NOT %RESDETC%==0 ECHO 7. Custom (%resdetc% DPI input detected)
IF %RESDETC%==0 ECHO 7. Custom
ECHO ----------------------
choice /c 1234567 /T 3 /D %resDefault% /N /M "Enter 1-7 (defaults to %resDefault% after 3 sec.): "
IF errorlevel==7 goto choice7
IF errorlevel==6 set reschoice=600 & goto convert
IF errorlevel==5 set reschoice=500 & goto convert
[...]
Thanks everyone for the help!
Upvotes: 0
Reputation: 56208
get the corresponding line to a variable and work with that instead of the whole file. Instead of your three for
loops, you can use just one, when you change the logic a bit:
@echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in ('findstr /C:"/Height " %1') do (
set "line=%%a"
set "line=!line:*/Height =!"
for /f "delims=/ " %%b in ("!line!") do set "hval=!hval! %%b"
)
for %%a in (1650,3300,6600) do @(
echo " %hval% " | find " %%a " >nul && set /a resdect=%%a/11
)
echo %resdect% DPI detected.
A solution with jrepl.bat could look something like:
for /f %a in ('type t.txt^|find "/Height "^|jrepl ".*/Height ([0-9]{4}).*" "$1"^|sort') do set /a dpi==%a / 11
(given, all valid Heights have 4 digits)
Note: for use in batchfiles, use %%a
instead of %a
I barely scratched the surface of jrepl
- I'm quite sure, there is a much more elegant (and probably faster) solution.
Upvotes: 2
Reputation: 67236
You may directly convert the Height value into the highest resolution in a single operation using an array. However, to do that we need to know the format of the line that contain the Height value. In the code below I assumed that the format of such a line is /Height xxxx
, that is, that the height is the second token in the line. If this is not true, just adjust the "tokens=2"
value in the for /F
command.
EDIT: Code modified as requested in comments
In this modified code the Height value may appear anywhere in the line.
@echo off
setlocal EnableDelayedExpansion
rem Initialize "resDect" array
for %%a in ("1650=150" "3300=300" "6600=600") do (
for /F "tokens=1,2 delims==" %%b in (%%a) do (
set "resDect[%%b]=%%c"
)
)
set "highResDect=0"
for /F "delims=" %%a in ('findstr "/Height" %1') do (
set "line=%%a"
set "line=!line:*/Height =!"
for /F %%b in ("!line!") do set /A "thisRectDect=resDect[%%b]"
if !thisRectDect! gtr !highResDect! set "highResDect=!thisRectDect!"
)
echo %highResDect% DPI detected.
Upvotes: 2
Reputation: 34959
Assuming that the value of RESDECT
is the /Height
value divided by 11
, and that no line contains more than one /Height
token, the following code might work for you:
@echo off
for /F delims^=^ eol^= %%A in ('findstr /R /I /C:"/Height *[0-9][0-9]*" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "RESDECT=!LINE:*/Height =!"
set /A "RESDECT/=11"
echo/!RESDECT!
endlocal
)
If you only want to match the dedicated /Height
values 1650
, 3300
, 6600
, you could use this:
@echo off
for /F delims^=^ eol^= %%A in ('findstr /I /C:"/Height 1650" /C:"/Height 3300" /C:"/Height 6600" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "RESDECT=!LINE:*/Height =!"
set /A "RESDECT/=11"
echo/!RESDECT!
endlocal
)
To gather the greatest /Height
value appearing in the file, you can use this script, respecting the aforementioned assumptions:
@echo off
set "RESDECT=0"
for /F delims^=^ eol^= %%A in ('findstr /R /I /C:"/Height *[0-9][0-9]*" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "HEIGHT=!LINE:*/Height =!"
for /F %%B in ('set /A HEIGHT/11') do (
if %%B gtr !RESDECT! (endlocal & set "RESDECT=%%B") else endlocal
)
)
echo %RESDECT%
Of course you can again exchange the findstr
command line like above.
Here is another approach to get the greatest /Height
value, using (pseudo-)arrays, which might be faster than the above method, because there are no extra cmd
instances created in the loop:
@echo off
setlocal
set "RESDECT=0"
for /F delims^=^ eol^= %%A in ('findstr /R /I /C:"/Height *[0-9][0-9]*" "%~1"') do (
set "LINE=%%A"
setlocal EnableDelayedExpansion
set "HEIGHT=!LINE:*/Height =!"
set /A "HEIGHT+=0, RES=HEIGHT/11" & set "HEIGHT=0000000000!HEIGHT!"
for /F %%B in ("$RESOLUTIONS[!HEIGHT:~-10!]=!RES!") do endlocal & set "%%B"
)
for /F "tokens=2 delims==" %%B in ('set $RESOLUTIONS[') do set "RESDECT=%%B"
echo %RESDECT%
endlocal
At first all heights and related resolutions are collected in an array called $RESOLUTIONS[]
, where the /Height
values are used as indexes and the resolutions are the values. The heights become left-zero-padded to a fixed number of digits, so set $RESOLUTIONS[
return them in ascending order. The second for /F
loop returns the last arrays element whose value is the greatest resolution.
I do have to admit that this was inspired by Aacini's nice answer.
Upvotes: 4