Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Bug: gimp-drawable-get-pixel fails despite channels visible in UI
#1
Anyone have any ideas?
Also, how is it possible that an RBG png image when opened in the GUI and image properties view, says it has 0 channels, but you can  Go to Windows > Dockable Dialogs > Channels and select each of the 3 channels, np??
-----

**Bug Report Summary: gimp-drawable-get-pixel Returns UNEXPECTED_TYPE for Pixel Data Despite Channels Being Visible in UI**

**GIMP Version:** 2.10.38
**Operating System:** windows11

-----

**Description of Issue:**

When attempting to retrieve pixel data using the gimp-drawable-get-pixel PDB function within a Script-Fu plugin, the second return value (expected to be the GIMP_PDB_INT8ARRAY containing pixel bytes) is consistently an UNEXPECTED_TYPE from Script-Fu's perspective. This occurs even when the image clearly displays color channels in GIMP's UI.

**Detailed Observations:**

1.  **Contradictory Channel Information:**

      * Image > Image Properties for the affected image reports "Number of channels: 0".
      * However, Windows > Dockable Dialogs > Channels *visibly shows* and allows interaction with R, G, and B channels (for an RGB image), and selecting/deselecting these channels correctly alters the image's display. This confirms that the channel data *does* exist internally and is usable by GIMP's UI.

2.  **gimp-drawable-get-pixel Behavior:**

      * The function call itself does not error out. It returns a Scheme PAIR (a two-element list) as expected.
      * The first element of this pair (expected num-channels) appears to be accessible.
      * The second element of this pair (expected pixel data, an INT8ARRAY or list of bytes) is the problem. Script-Fu's (cadr pixel-result) evaluates to a value that is not a list (empty or non-empty), boolean, number, string, or symbol. Our enhanced debugging in Script-Fu reports its type as UNEXPECTED_TYPE.

**Impact:**

This issue prevents Script-Fu plugins from reliably reading pixel data from images via gimp-drawable-get-pixel, effectively breaking any functionality that relies on pixel-level inspection (e.g., custom filters, image analysis, scene detection from masks).

**Steps to Reproduce:**

1.  Open an RGB PNG image (e.g., scene_mask.png with visible white/black areas) in GIMP.
2.  Verify the contradictory channel information:
      * Go to Image > Image Properties and confirm "Number of channels: 0".
size in pixels: 7013 x 4062 pixels
Color space: RGB color: GIMP built-in sRGB
Precision: 8-bit gamma integer
File Type: PNG image
Number of pixels: 34798506
Number of layers: 1
Number of channels: 0
Number of Paths: 0
      * Go to Windows > Dockable Dialogs > Channels and confirm that R, G, and B channels are visible and functional (e.g., toggling their visibility changes the image).
3.  Load the Script-Fu plugin (with the relevant scan function snippet) into GIMP.
4.  Run the Script-Fu plugin.
5.  Observe the GIMP console or debug messages for output similar to:
    script-fu.exe-Warning: Debug: Raw pixel-result at (X,Y): PAIR (Unknown Type)
    script-fu.exe-Warning: Warning: pixel-bytes is not a valid list for pixel data at (X,Y). Raw value type: UNEXPECTED_TYPE Value: Cannot display raw value

**Expected Behavior:**

gimp-drawable-get-pixel should return a valid Scheme list of integer bytes (e.g., (255 255 255) for a white RGB pixel) as its second return value when invoked on a drawable from an image with visible and functional channels.

**Troubleshooting Performed (No Effect):**

  * Attempted Image > Mode > Grayscale then Image > Mode > RGB.
  * Attempted Image > Flatten Image and Image > Merge Visible Layers....
  * Exported the image as a new PNG and then re-opened it in GIMP.

**Relevant Script-Fu Snippet (from scan function):**

