in src/libguac/encode-jpeg.c [168:266]
int guac_jpeg_write(guac_socket* socket, guac_stream* stream,
cairo_surface_t* surface, int quality) {
/* Get image surface properties and data */
cairo_format_t format = cairo_image_surface_get_format(surface);
if (format != CAIRO_FORMAT_RGB24) {
guac_error = GUAC_STATUS_INTERNAL_ERROR;
guac_error_message =
"Invalid Cairo image format. Unable to create JPEG.";
return -1;
}
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);
/* Flush pending operations to surface */
cairo_surface_flush(surface);
/* Prepare JPEG bits */
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
/* Write JPEG directly to given stream */
jpeg_guac_dest(&cinfo, socket, stream);
cinfo.image_width = width; /* image width and height, in pixels */
cinfo.image_height = height;
cinfo.arith_code = TRUE;
#ifdef JCS_EXTENSIONS
/* The Turbo JPEG extensions allows us to use the Cairo surface
* (BGRx) as input without converting it */
cinfo.input_components = 4;
cinfo.in_color_space = JCS_EXT_BGRX;
#else
/* Standard JPEG supports RGB as input so we will have to convert
* the contents of the Cairo surface from (BGRx) to RGB */
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
/* Create a buffer for the write scan line which is where we will
* put the converted pixels (BGRx -> RGB) */
unsigned char *scanline_data = guac_mem_zalloc(cinfo.image_width, cinfo.input_components);
#endif
/* Initialize the JPEG compressor */
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
jpeg_start_compress(&cinfo, TRUE);
JSAMPROW row_pointer[1]; /* pointer to a single row */
/* Write scanlines to be used in JPEG compression */
while (cinfo.next_scanline < cinfo.image_height) {
int row_offset = stride * cinfo.next_scanline;
#ifdef JCS_EXTENSIONS
/* In Turbo JPEG we can use the raw BGRx scanline */
row_pointer[0] = &data[row_offset];
#else
/* For standard JPEG libraries we have to convert the
* scanline from 24 bit (4 byte) BGRx to 24 bit (3 byte) RGB */
unsigned char *inptr = data + row_offset;
unsigned char *outptr = scanline_data;
for (int x = 0; x < width; ++x) {
outptr[2] = *inptr++; /* B */
outptr[1] = *inptr++; /* G */
outptr[0] = *inptr++; /* R */
inptr++; /* skip the upper byte (x/A) */
outptr += 3;
}
row_pointer[0] = scanline_data;
#endif
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
#ifndef JCS_EXTENSIONS
guac_mem_free(scanline_data);
#endif
/* Finalize compression */
jpeg_finish_compress(&cinfo);
/* Clean up */
jpeg_destroy_compress(&cinfo);
return 0;
}