|
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 */
|