scheme
    (define (scan x y)
      (let ((pixel-result (gimp-drawable-get-pixel mask-drawable x y)))
        (gimp-message (string-append "Debug: Raw pixel-result at (" (number->string x) "," (number->string y) "): "
                                     (if (pair? pixel-result) "PAIR" "NON-PAIR")
                                     (if (and (not (pair? pixel-result)) (boolean? pixel-result)) (if pixel-result " (Value: TRUE)" " (Value: FALSE)")
                                         (if (and (not (pair? pixel-result)) (number? pixel-result)) (string-append " (Value: " (number->string pixel-result) ")")
                                             " (Unknown Type)"))))

        (if (pair? pixel-result)
            (let* (
                    (num-channels (car pixel-result))
                    (pixel-bytes (cadr pixel-result))
                  )
              (if (and (pair? pixel-bytes) (not (null? pixel-bytes)))
                  (begin ; Process the pixel if valid
                    ; ... (pixel processing logic) ...
                  )
                  (gimp-message (string-append "Warning: pixel-bytes is not a valid list for pixel data at (" (number->string x) "," (number->string y) "). Raw value type: "
                                               (cond
                                                 ((pair? pixel-bytes)
                                                  (if (null? pixel-bytes) "EMPTY_LIST ()" "NON_EMPTY_LIST"))
                                                 ((boolean? pixel-bytes)
                                                  (if pixel-bytes "BOOLEAN_TRUE (#t)" "BOOLEAN_FALSE (#f)"))
                                                 ((number? pixel-bytes) "NUMBER")
                                                 ((symbol? pixel-bytes) "SYMBOL")
                                                 ((string? pixel-bytes) "STRING")
                                                 (else "UNEXPECTED_TYPE"))
                                               " Value: "
                                               (cond
                                                 ((boolean? pixel-bytes) (if pixel-bytes "#t" "#f"))
                                                 ((number? pixel-bytes) (number->string pixel-bytes))
                                                 ((pair? pixel-bytes) (if (null? pixel-bytes) "()" (string-append "(" (number->string (car pixel-bytes)) "...")) )
                                                 (else "Cannot display raw value")))))
            )
            (gimp-message (string-append "Error: gimp-drawable-get-pixel returned an unexpected value (not a pair) for pixel-result at (" (number->string x) "," (number->string y) "). Raw value: "
                                         (if (boolean? pixel-result) (if pixel-result "TRUE" "FALSE") "Unknown type"))))
      )
    )


-----
Reply
#2
When you say "RBG png image" does that mean "non-indexed image"?

In Python, get_pixel() returns a Gegl.Color object, not a plain byte array: redValue=layer.get_pixel().get_rgba().red.

The Script-fu browser doc also says that gimp-drawable-get-pixel returns a GeglColor, even if it doesn't document any way to extract data from this.
Reply
#3
Hi AgHornet,

Assuming you are on gimp 2.10 as your post says (so not gimp 3.0), hopefully the test script below helps. Example output:
    Test get pixel Warning
    Name: Background
    Coordinate: 4 9
    Bpp: 4
    Do num-channels = bpp? #t
    Is pixel a vector? #t
    Is len pixel = bpp? #t
    Channel: 0 Value: 152
    Channel: 1 Value: 229
    Channel: 2 Value: 84
    Channel: 3 Value: 197

As for Image -> Image properties
    ...
    Number of Channels
    ...

It's the number of selection mask channels in the mage. You can add these using the 'Create a new channel' icon at the bottom left of the channels dialog. See https://docs.gimp.org/2.10/en/gimp-channel-dialog.html


Code:
(define (boolean->string b) (if b "#t" "#f"))

