Posts: 110 
	Threads: 6 
	Joined: Jun 2019
	
 Reputation: 
 21
Gimp version: 
 
Operating system(s): Linux
	  
 
	
	
		For gimp 2.10, is my understanding correct? 
Given a region's bytes from a layer ‘l’:
 
    r = l.get_pixel_rgn(0, 0, w, h) 
    rb = r[:, :]
 
I think rb will hold the bytes of the channel's values in the machine's native endianess because:
 
- a region maps onto tiles, 
- getting the tile's pixels uses a simple memcpy(), and 
- a tile's pixels are in the native endianess.
 
I'm aware tile data in an XCF file is big-endian from
 https://testing.developer.gimp.org/core/...ganization
But I'm interested in what's in memory and guaranteed to be seen through slicing a Python region into a string of bytes.
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 6,916 
	Threads: 296 
	Joined: Oct 2016
	
 Reputation: 
 605
Gimp version: 
 
Operating system(s): Linux
	  
 
	
	
		In my code it appears that I assume it's R,G,B. Worrying about endianness would imply that you expect values in data types bigger than bytes?
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 110 
	Threads: 6 
	Joined: Jun 2019
	
 Reputation: 
 21
Gimp version: 
 
Operating system(s): Linux
	  
 
	
	
		Hi Ofnuts, Yes, that's right.  The image's precision can be integers or floats of 16 or 32 bits.
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 6,916 
	Threads: 296 
	Joined: Oct 2016
	
 Reputation: 
 605
Gimp version: 
 
Operating system(s): Linux
	  
 
	
		
		
		07-14-2025, 07:23 PM 
(This post was last modified: 07-14-2025, 07:47 PM by Ofnuts.)
	
	 
	
		 (07-14-2025, 05:52 PM)teapot Wrote:  Hi Ofnuts, Yes, that's right.  The image's precision can be integers or floats of 16 or 32 bits. 
