Blame src/gd_webp.c

Packit Service df60bb
/**
Packit Service df60bb
 * File: WebP IO
Packit Service df60bb
 *
Packit Service df60bb
 * Read and write WebP images.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
#ifdef HAVE_CONFIG_H
Packit Service df60bb
#include "config.h"
Packit Service df60bb
#endif /* HAVE_CONFIG_H */
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
#ifdef HAVE_LIBWEBP
Packit Service df60bb
#include <stdio.h>
Packit Service df60bb
#include <math.h>
Packit Service df60bb
#include <string.h>
Packit Service df60bb
#include <stdlib.h>
Packit Service df60bb
#include "gd.h"
Packit Service df60bb
#include "gd_errors.h"
Packit Service df60bb
#include "gdhelpers.h"
Packit Service df60bb
#include "webp/decode.h"
Packit Service df60bb
#include "webp/encode.h"
Packit Service df60bb
Packit Service df60bb
#define GD_WEBP_ALLOC_STEP (4*1024)
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromWebp
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromWebp> is called to load truecolor images from
Packit Service df60bb
    WebP format files. Invoke <gdImageCreateFromWebp> with an
Packit Service df60bb
    already opened pointer to a file containing the desired
Packit Service df60bb
    image. <gdImageCreateFromWebp> returns a <gdImagePtr> to the new
Packit Service df60bb
    truecolor image, or NULL if unable to load the image (most often
Packit Service df60bb
    because the file is corrupt or does not contain a WebP
Packit Service df60bb
    image). <gdImageCreateFromWebp> does not close the file.
Packit Service df60bb
Packit Service df60bb
    You can inspect the sx and sy members of the image to determine
Packit Service df60bb
    its size. The image must eventually be destroyed using
Packit Service df60bb
    <gdImageDestroy>.
Packit Service df60bb
Packit Service df60bb
    *The returned image is always a truecolor image.*
Packit Service df60bb
Packit Service df60bb
  Variants:
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromJpegPtr> creates an image from WebP data
Packit Service df60bb
    already in memory.
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromJpegCtx> reads its data via the function
Packit Service df60bb
    pointers in a <gdIOCtx> structure.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    infile - The input FILE pointer.
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    A pointer to the new *truecolor* image.  This will need to be
Packit Service df60bb
    destroyed with <gdImageDestroy> once it is no longer needed.
Packit Service df60bb
Packit Service df60bb
    On error, returns NULL.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewFileCtx(inFile);
