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
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
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.
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.
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
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.
Sorry. :)
Ciao,
Doug.
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;
}