我一直在搜索SO和谷歌搜索结果差不多一个星期,试图让一个简单的批处理脚本工作。我认为我的问题源于缺乏对批量FOR循环和DelayedExpansion的理解。
在这个主题上有大量相关的问题和答案,但我所看到的帖子中没有一个能够以对我有意义的方式分解信息
setlocal enabledelayedexpansion
SET /a QUALITY=20
SET /a STEP=5
:loop
convert input.jpg -resize 1080x1080 -quality %quality% -strip ./1080/output.jpg
SET /a quality+=step
for %%G in (./1080/output.jpg) DO (
set filesize=%%~zG
if !filesize! LSS 100000 if !quality! LSS 100 goto loop
)
此代码的目的是转换(ImageMagick)初始压缩质量为20的图像,检查文件大小,并在每次迭代时重新开始稍高质量的设置文件大小小于100KB且质量小于100。
实际上,输出是这样的:
>SET /a QUALITY=20
>SET /a STEP=5
>convert input.jpg -resize 1080x1080 -quality 20 -strip ./1080/output.jpg
>SET /a quality+=step
>for %G in (./1080/output.jpg) DO (
>set filesize=%~zG
>if !filesize! LSS 100000 if !quality! LSS 100 goto loop
>(
>set filesize=
>if !filesize! LSS 100000 if !quality! LSS 100 goto loop
>)
>convert export.jpg -resize 1080x1080 -quality 25 -strip ./1080/output.jpg
......等(无限循环)。这一直循环直到被杀死。
此特定测试运行中的output.jpg(质量为20)的文件大小为82.3KB,小于100KB的阈值,因此应该转到循环'并生成一个output.jpg(质量为25),文件大小为96.4KB,转到循环',并生成最终的output.jpg(质量为30),文件大小为109KB。
我相信所需的输出应该是这样的:
>SET /a QUALITY=20
>SET /a STEP=5
>convert input.jpg -resize 1080x1080 -quality 20 -strip ./1080/output.jpg
>SET /a quality+=step
>SET filesize=82300
>if 82300 LSS 100000 if 20 LSS 100 goto loop
>convert input.jpg -resize 1080x1080 -quality 25 -strip ./1080/output.jpg
>SET /a quality+=step
>SET filesize=96400
>if 96400 LSS 100000 if 25 LSS 100 goto loop
>convert input.jpg -resize 1080x1080 -quality 30 strip ./1080/output.jpb
>SET /a quality+=step
>SET filesize=109000
>if 109000 LSS 100000 if 30 LSS 100 goto loop
>
编辑:我尝试过实施David Ruhmann和Mike Nakis的建议,以及来自this post here的OR技巧。不幸的是,结果代码似乎与以前有相同的问题,我留下了无限循环(每次都增加质量)。
SET /a QUALITY=30
SET /a STEP=5
md large
:loop
convert export.jpg -resize 1080x1080 -quality %quality% -strip ./large/xhdpi.jpg
@set res=true
@echo Quality = %quality%
@SET /a quality+=step
@for %%G in (./large/xhdpi*) DO (if %%~zG GTR 100000 set res=false)
@for %%G in (./large/xhdpi*) DO (if !quality! GTR 100 set res=false)
@if "%res%"=="false" exit /b
@if "%res%"=="true" goto loop
在我的代码中,似乎错误的真正问题是%% ~zG没有被赋值。 为什么%% G会返回一个空字符串?
答案 0 :(得分:1)
:loop
convert input.jpg -resize 1080x1080 -quality %quality% -strip ./1080/output.jpg
SET /a quality+=step
for %%G in (./1080/output.jpg) DO set filesize=%%~zG
if !filesize! LSS 100000 if !quality! LSS 100 goto loop
免责声明:我无法对此进行测试,因此我很可能犯了一个错误,(我之前从未见过LSS
),但是这应该会让你知道你做了什么错了以及如何解决它。
答案 1 :(得分:1)
我通过type
12K文件 qotn.txt 模拟您的例程,使用此例程追加到“.jpg”:
@ECHO Off
setlocal enabledelayedexpansion
SET "filename=u:/sourcedir/1080-output.jpg"
TYPE qotn.txt >"%filename%"
SET /a QUALITY=20
SET /a STEP=5
:loop
TYPE qotn.txt >>"%filename%"
:: convert input.jpg -resize 1080x1080 -quality %quality% -strip ./1080/output.jpg
SET /a quality+=step
for %%G in (%filename%) DO (
set filesize=%%~zG
if !filesize! LSS 100000 if !quality! LSS 100 goto loop
)
DIR/d u:\sourcedir
SET q
GOTO :EOF
......而且效果很好。
所以我所能贡献的只是一些评论 - 是的,不是严格意义上的“回答”,但不容易按摩到“通知”...... soz。
目录分隔符为\
而不是/
,用于交换机。它似乎有效,但根据我的喜好,我会使用\
。请注意,最后,我使用了目标目录的DIR
- 因为dir
不喜欢%filename%
(包含/
)
如果文件不存在,for %%G
将不会执行set / if。因此,无论/
vs \
问题如何,都会找到该文件。
真正的问题是,filesize
未设置为目标大小的原因,如运行报告中的行>set filesize=
所示。
delayedexpansion
似乎没有理由。由于quality
循环内的for
不会发生变化,因此可以使用%quality%
,%%~zG
可以在!filesize!
语句中使用if
代替quality
请注意,您在运行convert
后正在更改quality
,因此实际使用的loop is not the quality use by
转换. This won't impact the size problem, but it will limit
质量'所见的%%G
为95%
所以 - 我怀疑使用中的mmetavariable $$~z
在循环中处于不同的情况 - 但运行报告另有说法。我甚至尝试在G
和{{1}}之间插入一个空格 - 但这会产生不同的结果,而不是无限循环。
赞成决议......
答案 2 :(得分:1)
@echo off
setlocal enableextensions disabledelayedexpansion
set "inputFile=.\input.jpg"
set "outputFile=.\1080\output.jpg"
set "done="
type nul > "%outputFile%"
for /l %%q in (20 5 100) do if not defined done for %%o in ("%outputFile%") do (
if %%~zo LSS 100000 (
convert "%inputFile%" -resize 1080x1080 -quality %%q -strip "%outputFile%"
) else set "done=1"
)
此代码只使用for /l
来迭代可用的质量选项,而不是为每次迭代跳回。变量用于确定循环是否应继续转换文件,但可以用goto
替换以跳出循环。