0

I'm looking to automate the addition of a small PNG at the centre of a much larger PNG using GIMP (2.8) and its Script-Fu language. The first image provided in the procedure call always shows, but the second image doesn't.

(overlay-images "/tmp/bigImage.png" "/tmp/smallImage.png" "/tmp/output.png")

Here is the script with the debugging I've been using to work out why the second image can't be seen in the output.png:

(define (overlay-images image-file-1 image-file-2 output-file)
  (let* (
      (image (car (file-png-load RUN-NONINTERACTIVE image-file-1 image-file-1)))
      (drawable (car (gimp-image-get-active-layer image)))
      (overlay-layer (car (gimp-file-load-layer RUN-NONINTERACTIVE image image-file-2)))
    )
    ;; Add a debugging statement here
    (gimp-message (string-append "overlay-layer: " (number->string overlay-layer)))
    (gimp-image-add-layer image overlay-layer -1)
    (gimp-message (string-append "Number of layers: " (number->string (car (gimp-image-get-layers image)))))
    (gimp-message (string-append "Overlay layer visible: " (if (= (car (gimp-drawable-get-visible overlay-layer)) TRUE) "yes" "no")))
    
    
    
    (let* (
        (image-width (car (gimp-image-width image)))
        (image-height (car (gimp-image-height image)))
        (overlay-width (car (gimp-drawable-width overlay-layer)))
        (overlay-height (car (gimp-drawable-height overlay-layer)))
        (offset-x (/ (- image-width overlay-width) 2))
        (offset-y (/ (- image-height overlay-height) 2))
      )
      (gimp-layer-set-offsets overlay-layer offset-x offset-y)
    )
    (let* (
    (overlay-offsets (gimp-drawable-offsets overlay-layer))
    (overlay-offset-x (car overlay-offsets))
    (overlay-offset-y (cadr overlay-offsets))
  )
  (gimp-message (string-append "Overlay layer size: " (number->string (car (gimp-drawable-width overlay-layer))) "x" (number->string (car (gimp-drawable-height overlay-layer)))))
  (gimp-message (string-append "Overlay layer position: (" (number->string overlay-offset-x) ", " (number->string overlay-offset-y) ")"))
  )
  (gimp-message (string-append "Number of layers before saving: " (number->string (car (gimp-image-get-layers image)))))
  (gimp-message (string-append "Overlay layer visible before saving: " (if (= (car (gimp-drawable-get-visible overlay-layer)) TRUE) "yes" "no")))
    (file-png-save RUN-NONINTERACTIVE image drawable output-file output-file 0 9 0 0 0 0 0)
    (gimp-image-delete image)
  )
)

My expectations are that the second image (smallImage.png) appears roughly in the centre of the first (bigImage.png). I've tried swapping the two images:

(overlay-images "/tmp/smallImage.png" "/tmp/bigImage.png" "/tmp/output.png")

That then shows smallImage.png in output.png so it isn't a file read error.

What am I missing?

Isaac
  • 11
  • 6
  • 1
    This would be a one-liner in a shell script with ImageMagick, You are really making you a disservice using Gimp (and script-fu, IMHO) for this. Could also run somewhat faster. – xenoid Mar 28 '23 at 07:18
  • As per their documentation the `file-*-save` calls save a **layer**, not the whole image. If you want to save the whole image, do a `layer-new-from-visible` and save the resulting layer. – xenoid Mar 28 '23 at 07:21
  • @xenoid I'm not wedded to GIMP, and I have ImageMagick installed. It also occurred to me that it could be done using PHP as well as the process is actually being initiated from web page. I chose GIMP as doing it manually was very quick and easy, but I need to automate it for large batches of images. Your suggestion pointed me in the right direction, I was also missing a command to overlay the overlay-layer (see my answer below) – Isaac Mar 28 '23 at 08:07

1 Answers1

1

Huge thanks to @xenoid for pointing me in the right direction. I was missing two essential elements:

  1. gimp-image-insert-layer image, and
  2. gimp-layer-new-from-visible
        (define (overlay-images image-file-1 image-file-2 output-file)
 

     (let* (
          (image (car (file-png-load RUN-NONINTERACTIVE image-file-1 image-file-1)))
          (drawable (car (gimp-image-get-active-layer image)))
          (overlay-layer (car (gimp-file-load-layer RUN-NONINTERACTIVE image image-file-2)))
        )    
        (let* (
            (image-width (car (gimp-image-width image)))
            (image-height (car (gimp-image-height image)))
            (overlay-width (car (gimp-drawable-width overlay-layer)))
            (overlay-height (car (gimp-drawable-height overlay-layer)))
            (offset-x (/ (- image-width overlay-width) 2))
            (offset-y (/ (- image-height overlay-height) 2))
          )
          (gimp-layer-set-offsets overlay-layer offset-x offset-y)
        )   
        ;; add the overlay layer to the image
        (gimp-image-insert-layer image overlay-layer 0 -1)
      
        ;; create a new layer from the visible layers of the image
        (let* (
            (visible-layer (car (gimp-layer-new-from-visible image image "visible")))
          )
          ;; save the new layer as a png file
          (file-png-save RUN-NONINTERACTIVE image visible-layer output-file output-file 0 9 0 0 0 0 0)
        )
        ;; delete the image to free resources
        (gimp-image-delete image)
      )
    )

Unless someone is holding a gun to your head and demands that you use GIMP, @xenoid's suggestion to use imagemagick should be accepted. One line of code just as he said:

composite -gravity center smallImage.png bigImage.png output.png
xenoid
  • 8,396
  • 3
  • 23
  • 49
Isaac
  • 11
  • 6