Вы можете загружать данные изображения из памяти, но вам нужно расположить эту память в правильном формате, который ожидает Каир.
Для того, что вы описываете, вероятно, проще сохранить данные в tmpfile и позволить Cairo загрузить их с помощью операций FILE. Cairo распознает больше форматов как типы файлов, чем как структуры в памяти.
Когда я использовал cairo_image_surface_create_for_data
для растровых изображений, мне приходилось преобразовывать мои байтовые данные с прямым порядком байтов в битовые карты в 32-битные слова с прямым порядком байтов.
Вы можете сказать по замороченным комментариям, что иногда мои усилия сводились к методам поиска и проверки, методам проб и ошибок. Но я получил желаемый результат с этим кодом. Укради у него все, что сможешь.
Еще одна вещь: Документация для форматов в памяти (A8, RGB24, ARGB32) находится в файлах .h
, а не в справочном руководстве.
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);
}
}