(define (script-fu-test-get-pixel image drawable x y)

  (let* ((bpp (car (gimp-drawable-bpp drawable)))
         (pixel-result (gimp-drawable-get-pixel drawable x y))
         (num-channels (car pixel-result))
         (pixel (cadr pixel-result))
         (mess "")
        )

    (set! mess (string-append mess "Name: " (car (gimp-item-get-name drawable)) "\n"))
    (set! mess (string-append mess "Coordinate: " (number->string x) " " (number->string y) "\n"))
    (set! mess (string-append mess "Bpp: " (number->string bpp) "\n"))
    (set! mess (string-append mess "Do num-channels = bpp? " (boolean->string (= num-channels bpp)) "\n"))
    (set! mess (string-append mess "Is pixel a vector? " (boolean->string (vector? pixel)) "\n"))
    (set! mess (string-append mess "Is len pixel = bpp? " (boolean->string (= (vector-length pixel) bpp)) "\n"))

    (do ((len (vector-length pixel))
         (i 0 (+ i 1)))
        ((= i len))
        (set! mess (string-append mess "Channel: " (number->string i) " Value: " (number->string (vector-ref pixel i)) "\n"))
    )

    (gimp-message mess)

  ))

(script-fu-register
  "script-fu-test-get-pixel"                  ; Name
  "Test get pixel"                            ; Menu label
  ""                                          ; Description
  "Author"                                    ; Author
  "Copyright"                                 ; Copyright
  ""                                          ; Date
  "*"                                         ; Types
  SF-IMAGE       "image"     0
  SF-DRAWABLE    "drawable"  0
  SF-ADJUSTMENT  "x"        (list 0 0 1000 1 10 0 SF-SPINNER)
  SF-ADJUSTMENT  "y"        (list 0 0 1000 1 10 0 SF-SPINNER)
)

(script-fu-menu-register "script-fu-test-get-pixel" "<Image>/Script-Fu")
Reply
#4
PS: There are big differences between gimp 2.10 and 3.0 so please clarify what version of gimp you're using in this case.  Your profile says 3.0 but post #1 in this thread says '**GIMP Version:** 2.10.38'.  Then again your post on your thread 'GIMP 3.0.4 Script-Fu Batch Issue: SF-TOGGLE Without Run-Mode' says 'gimp 3.0.4'.

As stated my above answer assumes you first post in this thread contains the appropriate version in this case.
Reply
#5
(07-03-2025, 08:20 PM)Ofnuts Wrote: The Script-fu browser doc also says that gimp-drawable-get-pixel returns a GeglColor, even if it doesn't document any way to extract data from this.

That's what it says but the following code works in V3.0.4 in an scm file in the plug-ins folder:

