cscg24-guacamole

CSCG 2024 Challenge 'Guacamole Mashup'
git clone https://git.sinitax.com/sinitax/cscg24-guacamole
Log | Files | Refs | sfeed.txt

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