Reputation: 149
I have a doubt with cairo library.
I downloaded an image and I put it into a buffer memory. Is there any solution in cairo to load an image from data that there is in memory?
Thanks
Upvotes: 1
Views: 7500
Reputation: 19514
You can load image data from memory, but you need to lay out that memory in the correct format that Cairo expects.
For what you describe, it's probably easier to save the data in a tmpfile and let Cairo load it using FILE operations. Cairo recognizes more formats as filetypes than it does as in-memory structures.
When I used cairo_image_surface_create_for_data
for bitmaps, I had to convert my byte-oriented Big-endian bitmap data into 32bit-word-oriented Little-endian rows.
You can tell from the littering of comments, that at times my efforts were reduced to hunt-and-peck, trial-and-error methods. But I got the desired output with this code. Steal from it what you can.
One more thing: The documentation for the in-memory formats (A8, RGB24, ARGB32) is in the .h
eader files, not the reference manual.
enum { BIG, LITTLE } endian = LITTLE;
inline unsigned char reverse(unsigned char b) {
return (b&1 ? 0x80: 0)
| (b&2 ? 0x40: 0)
| (b&4 ? 0x20: 0)
| (b&8 ? 0x10: 0)
| (b&0x10 ? 8: 0)
| (b&0x20 ? 4: 0)
| (b&0x40 ? 2: 0)
| (b&0x80 ? 1: 0);
}
inline unsigned long wreverse(unsigned long w) {
return ( ( w &0xFF) << 24)
| ( ((w>>8) &0xFF) << 16)
| ( ((w>>16)&0xFF) << 8)
| ( ((w>>24)&0xFF) );
}
unsigned char abit[2] = { 0, 0xFF };
unsigned char aspeck[4] = { 0, 0x55, 0xAA, 0xFF };
unsigned char anibble[16] = { 0, 36, 72, 108, 144, 180, 216, 255 };
unsigned char *amap[] = { abit, aspeck, anibble };
void drawimage(state *st, int wid, int hgt, int bits, unsigned char *samp, unsigned char *tmap) {
int stride;
//stride = cairo_format_stride_for_width(CAIRO_FORMAT_A8, wid);
stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, wid);
//stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, wid);
int n;
//unsigned char data[n=stride*hgt];
unsigned char data[n=stride*hgt*4];
memset(data, 0, n);
//unsigned char *data; data = calloc(n=stride*hgt, 1);
unsigned long *ldata = (void *)data;
int spo = 8/bits; /* samples per octet */
int span = wid/spo + (wid%spo?1:0); /* byte width */
int i,j;
for (i=0; i < hgt; i++) {
for (j=0; j < wid; j++) {
unsigned char t;
/*if (bits==8) t = samp[i*span + j/spo];
else*/ t = ( ( samp[i*span + j/spo] >> (/*7 -*/ (j%spo)/* *bits */) )
& (0xFF >> (8-bits)) ) /*<< (8-bits)*/;
if (bits < 8) t = amap[bits==1?0:bits==2?1:2][t];
t = tmap[t]; /* map value through the transfer map */
//printf("%2X ", t);
//data[i*stride + j] = t;
ldata[i*stride/4 + j] = /*0x80<<24 |*/ t<<16 | t<<8 | t;
}
//puts("");
}
/*
for (i=0; i < hgt; i++) {
//for (j=0; j < stride; j++)
//printf("%2X ", data[i*stride + j]);
for (j=0; j < stride/4; j++)
printf("%2lX ", ldata[i*stride/4 + j] & 0xFF);
puts("");
}
*/
cairo_surface_t *surf;
//surf = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_A8, wid, hgt, stride);
surf = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_RGB24, wid, hgt, stride);
//surf = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32, wid, hgt, stride);
//cairo_mask_surface(st->cr, surf, 0, 0);
cairo_set_source_surface(st->cr, surf, 0, 0);
cairo_paint(st->cr);
cairo_surface_flush(st->surface);
if (st->dis) XFlush(st->dis);
cairo_surface_destroy(surf);
//free(data);
}
OPFN_ void image(state *st, object w, object h, object bits, object mat, object proc) {
unsigned char tmap[256];
switch (bits.u.i) {
case 1: case 2: case 4: case 8: break;
default: error(st, rangecheck);
}
int n;
int i;
unsigned char data[n=w.u.i*h.u.i/(8/bits.u.i)];
/* map gray scale through the transfer function */
for (i = 0; i < 256; i++) {
object v;
v = consreal((double)i/255);
push(v);
pushe(consoper(st, "quit", NULL,0,0));
pushe(consoper(st, "exec", NULL,0,0));
pushe(consoper(st, "currenttransfer", NULL,0,0));
run(st);
v = pop();
if (v.tag==integertype) promote(v);
if (v.tag!=realtype) error(st, typecheck);
tmap[i] = v.u.r * 255;
}
for (i = 0; i < n; ) {
object s;
pushe(consoper(st, "quit", NULL,0,0));
pushe(proc);
run(st);
if (tos-os < 1) error(st, stackunderflow);
s = pop();
if (s.tag != stringtype) error(st, typecheck);
memcpy(&data[i], STR(s), s.u.c.n);
i += s.u.c.n;
}
if (DEBUG) { for (i=0; i<n; i++) { printf("%02x ", data[i]); } puts(""); }
if (st->cr) {
gsave(st);
cairo_new_path(st->cr);
cairo_rectangle(st->cr, 0, 0, 1, 1);
cairo_clip(st->cr);
{ cairo_matrix_t cm, icm;
psm2cm(st, mat, &cm);
cminvert(&cm, &icm);
cairo_transform(st->cr, &icm);
}
cairo_set_source_rgb(st->cr, 0.0, 0.0, 0.0);
drawimage(st, w.u.i, h.u.i, bits.u.i, data, tmap);
grestore(st);
}
}
Upvotes: 4