Code:
 ; Check if a pixel is opaque - it is not opaque if it lies outside the bounds of the unrotated image
 ;
 (define (pixel_is_opaque x y)
   (let* (
      (result FALSE)
      (pixel_value '())
      )
       (if (and (>= x 0) (< x width) (>= y 0) (< y height))
         (begin
         (set! pixel_value (gimp-drawable-get-pixel inLayer x y))
         (if (= (cadddr pixel_value) 255)
           (set! result TRUE)
         )    ; end - if
         )    ; end - begin
       )    ; end - if
       (list
         result
       )
    )    ; end - let
 )    ; end - define

The full code is available in https://programmer97.byethost10.com/File...cm_GV3.scm

I seem to remember a commit in this area but can't currently find it.

The GIMP activation line is:
/usr/bin/flatpak run --branch=stable --arch=x86_64 --command=gimp-3.0 --file-forwarding org.gimp.GIMP @@u %U @@ --pdb-compat-mode=warn

I don't suppose that it makes any difference but the pdb-compat-mode refers to this sort of area.
Reply
#6
(07-04-2025, 10:23 AM)programmer_ceds Wrote: The full code is available in https://programmer97.byethost10.com/File...cm_GV3.scm

I'm getting '404!  We couldn't find that page.' on that link can you update?
Reply
#7
(07-04-2025, 07:10 AM)teapot Wrote: PS: There are big differences between gimp 2.10 and 3.0 so please clarify what version of gimp you're using in this case.  Your profile says 3.0 but post #1 in this thread says '**GIMP Version:** 2.10.38'.  Then again your post on your thread 'GIMP 3.0.4 Script-Fu Batch Issue: SF-TOGGLE Without Run-Mode' says 'gimp 3.0.4'.

As stated my above answer assumes you first post in this thread contains the appropriate version in this case.

Thanks very much for getting back. Yes, I am using gimp 2.10.38. I had been trying to use Gimp 3.0.4 last week, but that proved to problematic, so I reverted to, what I thought might be better documented, with more examples. So, for the sack of this thread, I am using gimp 2.10. 

Thanks


ps. I'm going to look at the other suggestion now. Cheers

(07-04-2025, 04:21 AM)teapot Wrote: Hi AgHornet,

Assuming you are on gimp 2.10 as your post says (so not gimp 3.0), hopefully the test script below helps. Example output:
    Test get pixel Warning
    Name: Background
    Coordinate: 4 9
    Bpp: 4
    Do num-channels = bpp? #t
    Is pixel a vector? #t
    Is len pixel = bpp? #t
    Channel: 0 Value: 152
    Channel: 1 Value: 229
    Channel: 2 Value: 84
    Channel: 3 Value: 197

As for Image -> Image properties
    ...
    Number of Channels
    ...

It's the number of selection mask channels in the mage. You can add these using the 'Create a new channel' icon at the bottom left of the channels dialog. See https://docs.gimp.org/2.10/en/gimp-channel-dialog.html


Code:
(define (boolean->string b) (if b "#t" "#f"))

(define (script-fu-test-get-pixel image drawable x y)

  (let* ((bpp (car (gimp-drawable-bpp drawable)))
         (pixel-result (gimp-drawable-get-pixel drawable x y))
         (num-channels (car pixel-result))
         (pixel (cadr pixel-result))
         (mess "")
        )

    (set! mess (string-append mess "Name: " (car (gimp-item-get-name drawable)) "\n"))
    (set! mess (string-append mess "Coordinate: " (number->string x) " " (number->string y) "\n"))
    (set! mess (string-append mess "Bpp: " (number->string bpp) "\n"))
    (set! mess (string-append mess "Do num-channels = bpp? " (boolean->string (= num-channels bpp)) "\n"))
    (set! mess (string-append mess "Is pixel a vector? " (boolean->string (vector? pixel)) "\n"))
    (set! mess (string-append mess "Is len pixel = bpp? " (boolean->string (= (vector-length pixel) bpp)) "\n"))

    (do ((len (vector-length pixel))
         (i 0 (+ i 1)))
        ((= i len))
        (set! mess (string-append mess "Channel: " (number->string i) " Value: " (number->string (vector-ref pixel i)) "\n"))
    )

    (gimp-message mess)

  ))

(script-fu-register
  "script-fu-test-get-pixel"                  ; Name
  "Test get pixel"                            ; Menu label
  ""                                          ; Description
  "Author"                                    ; Author
  "Copyright"                                 ; Copyright
  ""                                          ; Date
  "*"                                         ; Types
  SF-IMAGE       "image"     0
  SF-DRAWABLE    "drawable"  0
  SF-ADJUSTMENT  "x"        (list 0 0 1000 1 10 0 SF-SPINNER)
  SF-ADJUSTMENT  "y"        (list 0 0 1000 1 10 0 SF-SPINNER)
)

(script-fu-menu-register "script-fu-test-get-pixel" "<Image>/Script-Fu")
Thanks so much for this explaination. This proved to be the problem. Whilst pixel-result was a pair
(a list), I was treating the second element as a scheme list when it was a scheme vector. I can now correctly read the values from the file. (What I didn't realise is how slow this function call is :-( )

Thanks for the help. Much appreciated.
Reply
#8
(07-04-2025, 01:17 PM)AgHornet Wrote:
(07-04-2025, 07:10 AM)teapot Wrote: PS: There are big differences between gimp 2.10 and 3.0 so please clarify what version of gimp you're using in this case.  Your profile says 3.0 but post #1 in this thread says '**GIMP Version:** 2.10.38'.  Then again your post on your thread 'GIMP 3.0.4 Script-Fu Batch Issue: SF-TOGGLE Without Run-Mode' says 'gimp 3.0.4'.

As stated my above answer assumes you first post in this thread contains the appropriate version in this case.

Thanks very much for getting back. Yes, I am using gimp 2.10.38. I had been trying to use Gimp 3.0.4 last week, but that proved to problematic, so I reverted to, what I thought might be better documented, with more examples. So, for the sack of this thread, I am using gimp 2.10. 

Thanks


ps. I'm going to look at the other suggestion now. Cheers

(07-04-2025, 04:21 AM)teapot Wrote: Hi AgHornet,

Assuming you are on gimp 2.10 as your post says (so not gimp 3.0), hopefully the test script below helps. Example output:
    Test get pixel Warning
    Name: Background
    Coordinate: 4 9
    Bpp: 4
    Do num-channels = bpp? #t
    Is pixel a vector? #t
    Is len pixel = bpp? #t
    Channel: 0 Value: 152
    Channel: 1 Value: 229
    Channel: 2 Value: 84
    Channel: 3 Value: 197

As for Image -> Image properties
    ...
    Number of Channels
    ...

It's the number of selection mask channels in the mage. You can add these using the 'Create a new channel' icon at the bottom left of the channels dialog. See https://docs.gimp.org/2.10/en/gimp-channel-dialog.html


Code:
(define (boolean->string b) (if b "#t" "#f"))

(define (script-fu-test-get-pixel image drawable x y)

  (let* ((bpp (car (gimp-drawable-bpp drawable)))
         (pixel-result (gimp-drawable-get-pixel drawable x y))
         (num-channels (car pixel-result))
         (pixel (cadr pixel-result))
         (mess "")
        )

    (set! mess (string-append mess "Name: " (car (gimp-item-get-name drawable)) "\n"))
    (set! mess (string-append mess "Coordinate: " (number->string x) " " (number->string y) "\n"))
    (set! mess (string-append mess "Bpp: " (number->string bpp) "\n"))
    (set! mess (string-append mess "Do num-channels = bpp? " (boolean->string (= num-channels bpp)) "\n"))
    (set! mess (string-append mess "Is pixel a vector? " (boolean->string (vector? pixel)) "\n"))
    (set! mess (string-append mess "Is len pixel = bpp? " (boolean->string (= (vector-length pixel) bpp)) "\n"))

    (do ((len (vector-length pixel))
         (i 0 (+ i 1)))
        ((= i len))
        (set! mess (string-append mess "Channel: " (number->string i) " Value: " (number->string (vector-ref pixel i)) "\n"))
    )

    (gimp-message mess)

  ))

(script-fu-register
  "script-fu-test-get-pixel"                  ; Name
  "Test get pixel"                            ; Menu label
  ""                                          ; Description
  "Author"                                    ; Author
  "Copyright"                                 ; Copyright
  ""                                          ; Date
  "*"                                         ; Types
  SF-IMAGE       "image"     0
  SF-DRAWABLE    "drawable"  0
  SF-ADJUSTMENT  "x"        (list 0 0 1000 1 10 0 SF-SPINNER)
  SF-ADJUSTMENT  "y"        (list 0 0 1000 1 10 0 SF-SPINNER)
)

(script-fu-menu-register "script-fu-test-get-pixel" "<Image>/Script-Fu")
Thanks so much for this explaination. This proved to be the problem. Whilst pixel-result was a pair
(a list), I was treating the second element as a scheme list when it was a scheme vector. I can now correctly read the values from the file. (What I didn't realise is how slow this function call is :-( )

Thanks for the help. Much appreciated.

This call is not really meant to check all pixels in layer. For this you have better get a "buffer" from the drawable. However this is Gegl territory. Doable in Python (in 2.x you could use "tiles"), but  I doubt the API is available from script-fu.
Reply
#9
(07-04-2025, 01:14 PM)teapot Wrote:
(07-04-2025, 10:23 AM)programmer_ceds Wrote: The full code is available in https://programmer97.byethost10.com/File...cm_GV3.scm

I'm getting '404!  We couldn't find that page.' on that link can you update?

Sorry I joined the file name to the link. The link by itself is:

https://programmer97.byethost10.com/File...teCrop.zip
Reply


Forum Jump: