image-stream.c (4871B)
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 "display.h" 22#include "image-stream.h" 23#include "jpeg.h" 24#include "log.h" 25#include "png.h" 26 27#ifdef ENABLE_WEBP 28#include "webp.h" 29#endif 30 31#include <cairo/cairo.h> 32#include <guacamole/mem.h> 33 34#include <stdlib.h> 35#include <string.h> 36 37guacenc_decoder_mapping guacenc_decoder_map[] = { 38 {"image/png", guacenc_png_decoder}, 39 {"image/jpeg", guacenc_jpeg_decoder}, 40#ifdef ENABLE_WEBP 41 {"image/webp", guacenc_webp_decoder}, 42#endif 43 {NULL, NULL} 44}; 45 46guacenc_decoder* guacenc_get_decoder(const char* mimetype) { 47 48 /* Search through mapping for the decoder having given mimetype */ 49 guacenc_decoder_mapping* current = guacenc_decoder_map; 50 while (current->mimetype != NULL) { 51 52 /* Return decoder if mimetype matches */ 53 if (strcmp(current->mimetype, mimetype) == 0) 54 return current->decoder; 55 56 /* Next candidate decoder */ 57 current++; 58 59 } 60 61 /* No such decoder */ 62 guacenc_log(GUAC_LOG_WARNING, "Support for \"%s\" not present", mimetype); 63 return NULL; 64 65} 66 67guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index, 68 const char* mimetype, int x, int y) { 69 70 /* Allocate stream */ 71 guacenc_image_stream* stream = guac_mem_alloc(sizeof(guacenc_image_stream)); 72 if (stream == NULL) 73 return NULL; 74 75 /* Init properties */ 76 stream->index = index; 77 stream->mask = mask; 78 stream->x = x; 79 stream->y = y; 80 81 /* Associate with corresponding decoder */ 82 stream->decoder = guacenc_get_decoder(mimetype); 83 84 /* Allocate initial buffer */ 85 stream->length = 0; 86 stream->max_length = GUACENC_IMAGE_STREAM_INITIAL_LENGTH; 87 stream->buffer = (unsigned char*) guac_mem_alloc(stream->max_length); 88 89 return stream; 90 91} 92 93int guacenc_image_stream_receive(guacenc_image_stream* stream, 94 unsigned char* data, int length) { 95 96 /* Allocate more space if necessary */ 97 if (stream->max_length - stream->length < length) { 98 99 /* Calculate a reasonable new max length guaranteed to fit buffer */ 100 size_t new_max_length = guac_mem_ckd_add_or_die( 101 guac_mem_ckd_mul_or_die(stream->max_length, 2), length); 102 103 /* Attempt to resize buffer */ 104 unsigned char* new_buffer = 105 (unsigned char*) guac_mem_realloc(stream->buffer, new_max_length); 106 if (new_buffer == NULL) 107 return 1; 108 109 /* Store updated buffer and size */ 110 stream->buffer = new_buffer; 111 stream->max_length = new_max_length; 112 113 } 114 115 /* Append data */ 116 memcpy(stream->buffer + stream->length, data, length); 117 stream->length += length; 118 return 0; 119 120} 121 122int guacenc_image_stream_end(guacenc_image_stream* stream, 123 guacenc_buffer* buffer) { 124 125 /* If there is no decoder, simply return success */ 126 guacenc_decoder* decoder = stream->decoder; 127 if (decoder == NULL) 128 return 0; 129 130 /* Decode received data to a Cairo surface */ 131 cairo_surface_t* surface = stream->decoder(stream->buffer, stream->length); 132 if (surface == NULL) 133 return 1; 134 135 /* Get surface dimensions */ 136 int width = cairo_image_surface_get_width(surface); 137 int height = cairo_image_surface_get_height(surface); 138 139 /* Expand the buffer as necessary to fit the draw operation */ 140 if (buffer->autosize) 141 guacenc_buffer_fit(buffer, stream->x + width, stream->y + height); 142 143 /* Draw surface to buffer */ 144 if (buffer->cairo != NULL) { 145 cairo_set_operator(buffer->cairo, guacenc_display_cairo_operator(stream->mask)); 146 cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y); 147 cairo_rectangle(buffer->cairo, stream->x, stream->y, width, height); 148 cairo_fill(buffer->cairo); 149 } 150 151 cairo_surface_destroy(surface); 152 return 0; 153 154} 155 156int guacenc_image_stream_free(guacenc_image_stream* stream) { 157 158 /* Ignore NULL streams */ 159 if (stream == NULL) 160 return 0; 161 162 /* Free image buffer */ 163 guac_mem_free(stream->buffer); 164 165 /* Free actual stream */ 166 guac_mem_free(stream); 167 return 0; 168 169} 170