GIMP Script-fu 批量TGA图片背景替换脚本运行无响应问题咨询
我有大量带透明通道的.tga格式图片,这类图片在业务应用中有时开启透明渲染、有时关闭透明渲染,因此“背景”(即包含alpha通道的图层蒙版中黑色区域对应的RGB像素)至关重要。
单张图片修改背景的手动操作流程如下(暂未验证是否为最优方案):
- 添加图层蒙版
- 传输图层的alpha通道
- 复制图层蒙版内容
- 应用图层蒙版
- 粘贴同尺寸的新背景图层到当前图片
- 将新图层移至图层栈底部
- 拼合图像
- 为拼合后的单图层添加图层蒙版
- 传输图层的alpha通道
- 从剪贴板粘贴之前复制的旧图层蒙版内容
- 应用图层蒙版
- 导出为.tga格式
我计划编写脚本实现批量处理,入参包含:目标文件扩展名、目标文件存储目录、新背景图片路径、是否为目标文件创建备份的开关,脚本需对目录下所有匹配目标扩展名的图片执行上述操作。
参考GIMP官方脚本教程和批处理模式文档,我编写了如下Scheme语法的Script-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)) ) ) )
修复语法错误后脚本可以正常启动,但运行后无任何效果,目标图片没有被修改,GIMP也没有抛出任何报错提示。
我初步怀疑是目标图片或新背景的路径配置问题导致脚本找不到对应文件,但我没有找到Script-fu的日志打印方法,无法进行调试定位。这是我第一次编写GIMP脚本和使用Scheme语言,我知道GIMP批处理模式官方推荐使用命令行实现,但我希望保留现有脚本的对话框交互输入方式。
问题原因与修复方案
1. 文件匹配路径错误
现有路径拼接逻辑没有加目录分隔符,会生成类似C:\test*.tga的无效路径,匹配不到任何文件导致脚本空跑。Script-fu内置了跨平台的目录分隔符常量DIR-SEPARATOR,修改文件匹配规则即可:
(filelist (cadr (file-glob (string-append directory DIR-SEPARATOR "*." fileType) 1)))
2. 背景图层加载逻辑错误
gimp-file-load返回的是图片对象,不能直接作为gimp-file-load-layer的入参,直接传入背景图路径即可加载图层:
(gimp-image-insert-layer image (car (gimp-file-load-layer RUN-NONINTERACTIVE image background)) 0 1)
3. 拼合后图层引用失效
调用gimp-image-flatten后原有layer变量指向的旧图层已经被删除,需要重新获取拼合后的图层:
(gimp-image-flatten image) (set! layer (car (gimp-image-get-active-layer image)))
4. 蒙版粘贴后未锚定
粘贴蒙版内容生成的是浮动选区,需要锚定后修改才会生效,新增一行锚定代码:
(gimp-edit-paste (car (gimp-image-get-active-drawable image)) TRUE) (gimp-floating-sel-anchor (car (gimp-image-get-active-drawable image)))
5. 调试方法
Script-fu可以用(gimp-message "日志内容")输出调试信息,日志可在GIMP顶部菜单窗口->可停靠对话框->错误控制台查看,你可以在获取文件列表后打印匹配到的文件数量,快速验证路径是否正确。
修复后完整脚本
(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* ( (filePattern (string-append directory DIR-SEPARATOR "*." fileType)) (filelist (cadr (file-glob filePattern 1))) ) ;; 调试用:打印匹配到的文件数量 (gimp-message (string-append "匹配到文件数:" (number->string (length filelist)))) (while (not (null? filelist)) (let* ( (filename (car filelist)) (image (car (gimp-file-load RUN-NONINTERACTIVE filename filename))) (layer (car (gimp-image-get-active-layer image))) ) (gimp-image-undo-disable image) (if (equal? backups 1) (gimp-file-save RUN-NONINTERACTIVE image layer (string-append filename "_backup") (string-append filename "_backup")) ) ;; 复制原有alpha蒙版 (gimp-layer-add-mask layer (car (gimp-layer-create-mask layer ADD-ALPHA-TRANSFER-MASK))) (gimp-edit-copy (car (gimp-image-get-active-drawable image))) (gimp-layer-set-apply-mask layer TRUE) ;; 插入背景图层 (gimp-image-insert-layer image (car (gimp-file-load-layer RUN-NONINTERACTIVE image background)) 0 1) ;; 拼合图像后更新图层引用 (gimp-image-flatten image) (set! layer (car (gimp-image-get-active-layer image))) ;; 还原原有alpha蒙版 (gimp-layer-add-mask layer (car (gimp-layer-create-mask layer ADD-WHITE-MASK))) (gimp-edit-paste (car (gimp-image-get-active-drawable image)) TRUE) (gimp-floating-sel-anchor (car (gimp-image-get-active-drawable image))) (gimp-layer-set-apply-mask layer TRUE) ;; 保存文件 (gimp-image-undo-enable image) (gimp-file-save RUN-NONINTERACTIVE image layer filename filename) (gimp-image-delete image) ) (set! filelist (cdr filelist)) ) ) )
内容的提问来源于stack exchange,提问作者Callistonian

