Handle formats, basic palette mapping implementation.

This commit is contained in:
Michael Jumper 2012-04-01 21:20:08 -07:00
parent 3cae4f016f
commit 4974f5a082

View File

@ -151,45 +151,111 @@ void __guac_socket_flush_png(png_structp png) {
/* Dummy function */ /* Dummy function */
} }
int __guac_socket_write_length_png(guac_socket* socket, cairo_surface_t* surface) { typedef struct __guac_palette {
png_structp png; int index;
png_infop png_info; int color;
png_byte** png_rows;
} __guac_palette;
void __guac_create_palette(cairo_surface_t* surface) {
int x, y; int x, y;
__guac_socket_write_png_data png_data;
int base64_length;
/* Get image surface properties and data */
/*cairo_format_t format = cairo_image_surface_get_format(surface);*/
int width = cairo_image_surface_get_width(surface); int width = cairo_image_surface_get_width(surface);
int height = cairo_image_surface_get_height(surface); int height = cairo_image_surface_get_height(surface);
int stride = cairo_image_surface_get_stride(surface); int stride = cairo_image_surface_get_stride(surface);
unsigned char* data = cairo_image_surface_get_data(surface); unsigned char* data = cairo_image_surface_get_data(surface);
/* Flush pending operations to surface */ /* Simple palette map */
cairo_surface_flush(surface); __guac_palette palette[0xFFF] = {{0}};
int colors = 0;
for (y=0; y<height; y++) {
for (x=0; x<width; x++) {
/* Get pixel color */
int color = ((uint32_t*) data)[x] & 0xFFFFFF;
/* Calculate hash code */
int hash = ((color & 0xFFF000) >> 12) ^ (color & 0xFFF);
__guac_palette* entry;
/* Search for open palette entry */
for (;;) {
entry = &palette[hash];
/* If we've found a free space, use it */
if (entry->index == 0) {
/* Stop if already at capacity */
if (colors == 256)
return;
/* Add color to map, done */
entry->index = ++colors;
entry->color = color;
break;
/* If not an image surface, fail */
if (data == NULL) {
return -1; /* FIXME: Set guac_error, etc? */
} }
/* Otherwise, if already stored here, done */
if (entry->color == color)
break;
/* Otherwise, collision. Move on to another bucket */
hash = (hash+1) & 0xFFF;
}
}
/* Advance to next data row */
data += stride;
}
fprintf(stderr, "%i colors!\n", colors);
}
png_byte** __guac_create_png_rgb(cairo_surface_t* surface, int alpha) {
png_byte** png_rows;
int x, y;
int width = cairo_image_surface_get_width(surface);
int height = cairo_image_surface_get_height(surface);
int stride = cairo_image_surface_get_stride(surface);
unsigned char* data = cairo_image_surface_get_data(surface);
/* Fail if not an image surface */
if (data == NULL)
return NULL;
int bpp;
if (alpha) bpp = 4;
else bpp = 3;
/* Copy data from surface into PNG data */ /* Copy data from surface into PNG data */
png_rows = (png_byte**) malloc(sizeof(png_byte*) * height); png_rows = (png_byte**) malloc(sizeof(png_byte*) * height);
for (y=0; y<height; y++) { for (y=0; y<height; y++) {
/* Allocate new PNG row */ /* Allocate new PNG row */
png_byte* row = (png_byte*) malloc(sizeof(png_byte) * width * 3); png_byte* row = (png_byte*) malloc(sizeof(png_byte) * width * bpp);
png_rows[y] = row; png_rows[y] = row;
/* Copy data from surface into current row */ /* Copy data from surface into current row */
for (x=0; x<width; x++) { for (x=0; x<width; x++) {
row[3*x] = data[4*x+2]; row[bpp*x] = data[4*x+2];
row[3*x+1] = data[4*x+1]; row[bpp*x+1] = data[4*x+1];
row[3*x+2] = data[4*x]; row[bpp*x+2] = data[4*x];
if (alpha)
row[bpp*x+3] = data[4*x+3];
} }
/* Advance to next data row */ /* Advance to next data row */
@ -197,6 +263,56 @@ int __guac_socket_write_length_png(guac_socket* socket, cairo_surface_t* surface
} }
return png_rows;
}
void __guac_free_png(png_byte** png_rows, int height) {
int y;
/* Free PNG data */
for (y=0; y<height; y++)
free(png_rows[y]);
free(png_rows);
}
int __guac_socket_write_length_png(guac_socket* socket, cairo_surface_t* surface) {
png_structp png;
png_infop png_info;
png_byte** png_rows;
int png_format;
__guac_socket_write_png_data png_data;
int base64_length;
/* Get image surface properties and data */
cairo_format_t format = cairo_image_surface_get_format(surface);
int width = cairo_image_surface_get_width(surface);
int height = cairo_image_surface_get_height(surface);
/* Flush pending operations to surface */
cairo_surface_flush(surface);
if (format == CAIRO_FORMAT_RGB24) {
__guac_create_palette(surface);
png_rows = __guac_create_png_rgb(surface, 0);
png_format = PNG_COLOR_TYPE_RGB;
}
else if (format == CAIRO_FORMAT_ARGB32) {
png_rows = __guac_create_png_rgb(surface, 1);
png_format = PNG_COLOR_TYPE_RGB_ALPHA;
}
else
return -1; /* FIXME: Format not yet supported */
/* If not an image surface, fail */
if (png_rows == NULL) {
return -1; /* FIXME: Set guac_error, etc? */
}
/* Set up PNG writer */ /* Set up PNG writer */
png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png) { if (!png) {
@ -233,7 +349,7 @@ int __guac_socket_write_length_png(guac_socket* socket, cairo_surface_t* surface
width, width,
height, height,
8, 8,
PNG_COLOR_TYPE_RGB, png_format,
PNG_INTERLACE_NONE, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_DEFAULT
@ -246,10 +362,7 @@ int __guac_socket_write_length_png(guac_socket* socket, cairo_surface_t* surface
/* Finish write */ /* Finish write */
png_destroy_write_struct(&png, &png_info); png_destroy_write_struct(&png, &png_info);
/* Free PNG data */ __guac_free_png(png_rows, height);
for (y=0; y<height; y++)
free(png_rows[y]);
free(png_rows);
base64_length = (png_data.data_size + 2) / 3 * 4; base64_length = (png_data.data_size + 2) / 3 * 4;