cscg24-guacamole

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

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