Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

XImage->data to RGB format

1,666 views
Skip to first unread message

Dongliang Chen

unread,
Sep 13, 2001, 5:16:45 PM9/13/01
to
Hi, guys,

I am new to X11. I am writing a program which needs to convert
XImage->data to RGB format(RGBRGBRGB...). Could you please let me know
how to do it?

Many thanks,

Dongliang Chen

Michel Bardiaux

unread,
Sep 14, 2001, 11:58:53 AM9/14/01
to

Impossible to say without knowing how the XImage was created. With what
parameters? And if with XGetImage, what were the properties (especially
the visual) of the Drawable?

--
Michel Bardiaux
Peaktime Belgium S.A. Rue Margot, 37 B-1457 Nil St Vincent
Tel : +32 10 65.44.15 Fax : +32 10 65.44.10

Doug

unread,
Sep 16, 2001, 8:08:36 PM9/16/01
to
dongli...@hotmail.com (Dongliang Chen) wrote in message news:<ebff56de.01091...@posting.google.com>...

As previously said; it depends. However, in general it is based on
your bit-depth, and visual. For any dynamic visual; DirectColor,
PseudoColor, GrayScale, the RGB components are not defined. You specify
them via your colormap.

For the static visuals; TureColor, StaticColor, StaticGray, it depends
on the bits per pixel of the ximage returned by whatever function created
it.

For 16 bpp, it is 5/6/5 RGB.
For 32 bpp, is is 8/8/8/8 RGBN, where N is the null bit (always zero).
For 8bpp, is it 3/3/2 RGB.

(Yes, you can get 12bpp; apparently it is 4/4/4 RGB, but don't quote me.
I've never encountered one, and Xlib is not what you might call, well
documented on this issue,)

However, it also depends on the bit order. For instance, under LSB, a
16bpp ximage with a say... TrueColor visual might be: BBBBBGGGGGGRRRRR
(Note it is BGR, not RGB because of the LSB). Or even, if the bytes are
swapped; GGGRRRRR BBBBBGGG.

Don't laugh. X does this.

Your BEST bet is to look at the [red/blue_green]_mask unsigned long in
the returned ximage. IF those masks are defined (ie. you have a static
visual), they should tell you what bits you have to set. For instance,
bit wise, you may get:

Red_mask: 00000000 00000000 00000000 00011111
Blue_mask: 00000000 00000000 11111000 00000000
Green_mask: 00000000 00000000 00000111 11100000

The most common rgb combinations are LSB, on the standard x86; which is
(as I recall, possibly with bytes swapped, I can't remember):

8: BBGGGRRR
16: BBBBBGGG GGGRRRRR
32: 00000000 BBBBBBBB GGGGGGGG RRRRRRRR

Note: Take EXTREME NOTE of the fact that you cannot get a 24bpp ximage.
It will only be 8/16/32 bpp. This is important because it will seg fault
if you pass xcreate image a 24 bit / pixel image buffer, when it uses
32 bpp.

Hope this helps.

Basic rule of thumb: Always use the static color visuals. This lets you
avoid ever needing a colormap. You need a case for 8, 16 or 32 bpp for the
XImage in this case, for both MSB and LSB, but that's all. Stay as far from
the dynamic visuals as possible. :)

On the other hand, with a direct color visual you have DIRECT control of the
bit_masks, and can pretty much define them. This unfortunately means: a)
screwing up the colormaps of all other applications, and b) using
XAllocColorXXX. Just remember: If you're not using the default visual,
make sure you specify a border pixel color, or you'll get a BadMatch error.

Ciao,
Doug.

Doug

unread,
Sep 16, 2001, 8:20:44 PM9/16/01
to
dongli...@hotmail.com (Dongliang Chen) wrote in message news:<ebff56de.01091...@posting.google.com>...

Checked; most common format I talked about before is:

32:
Byte0: BBBBBBBB
Byte1: GGGGGGGG
Byte2: RRRRRRRR
Byte3: 00000000

16:
Byte0: GGGBBBBB
Byte1: RRRRRGGG (Note: LSB, bytes swapped)

8:
Byte0: BBGGGRRR

