root/ext/gd/libgd/gd_webp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gdWebpGetVersionString
  2. gdImageCreateFromWebp
  3. gdImageCreateFromWebpPtr
  4. gdImageCreateFromWebpCtx
  5. gdImageWebpEx
  6. gdImageWebp
  7. gdImageWebpPtr
  8. gdImageWebpPtrEx
  9. mapQualityToVP8QP
  10. gdImageWebpCtx

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "gd.h"


#ifdef HAVE_LIBVPX
#include "webpimg.h"
#include "gdhelpers.h"

extern void gd_YUV420toRGBA(uint8* Y,
                  uint8* U,
                  uint8* V,
                  gdImagePtr im);

extern void gd_RGBAToYUV420(gdImagePtr im2,
                  uint8* Y,
                  uint8* U,
                  uint8* V);

const char * gdWebpGetVersionString()
{
        return "not defined";
}

gdImagePtr gdImageCreateFromWebp (FILE * inFile)
{
        gdImagePtr im;
        gdIOCtx *in = gdNewFileCtx(inFile);
        im = gdImageCreateFromWebpCtx(in);
        in->gd_free(in);

        return im;
}

gdImagePtr gdImageCreateFromWebpPtr (int size, void *data)
{
        int    width, height, ret;
        unsigned char   *Y = NULL;
        unsigned char   *U = NULL;
        unsigned char   *V = NULL;
        gdImagePtr im;

        ret = WebPDecode(data, size, &Y, &U, &V, &width, &height);
        if (ret != webp_success) {
                if (Y) free(Y);
                if (U) free(U);
                if (V) free(V);
                php_gd_error("WebP decode: fail to decode input data");
                return NULL;
        }
        im = gdImageCreateTrueColor(width, height);
        if (!im) {
                return NULL;
        }
        gd_YUV420toRGBA(Y, U, V, im);
        return im;
}

#define GD_WEBP_ALLOC_STEP (4*1024)

gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
{
        int    width, height, ret;
        unsigned char   *filedata = NULL;
        unsigned char   *read, *temp;
        unsigned char   *Y = NULL;
        unsigned char   *U = NULL;
        unsigned char   *V = NULL;
        size_t size = 0, n;
        gdImagePtr im;

        do {
                temp = gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
                if (temp) {
                        filedata = temp;
                        read = temp + size;
                } else {
                        if (filedata) {
                                gdFree(filedata);
                        }
                        php_gd_error("WebP decode: realloc failed");
                        return NULL;
                }

                n = gdGetBuf(read, GD_WEBP_ALLOC_STEP, infile);
                /* differs from upstream where gdGetBuf return 0 instead of EOF */
                if (n>0 && n!=EOF) {
                        size += n;
                }
        } while (n>0 && n!=EOF);

        ret = WebPDecode(filedata, size, &Y, &U, &V, &width, &height);
        gdFree(filedata);
        if (ret != webp_success) {
                if (Y) free(Y);
                if (U) free(U);
                if (V) free(V);
                php_gd_error("WebP decode: fail to decode input data");
                return NULL;
        }
        im = gdImageCreateTrueColor(width, height);
        gd_YUV420toRGBA(Y, U, V, im);
        return im;
}

void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
{
        gdIOCtx *out = gdNewFileCtx(outFile);
        gdImageWebpCtx(im, out, quantization);
        out->gd_free(out);
}

void gdImageWebp (gdImagePtr im, FILE * outFile)
{
        gdIOCtx *out = gdNewFileCtx(outFile);
        gdImageWebpCtx(im, out, -1);
        out->gd_free(out);
}

void * gdImageWebpPtr (gdImagePtr im, int *size)
{
        void *rv;
        gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
        gdImageWebpCtx(im, out, -1);
        rv = gdDPExtractData(out, size);
        out->gd_free(out);

        return rv;
}

void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization)
{
        void *rv;
        gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
        gdImageWebpCtx(im, out, quantization);
        rv = gdDPExtractData(out, size);
        out->gd_free(out);
        return rv;
}

/*
 * Maps normalized QP (quality) to VP8 QP
 */
int mapQualityToVP8QP(int quality) {
#define MIN_QUALITY 0
#define MAX_QUALITY 100
#define MIN_VP8QP 1
#define MAX_VP8QP 63
        const float scale = MAX_VP8QP - MIN_VP8QP;
        const float vp8qp =
        scale * (MAX_QUALITY - quality) / (MAX_QUALITY - MIN_QUALITY) + MIN_VP8QP;
        if (quality < MIN_QUALITY || quality > MAX_QUALITY) {
                php_gd_error("Wrong quality value %d.", quality);
                return -1;
        }

        return (int)(vp8qp + 0.5);
}

/* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
 *  and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
 *  (http://www.cdrom.com/pub/png/pngbook.html).
 */
void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
{
        int width = im->sx;
        int height = im->sy;
        int colors = im->colorsTotal;
        int *open = im->open;

        int  yuv_width, yuv_height, yuv_nbytes, ret;
        int vp8_quality;
        unsigned char *Y = NULL,
                                  *U = NULL,
                                  *V = NULL;
        unsigned char *filedata = NULL;

        /* Conversion to Y,U,V buffer */
    yuv_width = (width + 1) >> 1;
    yuv_height = (height + 1) >> 1;
    yuv_nbytes = width * height + 2 * yuv_width * yuv_height;

    if ((Y = (unsigned char *)gdCalloc(yuv_nbytes, sizeof(unsigned char))) == NULL) {
        php_gd_error("gd-webp error: cannot allocate Y buffer");
        return;
    }
        vp8_quality = mapQualityToVP8QP(quantization);

    U = Y + width * height;
    V = U + yuv_width * yuv_height;
    gd_RGBAToYUV420(im, Y, U, V);

        /* Encode Y,U,V and write data to file */
    ret = WebPEncode(Y, U, V, width, height, width, yuv_width, yuv_height, yuv_width,
                     vp8_quality, &filedata, &yuv_nbytes, NULL);
        gdFree(Y);

    if (ret != webp_success) {
        if (filedata) {
                free(filedata);
                }
                php_gd_error("gd-webp error: WebP Encoder failed");
                return;
    }

    gdPutBuf (filedata, yuv_nbytes, outfile);
    free(filedata);
}

#endif /* HAVE_LIBVPX */

/* [<][>][^][v][top][bottom][index][help] */