如何使用GhostScript反转PDF颜色并将文件放在子目录中?

时间:2017-03-14 19:48:52

标签: windows batch-file pdf ghostscript

正如问题所述,我想编写一个批处理脚本,它使用GhostScript反转PDF文件的所有颜色,并将结果放在子目录中。我已经安装了GhostScript然后尝试将路径添加到环境变量但是无法识别调用,因此我将可执行文件的副本放在与批处理文件相同的目录中,该文件似乎成功调用了GhostScript。我使用以下GhostScript代码作为模板,可在this post上找到:

gs -o output.pdf     \
-sDEVICE=pdfwrite \
-c "{1 exch sub}{1 exch sub}{1 exch sub}{1 exch sub} setcolortransfer" \
-f input.pdf

下面你会看到我目前对这个批处理文件的尝试,这是我的第一个批处理文件,所以任何建议都表示赞赏:

SETLOCAL EnableDelayedExpansion
@ECHO OFF

:: Setting some variables...
SET outdir=InvertedOutputs
SET gs=gswin64c.exe

:: Check for the inverted output directory,
:: make the directory if it doesn't exist.
IF NOT EXIST %outdir% MKDIR %outdir%

:: Iterate through all files in current directory.
FOR %%f IN (*) DO (

    :: Set the GhostScript / PostScript commands, before if statement.
    SET commands="{1 exch sub}{1 exch sub}{1 exch sub}{1 exch sub} setcolortransfer"

    :: Check that file extension is correct.
    IF %%~xf == .pdf (
        %gs% -o %outdir%\%%~f -sDEVICE=pdfwrite -c !commands! -f %%~f
    )
)

ECHO.
PAUSE

我编辑了代码以反映每个@aschipfl评论添加启用延迟扩展的情况。以下错误仍然存​​在:

Error: /undefinedfilenmae in ...

1 个答案:

答案 0 :(得分:0)

gs部分工作正常。谢谢你。 在我的测试中,当文件名包含空格时,我看到与OP类似的错误。所以我假设这个问题只是关于批处理文件和缺少双引号,这是cmd中的一个常见问题。

何时使用双引号

我所教的一般规则是:

(参见Timothy Hill于1998年4月27日发布的Windows NT Shell Scripting)

  • 不要在SET语句中使用引号。这与环境变量匹配,即使存在嵌入空格,也不会引用值。

  • 在扩展环境变量的任何地方都使用引号,这几乎是其他地方:IF,FOR,CALL和命令调用。

  • 最后FOR变量(在批处理文件中)使用doubled%。否则%X将解析为X,这不是你想要的。

请注意,如果值中包含嵌入空格,则脚本(和子例程)参数必须具有引号,否则是可选的。因此,您不能总是用引号包装参数%0 ..%9。因为双重双引号被忽略"" a b c"" 被解析为三个值a b和c而不是一个。

规范化参数(可能有引号)的最佳方法是使用〜运算符删除它们(如果存在),例如:

SET SOURCE=%~1
SET DESTINATION=%~2

然后所有变量都将始终没有引号,并且应该将它们添加回其他地方。注意%~f1对于从参数获取完整路径很有用,但仅当%1应该是文件名时才适用。

关于OP的脚本

  • 来自FOR(例如%% F)的值未用双引号括起来,因此必须用双引号括起来以防有嵌入空格。这就是造成一些有点神秘的错误消息的Error: /undefinedfilename in (xxx).我最初没有看到这一点,但是如果你在控制台输出中进一步阅读,你会看到:Last OS error: No such file or directory在我的情况下xxxx是嵌入空间之前路径的第一部分。

  • SET COMMANDS=可以移到FOR循环之外,以消除延迟扩展的需要。更简单的是完全消除变量,因为它只使用一次。

    我更喜欢使用子程序来避免FOR循环的怪癖和括号中的多个语句。子程序还消除了延迟扩展的需要,cmd回应每一行,使扩展易于调试。

  • -o %outdir%\%%~f有效(假设没有嵌入空格)但可能不是您可能认为的原因。 〜语法采用一个或多个修饰符,然后是FOR循环的参数字母。典型的修饰符是:d,p,n,x。请尝试Call /?了解详情。

    在这种情况下,'f'不是修饰符,因为它是〜表达式中的最后一个字母。相反,它引用FOR语句中的变量f。由于没有修饰符,%% ~f几乎相当于%% f,除了〜条带引号。

    我使用-o "%outdir%\%~nx1"从第一个参数中提取名称和扩展名到子程序(%1)。这处理%1是完整路径的情况。注意,因为〜条带引号必须加回来。

  • -f %%~f也可以在您的示例中编写%%f,但它也必须有引号,因为来自FOR的值未包含引号。否则,嵌入式空间会导致问题,如您所见。

    在我的示例中,在子例程中,因为%1在调用站点FOR %%F IN (*.pdf) DO Call :DoOne "%%F"处用引号括起来而没有其他引号是正确的。

更新的脚本(使用具有嵌入空格的文件名进行测试)

@ECHO OFF
SETLOCAL EnableExtensions

SET OUTDIR=InvertedOutputs
SET GS=C:\Program Files\gs\gs9.22\bin\gswin64c.exe

REM Make the output directory under the current one, hiding errors (e.g. directory exists)
MKDIR %OUTDIR% 1>nul: 2>>&1

REM Iterate through pdf files in current directory only.
REM Do not recurse child folders, since this would find files in the output directory
FOR %%F IN (*.pdf) DO Call :DoOne "%%F"

GOTO :Done

REM a subroutine eliminates the need for deferred expansion. All expansions are echoed to the console.
REM e.g. Call :DoOne "%%F" - processes one file
:DoOne
REM %~nx1 = the file name + extension of the argument. Since ~ strips quotes, they added back here.
REM including the commands 
REM -f %1 -- quotes are not used here, since %1 had to be quoted at the call site
ECHO ON
"%GS%" -o "%OUTDIR%\%~nx1" -sDEVICE=pdfwrite -c "{1 exch sub}{1 exch sub}{1 exch sub}{1 exch sub} setcolortransfer" -f %1
ECHO OFF
GOTO :EOF

:Done
Pause