| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include "config.h" |
| #include "display.h" |
| #include "image-stream.h" |
| #include "jpeg.h" |
| #include "log.h" |
| #include "png.h" |
| |
| #ifdef ENABLE_WEBP |
| #include "webp.h" |
| #endif |
| |
| #include <cairo/cairo.h> |
| |
| #include <stdlib.h> |
| #include <string.h> |
| |
| guacenc_decoder_mapping guacenc_decoder_map[] = { |
| {"image/png", guacenc_png_decoder}, |
| {"image/jpeg", guacenc_jpeg_decoder}, |
| #ifdef ENABLE_WEBP |
| {"image/webp", guacenc_webp_decoder}, |
| #endif |
| {NULL, NULL} |
| }; |
| |
| guacenc_decoder* guacenc_get_decoder(const char* mimetype) { |
| |
| /* Search through mapping for the decoder having given mimetype */ |
| guacenc_decoder_mapping* current = guacenc_decoder_map; |
| while (current->mimetype != NULL) { |
| |
| /* Return decoder if mimetype matches */ |
| if (strcmp(current->mimetype, mimetype) == 0) |
| return current->decoder; |
| |
| /* Next candidate decoder */ |
| current++; |
| |
| } |
| |
| /* No such decoder */ |
| guacenc_log(GUAC_LOG_WARNING, "Support for \"%s\" not present", mimetype); |
| return NULL; |
| |
| } |
| |
| guacenc_image_stream* guacenc_image_stream_alloc(int mask, int index, |
| const char* mimetype, int x, int y) { |
| |
| /* Allocate stream */ |
| guacenc_image_stream* stream = malloc(sizeof(guacenc_image_stream)); |
| if (stream == NULL) |
| return NULL; |
| |
| /* Init properties */ |
| stream->index = index; |
| stream->mask = mask; |
| stream->x = x; |
| stream->y = y; |
| |
| /* Associate with corresponding decoder */ |
| stream->decoder = guacenc_get_decoder(mimetype); |
| |
| /* Allocate initial buffer */ |
| stream->length = 0; |
| stream->max_length = GUACENC_IMAGE_STREAM_INITIAL_LENGTH; |
| stream->buffer = (unsigned char*) malloc(stream->max_length); |
| |
| return stream; |
| |
| } |
| |
| int guacenc_image_stream_receive(guacenc_image_stream* stream, |
| unsigned char* data, int length) { |
| |
| /* Allocate more space if necessary */ |
| if (stream->max_length - stream->length < length) { |
| |
| /* Calculate a reasonable new max length guaranteed to fit buffer */ |
| int new_max_length = stream->max_length * 2 + length; |
| |
| /* Attempt to resize buffer */ |
| unsigned char* new_buffer = |
| (unsigned char*) realloc(stream->buffer, new_max_length); |
| if (new_buffer == NULL) |
| return 1; |
| |
| /* Store updated buffer and size */ |
| stream->buffer = new_buffer; |
| stream->max_length = new_max_length; |
| |
| } |
| |
| /* Append data */ |
| memcpy(stream->buffer + stream->length, data, length); |
| stream->length += length; |
| return 0; |
| |
| } |
| |
| int guacenc_image_stream_end(guacenc_image_stream* stream, |
| guacenc_buffer* buffer) { |
| |
| /* If there is no decoder, simply return success */ |
| guacenc_decoder* decoder = stream->decoder; |
| if (decoder == NULL) |
| return 0; |
| |
| /* Decode received data to a Cairo surface */ |
| cairo_surface_t* surface = stream->decoder(stream->buffer, stream->length); |
| if (surface == NULL) |
| return 1; |
| |
| /* Get surface dimensions */ |
| int width = cairo_image_surface_get_width(surface); |
| int height = cairo_image_surface_get_height(surface); |
| |
| /* Expand the buffer as necessary to fit the draw operation */ |
| if (buffer->autosize) |
| guacenc_buffer_fit(buffer, stream->x + width, stream->y + height); |
| |
| /* Draw surface to buffer */ |
| if (buffer->cairo != NULL) { |
| cairo_set_operator(buffer->cairo, guacenc_display_cairo_operator(stream->mask)); |
| cairo_set_source_surface(buffer->cairo, surface, stream->x, stream->y); |
| cairo_rectangle(buffer->cairo, stream->x, stream->y, width, height); |
| cairo_fill(buffer->cairo); |
| } |
| |
| cairo_surface_destroy(surface); |
| return 0; |
| |
| } |
| |
| int guacenc_image_stream_free(guacenc_image_stream* stream) { |
| |
| /* Ignore NULL streams */ |
| if (stream == NULL) |
| return 0; |
| |
| /* Free image buffer */ |
| free(stream->buffer); |
| |
| /* Free actual stream */ |
| free(stream); |
| return 0; |
| |
| } |
| |