Repository: OpenTTD/OpenGFX
Pull request #98:  Script-Fu: Support GIMP3 in addition to GIMP2
Author: login: matthijskooijman
Created: 2025-03-23T20:24:05Z | Merged: 2025-03-30T12:10:06Z

This PR extends #96 to re-add gimp2 compatibility as discussed in the comments there.

This includes:
 - the one commit from #96 verbatim, which changes the gimpscript file for v2 compatibility
 - a new commit re-adding the original gimpscript for v2, with the makefile selecting the right version

I tested this on Debian unstable with both gimp 2.10.34-1+deb12u2 from stable and gimp 3.0.0-2 from unstable.


Diff:
diff --git a/Makefile b/Makefile
index 4062769..07b12b3 100644
--- a/Makefile
+++ b/Makefile
@@ -100,6 +100,12 @@ PYTHON         ?= python3
 GIMP           ?= $(shell command -v gimp-console)
 GIMP_FLAGS     ?= -n -i --batch-interpreter=plug-in-script-fu-eval
 
+ifneq ($(findstring GNU Image Manipulation Program version 2., $(shell $(GIMP) --version)),)
+GIMP_SCRIPT     ?= $(SCRIPT_DIR)/gimpscript-v2
+else
+GIMP_SCRIPT     ?= $(SCRIPT_DIR)/gimpscript
+endif
+
 # NML
 NML            ?= nmlc
 NML_FLAGS      ?= -c
@@ -250,7 +256,7 @@ Makefile.gfx: $(GFX_SCRIPT_LIST_FILES) Makefile Makefile.config
 			for i in `cat $$j | grep "\([pP][cCnN][xXgG]\)" | grep -v "^#" | cut -d\  -f1 | sed "s/\.\([pP][cCnN][xXgG]\)//"`; do\
 				echo "$$i.scm: $$j" >> $@;\
 				echo "GFX_FILES += $$i.png" >> $@;\
-				cat $(SCRIPT_DIR)/gimpscript > $$i.scm.new;\
+				cat $(GIMP_SCRIPT) > $$i.scm.new;\
 				grep $$i.png $$j | sed -f $(SCRIPT_DIR)/gimp.sed >> $$i.scm.new;\
 				echo "(gimp-quit 0)" >> $$i.scm.new;\
 				cmp -s $$i.scm.new $$i.scm || cp $$i.scm.new $$i.scm;\
