int guac_webp_write()

in src/libguac/encode-webp.c [165:263]


int guac_webp_write(guac_socket* socket, guac_stream* stream,
        cairo_surface_t* surface, int quality, int lossless) {

    guac_webp_stream_writer writer;
    WebPPicture picture;
    uint32_t* argb_output;

    int x, y;

    int width = cairo_image_surface_get_width(surface);
    int height = cairo_image_surface_get_height(surface);
    int stride = cairo_image_surface_get_stride(surface);
    cairo_format_t format = cairo_image_surface_get_format(surface);
    unsigned char* data = cairo_image_surface_get_data(surface);

    if (format != CAIRO_FORMAT_RGB24 && format != CAIRO_FORMAT_ARGB32) {
        guac_error = GUAC_STATUS_INTERNAL_ERROR;
        guac_error_message = "Invalid Cairo image format. Unable to create WebP.";
        return -1;
    }

    /* Flush pending operations to surface */
    cairo_surface_flush(surface);

    /* Configure WebP compression bits */
    WebPConfig config;
    if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality))
        return -1;

    /* Add additional tuning */
    config.lossless = lossless;
    config.quality = quality;
    config.thread_level = 0; /* NOT multi-threaded (threading results in unnecessary overhead vs. the worker threads used by guac_display) */
    config.method = 2; /* Compression method (0=fast/larger, 6=slow/smaller) */

    /* Validate configuration */
    if (!WebPValidateConfig(&config)) {
        return -1;
    }

    /* Set up WebP picture */
    if (!WebPPictureInit(&picture)) {
        return -1;
    }
    picture.use_argb = 1;
    picture.width = width;
    picture.height = height;

    /* Allocate and init writer */
    if (!WebPPictureAlloc(&picture)) {
        return -1;
    }
    picture.writer = guac_webp_stream_write;
    picture.custom_ptr = &writer;
    guac_webp_stream_writer_init(&writer, socket, stream);

    /* Copy image data into WebP picture */
    argb_output = picture.argb;
    for (y = 0; y < height; y++) {

        /* Get pixels at start of each row */
        uint32_t* src = (uint32_t*) data;
        uint32_t* dst = argb_output;

        /* For each pixel in row */
        for (x = 0; x < width; x++) {

            /* Pull pixel data, removing alpha channel if necessary */
            uint32_t src_pixel = *src;
            if (format != CAIRO_FORMAT_ARGB32)
                src_pixel |= 0xFF000000;

            /* Store converted pixel data */
            *dst = src_pixel;

            /* Next pixel */
            src++;
            dst++;

        }

        /* Next row */
        data += stride;
        argb_output += picture.argb_stride;

    }

    /* Encode image */
    const int result = WebPEncode(&config, &picture) ? 0 : -1;

    /* Free picture */
    WebPPictureFree(&picture);

    /* Ensure all data is written */
    guac_webp_flush_data(&writer);

    return result;

}