【问题标题】:GIMP Script-fu Batch Background ReplacementGIMP Script-fu 批量背景替换
【发布时间】:2021-09-29 20:03:45
【问题描述】:

目标

我有一堆使用透明度的 .tga 图片。这些图像用于有时以透明度呈现有时不以透明度呈现的应用程序,因此“背景”(对应于包含 Alpha 通道的图层蒙版中黑色部分的 RGB 区域)至关重要。

为了更改单个图像的背景,我的手动过程(甚至可能不是最有效的)是:添加图层蒙版 > 传输图层的 Alpha 通道 > 复制图层蒙版的内容 > 应用图层蒙版 > 粘贴新背景层到图像中(相同尺寸)>将新层移动到堆栈底部>展平图像>添加图层蒙版(到生成的单层)>传输图层的Alpha通道>从剪贴板粘贴上一层蒙版的内容>应用图层蒙版>导出到.tga。

我正在尝试编写一个以参数为参数的脚本:目标文件扩展名、包含目标文件的目录、新背景图像以及创建目标文件备份的选项。批处理脚本应将上述过程应用于具有目标文件扩展名的目录中的每个图像。

方法

按照 GIMP 的脚本教程及其批处理模式页面的示例,我编写了以下脚本-fu(方案)。对于背景和目标图像的尺寸或文件类型不同的情况,我没有进行任何类型的异常处理。就我而言,所有目标文件都是 .tga,所有背景都是 .tga/.png/.jpg。

(script-fu-register
    "batch-background-replacement"
    "Batch Background Replacement"
    "Replace backgrounds of all images in a directory"
    "Callistonian"
    "2021, Callistonian"
    "September 28, 2021"
    ""
    SF-STRING   "File type"             "tga"
    SF-DIRNAME  "Directory"             ""
    SF-FILENAME "New background"        (string-append "" gimp-data-directory "")
    SF-TOGGLE   "Create backups?"       0
)

(script-fu-menu-register "batch-background-replacement" "<Image>/File")

(define (batch-background-replacement fileType directory background backups)
    (let*
        (
            (filelist (cadr (file-glob (string-append directory "*." fileType) 1)))
        )
        (while (not (null? filelist))
            (let*
                (
                    (filename (car filelist))
                    (image (car (gimp-file-load 1 filename filename)))
                    (layer (car (gimp-image-get-active-layer image)))
                )
                (gimp-image-undo-disable image)
                (if (equal? backups 1)
                    (gimp-file-save 1 image layer (string-append filename "_backup") (string-append filename "_backup"))
                )
                (gimp-layer-add-mask layer (car (gimp-layer-create-mask layer 3)))
                (gimp-edit-copy (car (gimp-image-get-active-drawable image)))
                (gimp-layer-set-apply-mask (car (gimp-image-get-active-layer image)) TRUE)
                (gimp-image-insert-layer image (car (gimp-file-load-layer 1 image (car (gimp-file-load 1 background background)))) 0 1)
                (gimp-image-flatten image)
                (gimp-layer-add-mask (car (gimp-image-get-active-layer image)) (car (gimp-layer-create-mask layer 3)))
                (gimp-edit-paste (car (gimp-image-get-active-drawable image)) TRUE)
                (gimp-layer-set-apply-mask (car (gimp-image-get-active-layer image)) TRUE)
                (gimp-image-undo-enable image)
                (gimp-file-save 1 image layer filename filename)
                (gimp-image-delete image)
            )
            (set! filelist (cdr filelist))
        )
    )
)

script dialogue box

问题

在解决了一些语法错误后,脚本现在运行但静默失败 - 目标图像没有任何反应,也没有证据表明 GIMP 做了任何事情。

评论

我怀疑目标图像和新背景的路径存在问题,脚本根本找不到它们中的任何一个。但是我还没有找到一种方法可以在任何地方打印任何东西,这使得调试变得不可能。

这是我第一次尝试编写 GIMP 脚本或使用方案。我知道 GIMP 的批处理模式页面实际上建议使用命令行进行批处理,但我更喜欢在一个漂亮的对话框中给出所有输入,就像这个脚本提供的那样。

【问题讨论】:

  • 也可以使用Python,简单一些,见here,一些调试技巧here

标签: scheme batch-processing gimp script-fu


【解决方案1】:

gimp-message 是获取调试消息的命令,无论是弹出对话框还是错误控制台

另外我认为你需要一个目录分隔符,DIR-SEPARATOR 在这一行:

(string-append directory "*." fileType)

否则你会得到这个: "C:\\Program Files\\GIMP 2.10\\share\\gimp\\2.0*.tga" 可能与您的任何文件都不匹配。