Packit Service df60bb
	if (!in) {
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
	im = gdImageCreateFromWebpCtx(in);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromWebpPtr
Packit Service df60bb
Packit Service df60bb
    See <gdImageCreateFromWebp>.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    size            - size of WebP data in bytes.
Packit Service df60bb
    data            - pointer to WebP data.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
Packit Service df60bb
	if (!in)
Packit Service df60bb
		return 0;
Packit Service df60bb
	im = gdImageCreateFromWebpCtx(in);
Packit Service df60bb
	in->gd_free(in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromWebpCtx
Packit Service df60bb
Packit Service df60bb
    See <gdImageCreateFromWebp>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx (gdIOCtx * infile)
Packit Service df60bb
{
Packit Service df60bb
	int    width, height;
Packit Service df60bb
	uint8_t   *filedata = NULL;
Packit Service df60bb
	uint8_t    *argb = NULL;
Packit Service df60bb
	unsigned char   *read, *temp;
Packit Service df60bb
	size_t size = 0, n;
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	int x, y;
Packit Service df60bb
	uint8_t *p;
Packit Service df60bb
Packit Service df60bb
	do {
Packit Service df60bb
		temp = gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
Packit Service df60bb
		if (temp) {
Packit Service df60bb
			filedata = temp;
Packit Service df60bb
			read = temp + size;
Packit Service df60bb
		} else {
Packit Service df60bb
			if (filedata) {
Packit Service df60bb
				gdFree(filedata);
Packit Service df60bb
			}
Packit Service df60bb
			gd_error("WebP decode: realloc failed");
Packit Service df60bb
			return NULL;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		n = gdGetBuf(read, GD_WEBP_ALLOC_STEP, infile);
Packit Service df60bb
		if (n>0 && n!=EOF) {
Packit Service df60bb
			size += n;
Packit Service df60bb
		}
Packit Service df60bb
	} while (n>0 && n!=EOF);
Packit Service df60bb
Packit Service df60bb
	if (WebPGetInfo(filedata,size, &width, &height) == 0) {
Packit Service df60bb
		gd_error("gd-webp cannot get webp info");
Packit Service df60bb
		gdFree(temp);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	im = gdImageCreateTrueColor(width, height);
Packit Service df60bb
	if (!im) {
Packit Service df60bb
		gdFree(temp);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
	argb = WebPDecodeARGB(filedata, size, &width, &height);
Packit Service df60bb
	if (!argb) {
Packit Service df60bb
		gd_error("gd-webp cannot allocate temporary buffer");
Packit Service df60bb
		gdFree(temp);
Packit Service df60bb
		gdImageDestroy(im);
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
	for (y = 0, p = argb;  y < height; y++) {
Packit Service df60bb
		for (x = 0; x < width; x++) {
Packit Service df60bb
			register uint8_t a = gdAlphaMax - (*(p++) >> 1);
Packit Service df60bb
			register uint8_t r = *(p++);
Packit Service df60bb
			register uint8_t g = *(p++);
Packit Service df60bb
			register uint8_t b = *(p++);
Packit Service df60bb
			im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a);
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	/* do not use gdFree here, in case gdFree/alloc is mapped to something else than libc */
Packit Service df60bb
	free(argb);
Packit Service df60bb
	gdFree(temp);
Packit Service df60bb
	im->saveAlphaFlag = 1;
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/* returns 0 on success, 1 on failure */
Packit Service df60bb
static int _gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
Packit Service df60bb
{
Packit Service df60bb
	uint8_t *argb;
Packit Service df60bb
	int x, y;
Packit Service df60bb
	uint8_t *p;
Packit Service df60bb
	uint8_t *out;
Packit Service df60bb
	size_t out_size;
Packit Service df60bb
    int ret = 0;
Packit Service df60bb
Packit Service df60bb
	if (im == NULL) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (!gdImageTrueColor(im)) {
Packit Service df60bb
		gd_error("Palette image not supported by webp");
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (quality == -1) {
Packit Service df60bb
		quality = 80;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (overflow2(gdImageSX(im), 4)) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	if (overflow2(gdImageSX(im) * 4, gdImageSY(im))) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
Packit Service df60bb
	if (!argb) {
Packit Service df60bb
		return 1;
Packit Service df60bb
	}
Packit Service df60bb
	p = argb;
Packit Service df60bb
	for (y = 0; y < gdImageSY(im); y++) {
Packit Service df60bb
		for (x = 0; x < gdImageSX(im); x++) {
Packit Service df60bb
			register int c;
Packit Service df60bb
			register char a;
Packit Service df60bb
			c = im->tpixels[y][x];
Packit Service df60bb
			a = gdTrueColorGetAlpha(c);
Packit Service df60bb
			if (a == 127) {
Packit Service df60bb
				a = 0;
Packit Service df60bb
			} else {
Packit Service df60bb
				a = 255 - ((a << 1) + (a >> 6));
Packit Service df60bb
			}
Packit Service df60bb
			*(p++) = gdTrueColorGetRed(c);
Packit Service df60bb
			*(p++) = gdTrueColorGetGreen(c);
Packit Service df60bb
			*(p++) = gdTrueColorGetBlue(c); 
Packit Service df60bb
			*(p++) = a;
Packit Service df60bb
		}
Packit Service df60bb
	}
Packit Service df60bb
	out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quality, &out;;
Packit Service df60bb
	if (out_size == 0) {
Packit Service df60bb
		gd_error("gd-webp encoding failed");
Packit Service df60bb
        ret = 1;
Packit Service df60bb
		goto freeargb;
Packit Service df60bb
	}
Packit Service df60bb
	gdPutBuf(out, out_size, outfile);
Packit Service df60bb
	free(out);
Packit Service df60bb
Packit Service df60bb
freeargb:
Packit Service df60bb
	gdFree(argb);
Packit Service df60bb
Packit Service df60bb
    return ret;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageWebpCtx
Packit Service df60bb
Packit Service df60bb
    Write the image as WebP data via a <gdIOCtx>. See <gdImageWebpEx>
Packit Service df60bb
    for more details.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    im      - The image to write.
Packit Service df60bb
    outfile - The output sink.
Packit Service df60bb
    quality - Image quality.
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    Nothing.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quality)
Packit Service df60bb
{
Packit Service df60bb
	_gdImageWebpCtx(im, outfile, quality);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageWebpEx
Packit Service df60bb
Packit Service df60bb
    <gdImageWebpEx> outputs the specified image to the specified file in
Packit Service df60bb
    WebP format. The file must be open for writing. Under MSDOS and
Packit Service df60bb
    all versions of Windows, it is important to use "wb" as opposed to
Packit Service df60bb
    simply "w" as the mode when opening the file, and under Unix there
Packit Service df60bb
    is no penalty for doing so. <gdImageWebpEx> does not close the file;
Packit Service df60bb
    your code must do so.
Packit Service df60bb
Packit Service df60bb
	If _quality_ is -1, a reasonable quality value (which should yield a
Packit Service df60bb
	good general quality / size tradeoff for most situations) is used. Otherwise
Packit Service df60bb
	_quality_ should be a value in the range 0-100, higher quality values
Packit Service df60bb
	usually implying both higher quality and larger image sizes.
Packit Service df60bb
Packit Service df60bb
  Variants:
Packit Service df60bb
Packit Service df60bb
    <gdImageWebpCtx> stores the image using a <gdIOCtx> struct.
Packit Service df60bb
Packit Service df60bb
    <gdImageWebpPtrEx> stores the image to RAM.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    im      - The image to save.
Packit Service df60bb
    outFile - The FILE pointer to write to.
Packit Service df60bb
    quality - Compression quality (0-100).
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    Nothing.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quality)
Packit Service df60bb
{
Packit Service df60bb
	gdIOCtx *out = gdNewFileCtx(outFile);
Packit Service df60bb
	if (out == NULL) {
Packit Service df60bb
		return;
Packit Service df60bb
	}
Packit Service df60bb
	_gdImageWebpCtx(im, out, quality);
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageWebp
Packit Service df60bb
Packit Service df60bb
    Variant of <gdImageWebpEx> which uses the default quality (-1).
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    im      - The image to save
Packit Service df60bb
    outFile - The FILE pointer to write to.
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    Nothing.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile)
Packit Service df60bb
{
Packit Service df60bb
	gdIOCtx *out = gdNewFileCtx(outFile);
Packit Service df60bb
	if (out == NULL) {
Packit Service df60bb
		return;
Packit Service df60bb
	}
Packit Service df60bb
	_gdImageWebpCtx(im, out, -1);
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageWebpPtr
Packit Service df60bb
Packit Service df60bb
    See <gdImageWebpEx>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size)
Packit Service df60bb
{
Packit Service df60bb
	void *rv;
Packit Service df60bb
	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
Packit Service df60bb
	if (out == NULL) {
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
	if (_gdImageWebpCtx(im, out, -1)) {
Packit Service df60bb
		rv = NULL;
Packit Service df60bb
	} else {
Packit Service df60bb
		rv = gdDPExtractData(out, size);
Packit Service df60bb
	}
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
Packit Service df60bb
	return rv;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageWebpPtrEx
Packit Service df60bb
Packit Service df60bb
    See <gdImageWebpEx>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quality)
Packit Service df60bb
{
Packit Service df60bb
	void *rv;
Packit Service df60bb
	gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
Packit Service df60bb
	if (out == NULL) {
Packit Service df60bb
		return NULL;
Packit Service df60bb
	}
Packit Service df60bb
	if (_gdImageWebpCtx(im, out, quality)) {
Packit Service df60bb
        rv = NULL;
Packit Service df60bb
    } else {
Packit Service df60bb
        rv = gdDPExtractData(out, size);
Packit Service df60bb
    }
Packit Service df60bb
	out->gd_free(out);
Packit Service df60bb
	return rv;
Packit Service df60bb
}
Packit Service df60bb
#endif /* HAVE_LIBWEBP */