diff --git a/scripts/gimpscript b/scripts/gimpscript
index 5480698..c7019bd 100644
--- a/scripts/gimpscript
+++ b/scripts/gimpscript
@@ -5,8 +5,8 @@
 (define (script-fu-set-all-layers-invisible inImage inDrawable)
         (let*  (
                 (layers (gimp-image-get-layers inImage))
-                (num-layers (car layers))
-                (layer-array (cadr layers))
+                (layer-array (car layers))
+                (num-layers (vector-length layer-array))
                 (theLayer)
                )
 
@@ -14,9 +14,9 @@
 
         (while (> num-layers 0)
                 (set! num-layers (- num-layers 1))
-                (set! theLayer (aref layer-array num-layers))
-                (if (= (car (gimp-drawable-get-visible theLayer) ) TRUE)
-					(gimp-drawable-set-visible theLayer FALSE)
+                (set! theLayer (vector-ref layer-array num-layers))
+                (if (= (car (gimp-item-get-visible theLayer) ) TRUE)
+					(gimp-item-set-visible theLayer FALSE)
                 )
         )
 
@@ -46,10 +46,10 @@
 	(let*
 		(
 			(image (car (gimp-file-load RUN-NONINTERACTIVE inImageName inImageName)))
-			(visibleStuff (car (gimp-image-get-active-layer image)))
+			(visibleStuff (vector-ref (car (gimp-image-get-selected-layers image)) 0))
         	(layers (gimp-image-get-layers image))
-        	(num-layers (car layers))
-        	(layer-array (cadr layers))
+		(layer-array (car layers))
+		(num-layers (vector-length layer-array))
         	(thisLayer -1)
 			(thisNumLayers 0)
 			(theseLayers layers)
@@ -66,8 +66,8 @@
 		; iterate through all layers of the image
 		(while (> num-layers 0)
 			(set! num-layers (- num-layers 1))
-            (set! thisLayer (aref layer-array num-layers))
-			(set! thisLayerName (car (gimp-drawable-get-name thisLayer)))
+            (set! thisLayer (vector-ref layer-array num-layers))
+			(set! thisLayerName (car (gimp-item-get-name thisLayer)))
 			; (gimp-message (string-append "Image Layer-Name: " thisLayerName))
 
 			; iterate through all layer Names we shall use
@@ -75,7 +75,7 @@
 			(while (not (null? layerNames))
 				; if layerName matches this user supplied layername: make it visible
 				(if (string=? (car layerNames) thisLayerName)
-					(gimp-drawable-set-visible thisLayer TRUE)
+					(gimp-item-set-visible thisLayer TRUE)
 				)
 				(set! layerNames (cdr layerNames))
 			)
@@ -83,7 +83,7 @@
 
 		; Merge all visible layers into one layer which we then save to the given filename
 		(set! visibleStuff (car (gimp-image-merge-visible-layers image CLIP-TO-IMAGE)))
-		(file-png-save RUN-NONINTERACTIVE image visibleStuff outImageName outImageName 0 9 0 0 0 0 0)
+		(file-png-export #:run-mode RUN-NONINTERACTIVE #:image image #:file outImageName #:interlaced FALSE #:compression 9 #:bkgd FALSE #:offs FALSE #:phys FALSE #:time FALSE #:save-transparent FALSE)
 		(gimp-image-delete image)
 	)
 )
diff --git a/scripts/gimpscript-v2 b/scripts/gimpscript-v2
new file mode 100644
index 0000000..5480698
--- /dev/null
+++ b/scripts/gimpscript-v2
@@ -0,0 +1,97 @@
+;----------script-fu-set-all-layers-invisible----------
+;procedure by Hevan53
+;------------------------------------------------------
+
+(define (script-fu-set-all-layers-invisible inImage inDrawable)
+        (let*  (
+                (layers (gimp-image-get-layers inImage))
+                (num-layers (car layers))
+                (layer-array (cadr layers))
+                (theLayer)
+               )
+
+        (gimp-image-undo-group-start inImage)
+
+        (while (> num-layers 0)
+                (set! num-layers (- num-layers 1))
+                (set! theLayer (aref layer-array num-layers))
+                (if (= (car (gimp-drawable-get-visible theLayer) ) TRUE)
+					(gimp-drawable-set-visible theLayer FALSE)
+                )
+        )
+
+        (gimp-image-undo-group-end inImage)
+        (gimp-displays-flush)
+
+        )
+)
+
+;--------------------save-layers-----------------------
+;procedure by planetmaker
+;
+; // List of source and target images followed by a list of layer names
+; // in the source image which will make up the target image.
+;
+; // Example:
+; // (save-layers "source-file-name" "target-file-name" '(layername1 layername2 layername3 ...))
+;------------------------------------------------------
+(define
+	(
+		save-layers
+
+		inImageName
+		outImageName
+		inLayerNames
+	)
+	(let*
+		(
+			(image (car (gimp-file-load RUN-NONINTERACTIVE inImageName inImageName)))
+			(visibleStuff (car (gimp-image-get-active-layer image)))
+        	(layers (gimp-image-get-layers image))
+        	(num-layers (car layers))
+        	(layer-array (cadr layers))
+        	(thisLayer -1)
+			(thisNumLayers 0)
+			(theseLayers layers)
+			(thisLayerName 0)
+
+			(layerNames inLayerNames)
+		)
+
+		; First make everything invisble
+		(script-fu-set-all-layers-invisible image image)
+
+		; Now make those layers visible which were asked to become visible
+
+		; iterate through all layers of the image
+		(while (> num-layers 0)
+			(set! num-layers (- num-layers 1))
+            (set! thisLayer (aref layer-array num-layers))
+			(set! thisLayerName (car (gimp-drawable-get-name thisLayer)))
+			; (gimp-message (string-append "Image Layer-Name: " thisLayerName))
+
+			; iterate through all layer Names we shall use
+			(set! layerNames inLayerNames)
+			(while (not (null? layerNames))
+				; if layerName matches this user supplied layername: make it visible
+				(if (string=? (car layerNames) thisLayerName)
+					(gimp-drawable-set-visible thisLayer TRUE)
+				)
+				(set! layerNames (cdr layerNames))
+			)
+		)
+
+		; Merge all visible layers into one layer which we then save to the given filename
+		(set! visibleStuff (car (gimp-image-merge-visible-layers image CLIP-TO-IMAGE)))
+		(file-png-save RUN-NONINTERACTIVE image visibleStuff outImageName outImageName 0 9 0 0 0 0 0)
+		(gimp-image-delete image)
+	)
+)
+
+
+; // ===================================================================
+; // List of source and target images followed by a list of layer names
+; // in the source image which will make up the target image.
+; // Example:
+; // (save-layers "source-file-name" "target-file-name" '(layername1 layername2 layername3 ...))
+; // ===================================================================


Reviews:
user: login: jayaddison
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-23T21:36:36Z
user: login: matthijskooijman
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T08:08:12Z
user: login: jayaddison
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T09:17:33Z
user: login: jayaddison
body: Adding my +1 approval, although as an external/non-maintainer here
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T09:18:13Z
user: login: frosch123
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-25T12:05:35Z
user: login: zephyris
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-29T23:28:32Z

Review comments:
diff_hunk: @@ -100,6 +100,12 @@ PYTHON         ?= python3
 GIMP           ?= $(shell command -v gimp-console)
 GIMP_FLAGS     ?= -n -i --batch-interpreter=plug-in-script-fu-eval
 
+ifneq ($(findstring GNU Image Manipulation Program version 2., $(shell $(GIMP) --version)),)
path: Makefile
user: login: jayaddison
body: Generally looks good to me, thank you @matthijskooijman - I'm wondering whether we should try to accommodate the v3 prerelease versions of GIMP here -- IIRC those were numbered v2.9*.
created_at: 2025-03-23T21:36:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -100,6 +100,12 @@ PYTHON         ?= python3
 GIMP           ?= $(shell command -v gimp-console)
 GIMP_FLAGS     ?= -n -i --batch-interpreter=plug-in-script-fu-eval
 
+ifneq ($(findstring GNU Image Manipulation Program version 2., $(shell $(GIMP) --version)),)
path: Makefile
user: login: matthijskooijman
body: Good point, but I'm not sure if we really can - I expect the changes in the gimpscript were made gradually, so there are likely 2.99 versions that need the old script, others need the new script and probably some need a mix? Also, I'd like to keep this check as simple as possible.
created_at: 2025-03-24T08:08:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -100,6 +100,12 @@ PYTHON         ?= python3
 GIMP           ?= $(shell command -v gimp-console)
 GIMP_FLAGS     ?= -n -i --batch-interpreter=plug-in-script-fu-eval
 
+ifneq ($(findstring GNU Image Manipulation Program version 2., $(shell $(GIMP) --version)),)
path: Makefile
user: login: zephyris
body: I agree that trying to give development/beta release support isn't the the best plan, especially as it is presumably untested. Requiring a stable release of GIMP seems reasonable.
created_at: 2025-03-24T09:08:31Z
author_association: CONTRIBUTOR
diff_hunk: @@ -100,6 +100,12 @@ PYTHON         ?= python3
 GIMP           ?= $(shell command -v gimp-console)
 GIMP_FLAGS     ?= -n -i --batch-interpreter=plug-in-script-fu-eval
 
+ifneq ($(findstring GNU Image Manipulation Program version 2., $(shell $(GIMP) --version)),)
path: Makefile
user: login: jayaddison
body: Ok, yep; that seems reasonable to me :+1: 
created_at: 2025-03-24T09:17:32Z
author_association: CONTRIBUTOR

PR comments:
user: login: matthijskooijman
created_at: 2025-03-29T10:00:06Z
body: Any plans to merge this and maybe also prepare a release with this in the coming days? If so, I can use that to fix the Debian package. If not (which is also fine, but I do need to know), then I will go ahead and backport these gimp fixes into the current version instead. This should be done next weekend at the latest, since Debian will go into freeze a week or so later.
author_association: CONTRIBUTOR
user: login: frosch123
created_at: 2025-03-30T12:13:42Z
body: @matthijskooijman
I would like to wait for #99 for the next release, but that one is blocked by a NML release, which is blocked ...
Please go ahead with backporting just the gimp adjustments :)
author_association: MEMBER
user: login: jayaddison
created_at: 2025-03-31T10:15:48Z
body: Thanks all :)
author_association: CONTRIBUTOR
user: login: matthijskooijman
created_at: 2025-03-31T20:55:49Z
body: Thanks for the update, I've backported the changes, works like a charm (tested again on both gimp2 and gimp3): https://tracker.debian.org/news/1633899/accepted-openttd-opengfx-71-2-source-into-unstable/
author_association: CONTRIBUTOR