(string-append directory DIR-SEPARATOR "*." fileType) 得到这个:

"C:\\Program Files\\GIMP 2.10\\share\\gimp\\2.0\\*.tga"

【讨论】:

    【解决方案2】:

    解决了目标文件路径(感谢 paynekj,如果可以的话,我会为你投票),我能够继续调试并提出一个功能性脚本。有一些错误的函数调用已得到纠正,我添加了一个警告,以防任何目标文件尺寸与所选背景图像不匹配。

    虽然脚本按预期工作,但现在的问题是它花费的时间太长 - 在我的机器上,每张 69x96 图像大约需要 3 秒,处理大约 6,000 张图像需要几个小时才能完成所有图像。我关于尺寸不匹配的警告消息似乎不会影响处理时间。禁用撤消似乎也没有太大效果(我只是添加了这个,因为我在其他地方读到它会有所帮助)。如果有人对提高脚本效率有任何建议,请赐教。

    (define (batch-background-replacement fileType directory background backups)
        (let*
            (
                (filelist (cadr (file-glob (string-append directory DIR-SEPARATOR "*." fileType) 1)))
                (filelistLength (length filelist))
                (backgroundImage (car (gimp-file-load 1 background background)))
                (backgroundWidth (car (gimp-image-width backgroundImage)))
                (backgroundHeight (car (gimp-image-height backgroundImage)))
            )
            (gimp-image-delete backgroundImage)
            (gimp-message-set-handler 0)
            (while (not (null? filelist))
                (let*
                    (
                        (filename (car filelist))
                        (image (car (gimp-file-load 1 filename filename)))
                        (layer (car (gimp-image-get-active-layer image)))
                        (width (car (gimp-image-width image)))
                        (height (car (gimp-image-height image)))
                    )
                    
                    ;warning message for mismatched dimensions
                    (if (and (= width backgroundWidth) (= height backgroundHeight)) ()
                        (gimp-message (string-append "WARNING: target image dimensions do not match selected background image:\n" filename "\n\nBatch Background Replacement will continue processing images but the new backgrounds may not line up correctly."))
                    )
                    
                    (gimp-image-undo-disable image) ;purely to improve performance, doesn't seem to have much effect
                    
                    ;save backups
                    (if (= backups 1)
                        (gimp-file-save 1 image layer (string-append filename "_backup." fileType) (string-append filename "_backup." fileType))
                    )
                    
                    ;core process
                    (gimp-layer-add-mask layer (car (gimp-layer-create-mask layer 3)))  ;'Transfer layer's alpha channel'
                    (gimp-edit-copy (car (gimp-image-get-active-drawable image)))   ;copy contents of alpha channel
                    (gimp-image-insert-layer image (car (gimp-file-load-layer 1 image background)) 0 1) ;insert new background as bottom layer
                    (gimp-image-flatten image)  ;flatten image without applying layer mask, this doesn't work in interactive mode but seems to work fine in script
                    (gimp-layer-add-mask (car (gimp-image-get-active-layer image)) (car (gimp-layer-create-mask (car (gimp-image-get-active-layer image)) 3)))  ;'Transfer layer's alpha channel'
                    (gimp-edit-paste (car (gimp-image-get-active-drawable image)) TRUE) ;paste alpha channel from previous layer mask
                    (gimp-floating-sel-anchor (car (gimp-image-get-active-layer image)))    ;'Anchor the floating layer'
                    (gimp-layer-remove-mask (car (gimp-image-get-active-layer image)) 0)    ;'Apply layer mask'
                    (gimp-image-undo-enable image)  ;probably unnecessary
                    (gimp-file-save 1 image (car (gimp-image-get-active-layer image)) filename filename)    ;export
                    (gimp-image-delete image)   ;close
                )
                (set! filelist (cdr filelist))
            )
            (gimp-message (string-append "Batch Background Replacement has finished processing " (number->string filelistLength) " images."))
        )
    )
    

    edit:对脚本和 cmets 添加了一些改进,至少可以解释我认为正在发生的事情。每个文件仍然需要大约 3-4 秒,在首选项中使用 16 个线程。我尝试取消选中“在最近的文档列表中保留已使用文件的记录”,但没有明显效果。

    在控制台中单独运行命令,大多数是即时的,但打开文件和导出肯定不是 - 这些需要大约 3 秒的交互运行,这表明几乎所有的处理时间都只是打开和导出。 开始每个目标图像的核心进程之前打开所有目标图像,然后在最后将它们全部导出可能会更快?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-09
      相关资源
      最近更新 更多