OK, so  
- I create a 32-bit image, and fill with a (100%,50%,25%) color (values in the FG color selector, in other words #FF8040).
 
 
- Get a pixel region. rgn.bpp is 3, so data is converted to one byte per channel.
 
 
- Call pdb.gimp_plugin_enable_precision() 
 
 
- rgn.bpp is now 12 (coherent with 32-bit per channel (no alpha channel).
 
  
Then
 
Code: 
 ➤> rgn=image.active_layer.get_pixel_rgn(0,0,10,10) 
➤> rgn.bpp # Check the precision of the returned data 
3 
➤> # Tell Gimp we are a big boy and can be told the truth 
➤> pdb.gimp_plugin_enable_precision()  
 
➤> rgn=image.active_layer.get_pixel_rgn(0,0,10,10) 
➤> rgn.bpp 
12 
➤> # OK, much better (no alpha, so 3 channels of 4 bytes each) 
➤> # Let's try some decoding 
➤> import struct 
 
➤> struct.unpack('f',rgn[0,0][0:4])  # Native order, get 1 for Red, as expected 
(1.0,) 
➤> struct.unpack('<f',rgn[0,0][0:4]) # Little-endian order (same as native on my x86 PC, still OK) 
(1.0,) 
➤> struct.unpack('>f',rgn[0,0][0:4]) # Big-endian, WTF 
(4.600602988224807e-41,) 
➤> struct.unpack('f',rgn[0,0][4:8])  # Green (obviously linear) 
(0.21586056053638458,) 
➤> struct.unpack('f',rgn[0,0][8:12]) # Blue (obviously linear too) 
(0.051269471645355225,) 
➤>
  
	 
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 110 
	Threads: 6 
	Joined: Jun 2019
	
 Reputation: 
 21
Gimp version: 
 
Operating system(s): Linux
	  
 
	
	
		Thanks Ofnuts, 
Working though your example to see if I understand the figures:
 
Colour selector: #ff8040
 
Code: 
 255/255 = 1.0 
128/255 = 0.50196078431372549019 
 64/255 = 0.25098039215686274509
  
Converting from perceptual to linear using
 https://en.wikipedia.org/wiki/SRGB#Trans...amma%22%29
gives results close to yours:
 
Code: 
 ➤> def g(v): return ((v + 0.055) / 1.055) ** 2.4 
... 
➤> g(1.0) 
1.0 
➤> g(0.50196078431372549019) 
0.21586050011389926 
➤> g(0.25098039215686274509) 
0.05126945837404324
  
So it looks like the colour selector is perceptual RGB, sRGB, even when the image is linear.
 
I found it useful to look in the Colour Picker info window with the two columns set to RGB (%) and Pixel. E.g. for a pixel entered as RGB #102030, a 32-bit float, perceptual image gives:
 
Code: 
     RGB (%)       Pixel 
    R:   6.3%     R: 0.062745  16 / 255 = 0.06274509803921568627 
    G:  12.5%     G: 0.125491  32 / 255 = 0.12549019607843137254 
    B:  18.8%     B: 0.188236  48 / 255 = 0.18823529411764705882
  
Whereas a 32-bit float, linear image gives:
 
Code: 
     RGB (%)       Pixel 
    R:   6.3%     R: 0.005182  g(16 / 255) = 0.005181516702338386 
    G:  12.5%     G: 0.014444  g(32 / 255) = 0.014443843596092545 
    B:  18.8%     B: 0.029577  g(48 / 255) = 0.0295568344378088
  
Getting back to the question of a region's pixel data, I am also on a little endian machine and got the same results as you. However, to make generic code we'd need to know if gimp gives the data in native or little endianness.
 
Perhaps someone on a big endian machine could try your example and post the results.
 
To check what the endianness is:
 
Code: 
 ➤> import sys 
➤> sys.byteorder 
'little'
  
There's no documentation I've found which states the region data is always native endianness, but looking at GIMP's code to load and save XCF files, it calls functions and macros from Glib which convert pixels in the XCF file's big-endian to native.  From then on, I think it just remains native endianness for efficiency.
	  
	
	
	
		
	 
 
 
	
	
	
		
	Posts: 6,916 
	Threads: 296 
	Joined: Oct 2016
	
 Reputation: 
 605
Gimp version: 
 
Operating system(s): Linux
	  
 
	
	
		 (07-21-2025, 05:40 PM)teapot Wrote:  Thanks Ofnuts, 
 
Working though your example to see if I understand the figures: 
 
Colour selector: #ff8040 
 
Code: 
 255/255 = 1.0 
128/255 = 0.50196078431372549019 
 64/255 = 0.25098039215686274509
  
 
Converting from perceptual to linear using 
https://en.wikipedia.org/wiki/SRGB#Trans...amma%22%29 
gives results close to yours: 
 
Code: 
 ➤> def g(v): return ((v + 0.055) / 1.055) ** 2.4 
... 
➤> g(1.0) 
1.0 
➤> g(0.50196078431372549019) 
0.21586050011389926 
➤> g(0.25098039215686274509) 
0.05126945837404324
  
 
So it looks like the colour selector is perceptual RGB, sRGB, even when the image is linear. 
 
I found it useful to look in the Colour Picker info window with the two columns set to RGB (%) and Pixel. E.g. for a pixel entered as RGB #102030, a 32-bit float, perceptual image gives: 
 
Code: 
     RGB (%)       Pixel 
    R:   6.3%     R: 0.062745  16 / 255 = 0.06274509803921568627 
    G:  12.5%     G: 0.125491  32 / 255 = 0.12549019607843137254 
    B:  18.8%     B: 0.188236  48 / 255 = 0.18823529411764705882
  
 
Whereas a 32-bit float, linear image gives: 
 
Code: 
     RGB (%)       Pixel 
    R:   6.3%     R: 0.005182  g(16 / 255) = 0.005181516702338386 
    G:  12.5%     G: 0.014444  g(32 / 255) = 0.014443843596092545 
    B:  18.8%     B: 0.029577  g(48 / 255) = 0.0295568344378088
  
 
Getting back to the question of a region's pixel data, I am also on a little endian machine and got the same results as you. However, to make generic code we'd need to know if gimp gives the data in native or little endianness. 
 
Perhaps someone on a big endian machine could try your example and post the results. 
 
To check what the endianness is: 
 
Code: 
 ➤> import sys 
➤> sys.byteorder 
'little'
  
 
There's no documentation I've found which states the region data is always native endianness, but looking at GIMP's code to load and save XCF files, it calls functions and macros from Glib which convert pixels in the XCF file's big-endian to native.  From then on, I think it just remains native endianness for efficiency. 
You can determine endianness on the fly. If you look at my code, if you set a channel to 1 (bucket-fill or else), and re-obtain it and decode it with the wrong endianness, you get a completely invalid answer, so it is easy to determine which endianness should be used
	  
	
	
	
		
	 
 
 
	 
 |