jpeg.c (4537B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21#include "jpeg.h" 22#include "log.h" 23 24#include <stdio.h> 25#include <unistd.h> 26 27#include <cairo/cairo.h> 28#include <guacamole/mem.h> 29#include <jpeglib.h> 30 31#include <stdlib.h> 32 33/** 34 * Translates libjpeg's 24-bit RGB format into Cairo's 32-bit ARGB32 / RGB24 35 * format. The red, green, and blue components from the libjpeg pixel are 36 * copied verbatim, while the extra high byte used within Cairo is set to 0xFF. 37 * 38 * @param src 39 * A pointer to the first byte of the 24-bit RGB pixel within a libjpeg 40 * scanline buffer. 41 * 42 * @return 43 * A 32-bit Cairo ARGB32 / RGB24 pixel value equivalent to the libjpeg 44 * pixel at the given pointer. 45 */ 46static uint32_t guacenc_jpeg_translate_rgb(const unsigned char* src) { 47 48 /* Pull components from source */ 49 int r = *(src++); 50 int g = *(src++); 51 int b = *(src++); 52 53 /* Translate to 32-bit integer compatible with Cairo */ 54 return 0xFF000000 | (r << 16) | (g << 8) | b; 55 56} 57 58/** 59 * Copies the data from a libjpeg scanline buffer into a row of image data 60 * within a Cairo surface, translating each pixel as necessary. 61 * 62 * @param dst 63 * The destination buffer into which the scanline should be copied. 64 * 65 * @param src 66 * The libjpeg scanline buffer that should be copied into the 67 * destination buffer. 68 * 69 * @param width 70 * The number of pixels available within both the scanline buffer and the 71 * destination buffer. 72 */ 73static void guacenc_jpeg_copy_scanline(unsigned char* dst, 74 const unsigned char* src, int width) { 75 76 uint32_t* current = (uint32_t*) dst; 77 78 /* Copy all pixels from source to destination, translating for Cairo */ 79 for (; width > 0; width--, src += 3) { 80 *(current++) = guacenc_jpeg_translate_rgb(src); 81 } 82 83} 84 85cairo_surface_t* guacenc_jpeg_decoder(unsigned char* data, int length) { 86 87 struct jpeg_decompress_struct cinfo; 88 struct jpeg_error_mgr jerr; 89 90 /* Create decompressor with standard error handling */ 91 jpeg_create_decompress(&cinfo); 92 cinfo.err = jpeg_std_error(&jerr); 93 94 /* Read JPEG directly from memory buffer */ 95 jpeg_mem_src(&cinfo, data, length); 96 97 /* Read and validate JPEG header */ 98 if (!jpeg_read_header(&cinfo, TRUE)) { 99 guacenc_log(GUAC_LOG_WARNING, "Invalid JPEG data"); 100 jpeg_destroy_decompress(&cinfo); 101 return NULL; 102 } 103 104 /* Begin decompression */ 105 cinfo.out_color_space = JCS_RGB; 106 jpeg_start_decompress(&cinfo); 107 108 /* Pull JPEG dimensions from decompressor */ 109 int width = cinfo.output_width; 110 int height = cinfo.output_height; 111 112 /* Allocate sufficient buffer space for one JPEG scanline */ 113 unsigned char* jpeg_scanline = guac_mem_alloc(width, 3); 114 115 /* Create blank Cairo surface (no transparency in JPEG) */ 116 cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, 117 width, height); 118 119 /* Pull underlying buffer and its stride */ 120 int stride = cairo_image_surface_get_stride(surface); 121 unsigned char* row = cairo_image_surface_get_data(surface); 122 123 /* Read JPEG into surface */ 124 while (cinfo.output_scanline < height) { 125 126 /* Read single scanline */ 127 unsigned char* buffers[1] = { jpeg_scanline }; 128 jpeg_read_scanlines(&cinfo, buffers, 1); 129 130 /* Copy scanline to Cairo surface */ 131 guacenc_jpeg_copy_scanline(row, jpeg_scanline, width); 132 133 /* Advance to next row of Cairo surface */ 134 row += stride; 135 136 } 137 138 /* Scanline buffer is no longer needed */ 139 guac_mem_free(jpeg_scanline); 140 141 /* End decompression */ 142 jpeg_finish_decompress(&cinfo); 143 144 /* Free decompressor */ 145 jpeg_destroy_decompress(&cinfo); 146 147 /* JPEG was read successfully */ 148 return surface; 149 150} 151