Encode RGBA color to 24 bits (ImageRep)

By the way, I test on 24 bits PNG (no alpha for pixels).

I wonder if with 32 bits PNG, we have
a, b, g, r = pixel
b, g, r, a = pixel

that will give me a flipped image using my sample file…

which is what I would expect…

rgb_4_flip_1_rev r, g, b, a = pixel; new_data2 << b.chr << g.chr << r.chr

my question is does it do the same on a PC…

the reason I ask is I have sent out a few plugins using image_rep and no-one has ever reported flipped images when using on windows…


I believe image_rep uses a version of this…

// Allocate a 32-bit dib
FIBITMAP *dib = FreeImage_Allocate(512, 512, 32, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
// Calculate the number of bytes per pixel (3 for 24-bit or 4 for 32-bit) int bytespp = FreeImage_GetLine(dib) / FreeImage_GetWidth(dib);
for(unsigned y = 0; y < FreeImage_GetHeight(dib); y++) { BYTE *bits = FreeImage_GetScanLine(dib, y);
for(unsigned x = 0; x < FreeImage_GetWidth(dib); x++) { // Set pixel color to green with a transparency of 128 
bits[FI_RGBA_RED] = 0;
bits[FI_RGBA_GREEN] = 255;
bits[FI_RGBA_BLUE]  = 0;
bits[FI_RGBA_ALPHA] = 128;
// jump to next pixel
bits += bytespp;


I don’t understand why you talk about ‘flipped image’. The problem of order is at pixel level.

In Windows, the 3 bytes for a pixel are encoded in imagerep.data in [B, G, R] order, and thus must be put back in the new_data in this [B, G, R] order too.

From what you say, it seems that on Mac, each pixel is encoded in [R, G, B] order.

I checked that, on Windows, the following code will take any 24-bits PNG image and make it fully in RED, which proves that the pixel encoding is [B, G, R] on Windows

		imgrep.data.bytes.each_slice(3) do |pixel|
			r = 255
			g = b = 0
			new_data << b.chr << g.chr << r.chr

Could you try on Mac…

I get BLUE on the mac, confirming [R, B, G] is used…

the image only contains single colour pixels, so same test really, it just visually shows RGB vs BGR…

what threw me was the double reverse, but I can see that a colour weighted algorithm requires a known colour order…

mine have only been steaming the input, pixel doubling or converting to B&W so I guess it’s never came up as an issue…


Good to know…

And Thomthom was right to warn us about the platform difference.

If you grayscale the picture, then I guess you assign the same value to R, G and B. So the order does not matter.

PS: I also check that on Windows, the order is [B, G, R , A] for 32-bits PNG. The last byte, A, is supposed to give individual transparency to the pixel, which works fine and can be useful for masking.

I have been ‘clipping’ the alpha to remove screen shot anti aliasing, but that outside of the RBG / BGR as well…

i.e. if a.between(0..10) change the whole pixel fully transparent…

have a look at the FreeImage3180.pdf to see what ‘could’ be easily exposed in the API and SDK…


After this discussion, here is the code snippet for substituting colors in a PNG

# IMAGEREP: Substitute colors in an ImageRep
#           Method substitute_proc takes arguments (r, g, b, a) and returns a new [r, g, b, a]
def imagerep_substitute_colors(imgrep, &substitute_proc)
	#Data bytes are processed by pixel as [r, g, b, a] (Mac) or [b, g, r, a] (Windows)
	#<a> is missing for 24 bits files
	new_data = ""
	if RUBY_PLATFORM =~ /darwin/i
		imgrep.data.bytes.each_slice(imgrep.bits_per_pixel / 8) do |pixel|
			r, g, b, a = substitute_proc.call(*pixel)
			new_data << r.chr << g.chr << b.chr
			new_data << a.chr if a
		imgrep.data.bytes.each_slice(imgrep.bits_per_pixel / 8) do |pixel|
			b, g, r, a = pixel
			r, g, b, a = substitute_proc.call(r, g, b, a)
			new_data << b.chr << g.chr << r.chr
			new_data << a.chr if a
	#Saving the data into the output image file
	imgrep.set_data(imgrep.width, imgrep.height, 8 * new_data.length / imgrep.width / imgrep.height, 
	               imgrep.row_padding, new_data)

Then, if you wish to grayscale a PNG, you would need to use it as

# IMAGEREP: Grayscale an Imagerep
def imagerep_grayscale(imgrep)
	imagerep_substitute_colors(imgrep) { |r, g, b, a| lum = (r * 0.2126 + g * 0.7152 + b * 0.0722).round ; [lum, lum, lum, a] }

You can also take a 24-bit PNG and make it a 32-bit PNG with individual alpha channel, say, make all pixels with color0 = [r0, g0, b0] to become transparent:

# IMAGEREP: Create a transparent mask for a given color
def imagerep_make_color_transparent
	imagerep_substitute_colors(imgrep) { |r, g, b, a| a = 0 if ([r, g, b] == [r0, g0, b0]) ; a = 255 unless a ; [r, g, b, a]  }
1 Like

We have been talking about ways to involve developers earlier.
However, in the case of ImageRep’s original intent we did have a number of developers with common need which was in contact with us via email, forum and DevCamp.
But we are listening for further improvement to ImageRep that extends beyond that. Even if we had solicited that for when ImageRep was added, we probably would not have time to include all of it into a release. Because two themes share a common one doesn’t mean we have the capacity to do it all at one. Some things needs to be done in steps.

Agree. I added an issue in the tracker for this: Getting an ImageRep from current view · Issue #183 · SketchUp/api-issue-tracker · GitHub

Noted. I’m adding this to our list of topics to improve documentation and examples for. I ran into the same explorative discovery myself when I used it in my own extension. I wish to reduce this overhead for each developer.

If you could enumerate some common image manipulation operations, that would be a good start. (Ideally in the issue tracker so we can further dig into it there.) Some thoughts of the top of my head; crop sounds like a good generic operation.

replace_color { condition }, sounds like map! to me. Is { condition } meant as a block? you’d get r,g,b,a parameters? and you’d return [r,g,b,a] or Color back?

Grayscale, this can be ambiguous. Do you return an average of RGB values, or do you return an optical grey value, like desaturation?

(Answers to this would be good to have logged in the tracker, as they’ll likely get lost in this thread.)

Agree, forums aren’t great for discovering old community wisdom.
One of the things we worked on last year was rubocop-sketchup: GitHub - SketchUp/rubocop-sketchup: Rubocop cops for SketchUp - test against our Extension Warehouse technical requirements and other pitfalls
Collecting a lot of the community’s best practices for SketchUp extensions into static code analysis. We’re working on making this tool more easily accessible and promoting it more. If used early in extension development it can save developers from many common pitfalls.

Ideally I want a way to easily include a third party library into my extensions. I’ve started prototyping a CLI app towards that (GitHub - thomthom/skippy: CLI Development tool for SketchUp extensions) But it got a while to go. One of the things I’ve played around with is setting up a dependency reference to a library on github or bitbucket. The tool will then pull that library into a local cache and copy it into your extension project under your extension namespace (the latter is key to the concept.)

However, even before that we could look into setting up a repository of modules/classes that people can manually copy+paste from. Curated by the SketchUp team to enforce consistency and high quality by having it peer reviewed.

I see that the C API documentation include this warning: Page Not Found | SketchUp Extension Warehouse

But I cannot find it mentioned in the Ruby API docs: Class: Sketchup::ImageRep — SketchUp Ruby API Documentation

I logged this as a documentation issue to be fixed: Documentation for `ImageRep` should describe platform dependent RGB order · Issue #184 · SketchUp/api-issue-tracker · GitHub

You have the full code in my last post before yours.

For grayscale, I have illustrated the luminosiity (or luminance) apporach. Alternatives are average or lightness.

1 Like