(Obviously in the char *array, each byte is 8-bits, so for
32/16/8, there are 4/2/1 chars to define a given pixel).

Ciao,
Doug.

Michel Bardiaux

unread,
Sep 17, 2001, 10:58:41 AM9/17/01
to

2 slight corrections to 2 otherwise very informative posts:

* In the first posts you enthusiastically mix the words for bit and
byte!

* The above are common with XFree86. Other X servers tend to have their
own preferences. E.g. with Hummingbird Exceed the 24-bits TrueColor is:

00000000 BBBBBBBB GGGGGGGG RRRRRRRR

The SGI INDIGO-1 (1992 vintage!) had for 8-bits TrueColor:

RRRGGBBB (and they had a JPEG library where this went by the mnemonic
of... RGB332!)

And ISTR a Tektronix X-terminal that used

RRRRRRRR GGGGGGGG BBBBBBBB 00000000

Doug

unread,
Sep 19, 2001, 12:04:26 AM9/19/01
to
> 2 slight corrections to 2 otherwise very informative posts:
>
> * In the first posts you enthusiastically mix the words for bit and
> byte!

Did I? I don't think I did...
Either way, the important thing is that both bit and byte order are
LSF (least significant first). For instance, if the capital is the
most significant bit:

RrrrrGgggggBbbbb if how we might write a 16 bpp pixel
-> Split the bytes up
RrrrrGgg gggBbbbb
-> Now transform to LS Bytes
gggBbbbb RrrrrGgg
-> Now transform to LS bits
bbbbBggg ggGrrrrR

Which is how a LS Bit and Byte pixel would be stored in the X server.
Note; this only true if BOTH ImageByteOrder and BitmapBitOrder return
LSBFirst.

Also, it doesn't matter if you do bit swap or byte swap first; so long
as you split the bytes up before doing either.

Don't believe me? Well...you probably do, but just in case:
What you might do is say (in binary):

Rx = R1 R2 R3 R4 R5 (eg. 10; 01010)
Gx = G1 G2 G3 G4 G5 G6
Bx = B1 B2 B3 B4 B5

pixel[0] = Gx << 5 | Bx
pixel[1] = Rx << 3 | Gx >> 3

which you would think of as being:

(G1 G2 G3 B1 B2 B3 B4 B5) (R1 R2 R3 R4 R5 G6 G5 G4)

What you have to remember though, is that those binary numbers are
stored
in LSB format! They are actually:

Rx = R5 R4 R3 R2 R1 (eg. 10; still 01010. But 1 would be 10000)
Gx = G6 G5 G4 G3 G2 G1
Bx = B5 B4 B3 B2 B1

Then you'd have:

pixel[0] = Gx << 5 | Bx
pixel[1] = Rx << 3 | Gx >> 3

Which are ALSO in LSB format. So, shifting the Gx and ORing with Bx
acutally
makes:

(B5 B4 B3 B2 B1 G6 G5 G4)

Think about that for a while. It is true. The left most bit is 1.
Remember 1<<1 = 2, 1<<2 = 4, 1<<3 = 8, etc. These actually shift the
bits
RIGHT.

So you also get (for the second one): (G3 G2 G1 R5 R4 R3 R2 R1), as I
said originally. Kinda cool when you think about it. You have to work
in
LSB though, or none of it even remotely makes sense. :)

Incidentally, that's why it seems the red/blue/green masks are in MSB
format,
when they shouldn't be. For instance:

red_mask = 63488
green_mask = 2016
blue_mask = 31

This is !!NOT!! RRRRR00000000000, 00000GGGGGG00000, 00000000000BBBBB.
They are
LSB; the bits are reversed: It is: 00000000000RRRRR, 00000GGGGGG00000,
00000000000BBBBB. Which is how it is actually stored, as above. Cool,
huh?
:)

...as for those being common only to xfree86... well. What can I say?
you're right. :)

Ciao,
Doug.

Doug

unread,
Sep 19, 2001, 12:08:14 AM9/19/01
to
Crap. Must proof read before posting. =p
Last bit on the end, should be:
red_mask: 00000000000RRRRR
blue_mask: BBBBB00000000000
green_mask: 00000GGGGGG00000

Sorry. :)
Ciao,
Doug.

Kip Rugger

