【问题标题】:How to invert PDF colors with GhostScript and place file in sub-directory?如何使用 GhostScript 反转 PDF 颜色并将文件放在子目录中?
【发布时间】:2017-08-05 08:03:28
【问题描述】:

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

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 ...

【问题讨论】:

  • 您需要delayed expansion,因为您正在编写在一个带括号的代码块中读取相同的变量...
  • 我以为我只是在读取源文件并写入子目录中的新文件?我不打算修改原始文件,只是阅读它。
  • 不,我说的是环境变量:您在同一块中分配变量commands,稍后您将通过%commands% 扩展它;这不起作用,因为当一个块被解析时会读取变量;要在代码执行时阅读它们,您需要将setlocal EnableDelayedExpansion 放在该块之前的某个位置(通常在脚本顶部),然后使用!commands! 而不是%commands%...
  • 查看我上面的代码更改 - 我启用了延迟扩展并将变量声明也移到了块之外。但我仍然得到以下输出:Error: /undefinedfilename in ...
  • 我建议对 cme​​ts 使用 rem 而不是 ::,因为后者可能会导致意外行为;此外,将"" 放在文件路径周围(-o "%outdir%\%%~f"-f "%%~f")。我无法为您提供 gs 本身的帮助,因为我不知道此命令...

标签: windows batch-file pdf ghostscript


【解决方案1】:

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

何时使用双引号

我学到的一般规则是:

(参见 Timothy Hill 于 1998 年 4 月 27 日发表的 Windows NT Shell 脚本)

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

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

  • 最后 FOR 变量(在批处理文件中)使用双倍的 %。否则 %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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多