unread,
Sep 20, 2001, 7:05:49 PM9/20/01
to

The problem with XGetImage is that it can return data in some very
ugly formats, as Doug has explained, and that *it* picks the format.
This leads to a test coverage problem, unless you have access to
a number of systems, which collectively return all possible formats.

Another possibility is to use XIE, which lets the caller pick the
format. There are an incredible number of possible formats, most
of them very ugly, but you can also choose to get the very simple
3 bytes per RGB value, which is what ppm uses. XIE also converts
the pixels to colormap values (for pseudo color), and can handle
any visual.

With the attached subroutine, you can write out ppm data thus

buffer = getimage(display, window, colormap, X, Y, W, H);
f = fopen("whatever.ppm", "w");
fprintf(f, "P6\n%d %d\n255\n", W, H);
fwrite(buffer, 1, 3*W*H, f);
fclose(f);

or you can get a gif (or some other format) like this

buffer = getimage(display, window, colormap, X, Y, W, H);
f = popen("ppmtogif >whatever.gif 2>/dev/null", "w");
fprintf(f, "P6\n%d %d\n255\n", W, H);
fwrite(buffer, 1, 3*W*H, f);
pclose(f);


#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/extensions/XIElib.h>

char *
getimage(Display * display, Drawable drawable, Colormap colormap,
int X, int Y, int W, int H)
{
static XieExtensionInfo * xieExtensionInfo;
XiePhotoElement * photoElement;
XieEncodeUncompressedTripleParam * encode;
unsigned char pixelStride[3];
unsigned char scanlinePad[3];
XiePhotospace photospace;
XieExportState state;
char * buffer;
unsigned buffer_offset;
unsigned buffer_size;
unsigned n;

buffer_offset = 0;
buffer_size = 3*W*H;
buffer = malloc(buffer_size);
if (!buffer) fatal("malloc failed");

if (!xieExtensionInfo && !XieInitialize(display, &xieExtensionInfo))
fatal("can't initialize xie");

photoElement = XieAllocatePhotofloGraph(3);
if (!photoElement) fatal("photoElement alloc failed");

pixelStride[0] = pixelStride[1] = pixelStride[2] = 24;
scanlinePad[0] = scanlinePad[1] = scanlinePad[2] = 0;
encode = XieTecEncodeUncompressedTriple(
xieValLSFirst, /* fill order */
xieValLSFirst, /* pixel order */
xieValLSFirst, /* band order */
xieValBandByPixel, /* interleave */
pixelStride, /* pixel stride */
scanlinePad /* scanline pad */
);

XieFloImportDrawable(
&photoElement[0], /* where I go */
drawable, /* my input */
X, Y, W, H, /* input rectangle */
0, /* fill pixel */
True); /* notify of import obscured */
XieFloConvertFromIndex(
&photoElement[1], /* where I go */
1, /* my input */
colormap, /* input -> output pixels */
xieValTripleBand, /* output data is 3 bands */
8); /* precision of output */
XieFloExportClientPhoto(
&photoElement[2], /* where I go */
2, /* my input */
xieValDisable, /* send export available */
xieValEncodeUncompressedTriple, /* output format tec */
(XiePointer)encode); /* output format parms */

photospace = XieCreatePhotospace(display);
XieExecuteImmediate(
display, /* display */
photospace, 1, /* namespace */
False, /* send photoflo done event */
photoElement, 3); /* photoflo graph and size */

do {
unsigned char * bp;
unsigned maxn;

maxn = buffer_size - buffer_offset;
if (maxn > 8192) maxn = 8192;
XieGetClientData(
display, /* connection */
photospace, 1, /* namespace */
3, /* source element */
maxn, /* max bytes */
False, /* terminate? */
0, /* band number */
&state, /* new state */
&bp, /* data returned */
&n); /* length of above */
if (bp) {
memcpy(buffer + buffer_offset, bp, n);
buffer_offset += n;
XFree(bp);
}
} while (n);

XieDestroyPhotospace(display, photospace);
XieFreePhotofloGraph(photoElement, 3);
XFree(encode);

if (state == xieValExportError) {
free(buffer);
buffer = 0;
}
return buffer;
}

0 new messages