summaryrefslogtreecommitdiff
path: root/ext/gd/libgd
diff options
context:
space:
mode:
Diffstat (limited to 'ext/gd/libgd')
-rw-r--r--ext/gd/libgd/gd.c16
-rw-r--r--ext/gd/libgd/gd.h2
-rw-r--r--ext/gd/libgd/gd_gif_in.c8
-rw-r--r--ext/gd/libgd/gd_gif_out.c6
-rw-r--r--ext/gd/libgd/gd_jpeg.c4
-rw-r--r--ext/gd/libgd/gd_webp.c231
-rw-r--r--ext/gd/libgd/gdft.c15
-rw-r--r--ext/gd/libgd/gdhelpers.h2
-rw-r--r--ext/gd/libgd/gdkanji.c3
-rw-r--r--ext/gd/libgd/gdxpm.c2
-rw-r--r--ext/gd/libgd/webpimg.c914
-rw-r--r--ext/gd/libgd/webpimg.h181
-rw-r--r--ext/gd/libgd/xbm.c2
13 files changed, 136 insertions, 1250 deletions
diff --git a/ext/gd/libgd/gd.c b/ext/gd/libgd/gd.c
index 0b4b42fa27..928fdb89ca 100644
--- a/ext/gd/libgd/gd.c
+++ b/ext/gd/libgd/gd.c
@@ -102,10 +102,9 @@ void php_gd_error_ex(int type, const char *format, ...)
{
va_list args;
- TSRMLS_FETCH();
va_start(args, format);
- php_verror(NULL, "", type, format, args TSRMLS_CC);
+ php_verror(NULL, "", type, format, args);
va_end(args);
}
@@ -113,10 +112,9 @@ void php_gd_error(const char *format, ...)
{
va_list args;
- TSRMLS_FETCH();
va_start(args, format);
- php_verror(NULL, "", E_WARNING, format, args TSRMLS_CC);
+ php_verror(NULL, "", E_WARNING, format, args);
va_end(args);
}
@@ -3144,13 +3142,11 @@ int gdImagePaletteToTrueColor(gdImagePtr src)
return 1;
clean_on_error:
- if (y > 0) {
-
- for (yy = y; yy >= yy - 1; y--) {
- gdFree(src->tpixels[y]);
- }
- gdFree(src->tpixels);
+ /* free new true color buffer (y is not allocated, have failed) */
+ for (yy = 0; yy < y; yy++) {
+ gdFree(src->tpixels[yy]);
}
+ gdFree(src->tpixels);
return 0;
}
diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h
index 0ace31ba03..2eb4fd8e1c 100644
--- a/ext/gd/libgd/gd.h
+++ b/ext/gd/libgd/gd.h
@@ -112,7 +112,7 @@ int gdAlphaBlend(int dest, int src);
* GD_BELL - Bell
* GD_BESSEL - Bessel
- * GD_BILINEAR_FIXED - fixed point bilinear
+ * GD_BILINEAR_FIXED - fixed point bilinear
* GD_BICUBIC - Bicubic
* GD_BICUBIC_FIXED - fixed point bicubic integer
* GD_BLACKMAN - Blackman
diff --git a/ext/gd/libgd/gd_gif_in.c b/ext/gd/libgd/gd_gif_in.c
index f41ec8460a..74b7493331 100644
--- a/ext/gd/libgd/gd_gif_in.c
+++ b/ext/gd/libgd/gd_gif_in.c
@@ -232,11 +232,11 @@ gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr fd) /* {{{ */
}
im->interlace = BitSet(buf[8], INTERLACE);
if (!useGlobalColormap) {
- if (ReadColorMap(fd, bitPixel, localColorMap)) {
+ if (ReadColorMap(fd, bitPixel, localColorMap)) {
gdImageDestroy(im);
return 0;
}
- ReadImage(im, fd, width, height, localColorMap,
+ ReadImage(im, fd, width, height, localColorMap,
BitSet(buf[8], INTERLACE), &ZeroDataBlock);
} else {
if (!haveGlobalColormap) {
@@ -244,7 +244,7 @@ gdImagePtr gdImageCreateFromGifCtx(gdIOCtxPtr fd) /* {{{ */
return 0;
}
ReadImage(im, fd, width, height,
- ColorMap,
+ ColorMap,
BitSet(buf[8], INTERLACE), &ZeroDataBlock);
}
if (Transparent != (-1)) {
@@ -567,7 +567,7 @@ ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)
}
if (c > MAX_LWZ_BITS) {
- return;
+ return;
}
/* Stash the color map into the image */
diff --git a/ext/gd/libgd/gd_gif_out.c b/ext/gd/libgd/gd_gif_out.c
index 0178dd9741..1f2a6b936a 100644
--- a/ext/gd/libgd/gd_gif_out.c
+++ b/ext/gd/libgd/gd_gif_out.c
@@ -45,7 +45,7 @@ typedef long int count_int;
#define maxmaxcode ((code_int)1 << GIFBITS)
#define HSIZE 5003 /* 80% occupancy */
-#define hsize HSIZE /* Apparently invariant, left over from
+#define hsize HSIZE /* Apparently invariant, left over from
compress */
typedef struct {
@@ -127,7 +127,7 @@ void gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out)
if (!pim) {
return;
}
- tim = pim;
+ tim = pim;
}
BitsPerPixel = colorstobpp(tim->colorsTotal);
/* All set, let's do it. */
@@ -690,7 +690,7 @@ cl_block (GifCtx *ctx) /* table clear for block compress */
static void
cl_hash(register count_int chsize, GifCtx *ctx) /* reset code table */
-
+
{
register count_int *htab_p = ctx->htab+chsize;
diff --git a/ext/gd/libgd/gd_jpeg.c b/ext/gd/libgd/gd_jpeg.c
index 7189c28b58..f239ef8acd 100644
--- a/ext/gd/libgd/gd_jpeg.c
+++ b/ext/gd/libgd/gd_jpeg.c
@@ -468,7 +468,7 @@ gdImagePtr gdImageCreateFromJpegCtxEx (gdIOCtx * infile, int ignore_warning)
*tpix = gdTrueColor (currow[0], currow[1], currow[2]);
}
}
- }
+ }
if (jpeg_finish_decompress (&cinfo) != TRUE) {
php_gd_error("gd-jpeg: warning: jpeg_finish_decompress reports suspended data source");
@@ -478,7 +478,7 @@ gdImagePtr gdImageCreateFromJpegCtxEx (gdIOCtx * infile, int ignore_warning)
goto error;
}
}
-
+
jpeg_destroy_decompress (&cinfo);
gdFree (row);
diff --git a/ext/gd/libgd/gd_webp.c b/ext/gd/libgd/gd_webp.c
index bf9ac9dd0e..da0cc9d5b8 100644
--- a/ext/gd/libgd/gd_webp.c
+++ b/ext/gd/libgd/gd_webp.c
@@ -1,77 +1,52 @@
+#ifdef HAVE_LIBWEBP
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include "gd.h"
-
-
-#ifdef HAVE_LIBVPX
-#include "webpimg.h"
#include "gdhelpers.h"
+#include "webp/decode.h"
+#include "webp/encode.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";
-}
+#define GD_WEBP_ALLOC_STEP (4*1024)
gdImagePtr gdImageCreateFromWebp (FILE * inFile)
{
gdImagePtr im;
gdIOCtx *in = gdNewFileCtx(inFile);
+ if (!in)
+ return 0;
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);
+ gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
+ if (!in)
+ return 0;
+ im = gdImageCreateFromWebpCtx(in);
+ in->gd_free(in);
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;
+ int width, height;
+ uint8_t *filedata = NULL;
+ uint8_t *argb = NULL;
size_t size = 0, n;
gdImagePtr im;
+ int x, y;
+ uint8_t *p;
do {
+ unsigned char *read, *temp;
+
temp = gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
if (temp) {
filedata = temp;
@@ -80,31 +55,105 @@ gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
if (filedata) {
gdFree(filedata);
}
- php_gd_error("WebP decode: realloc failed");
+ zend_error(E_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");
+ if (WebPGetInfo(filedata,size, &width, &height) == 0) {
+ zend_error(E_ERROR, "gd-webp cannot get webp info");
+ gdFree(filedata);
return NULL;
}
+
im = gdImageCreateTrueColor(width, height);
- gd_YUV420toRGBA(Y, U, V, im);
+ if (!im) {
+ gdFree(filedata);
+ return NULL;
+ }
+ argb = WebPDecodeARGB(filedata, size, &width, &height);
+ if (!argb) {
+ zend_error(E_ERROR, "gd-webp cannot allocate temporary buffer");
+ gdFree(filedata);
+ gdImageDestroy(im);
+ return NULL;
+ }
+ for (y = 0, p = argb; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ register uint8_t a = gdAlphaMax - (*(p++) >> 1);
+ register uint8_t r = *(p++);
+ register uint8_t g = *(p++);
+ register uint8_t b = *(p++);
+ im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a);
+ }
+ }
+ gdFree(filedata);
+ /* do not use gdFree here, in case gdFree/alloc is mapped to something else than libc */
+ free(argb);
+ im->saveAlphaFlag = 1;
return im;
}
+void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
+{
+ uint8_t *argb;
+ int x, y;
+ uint8_t *p;
+ uint8_t *out;
+ size_t out_size;
+
+ if (im == NULL) {
+ return;
+ }
+
+ if (!gdImageTrueColor(im)) {
+ zend_error(E_ERROR, "Paletter image not supported by webp");
+ return;
+ }
+
+ if (quantization == -1) {
+ quantization = 80;
+ }
+
+ argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
+ if (!argb) {
+ return;
+ }
+ p = argb;
+ for (y = 0; y < gdImageSY(im); y++) {
+ for (x = 0; x < gdImageSX(im); x++) {
+ register int c;
+ register char a;
+ c = im->tpixels[y][x];
+ a = gdTrueColorGetAlpha(c);
+ if (a == 127) {
+ a = 0;
+ } else {
+ a = 255 - ((a << 1) + (a >> 6));
+ }
+ *(p++) = gdTrueColorGetRed(c);
+ *(p++) = gdTrueColorGetGreen(c);
+ *(p++) = gdTrueColorGetBlue(c);
+ *(p++) = a;
+ }
+ }
+ out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quantization, &out);
+ if (out_size == 0) {
+ zend_error(E_ERROR, "gd-webp encoding failed");
+ goto freeargb;
+ }
+ gdPutBuf(out, out_size, outfile);
+ free(out);
+
+freeargb:
+ gdFree(argb);
+}
+
void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
{
gdIOCtx *out = gdNewFileCtx(outFile);
@@ -115,7 +164,7 @@ void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
void gdImageWebp (gdImagePtr im, FILE * outFile)
{
gdIOCtx *out = gdNewFileCtx(outFile);
- gdImageWebpCtx(im, out, -1);
+ gdImageWebpCtx(im, out, -1);
out->gd_free(out);
}
@@ -139,74 +188,4 @@ void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization)
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 */
+#endif /* HAVE_LIBWEBP */
diff --git a/ext/gd/libgd/gdft.c b/ext/gd/libgd/gdft.c
index ba905dc0a8..d484b83e2e 100644
--- a/ext/gd/libgd/gdft.c
+++ b/ext/gd/libgd/gdft.c
@@ -338,7 +338,7 @@ static int fontTest (void *element, void *key)
{
font_t *a = (font_t *) element;
fontkey_t *b = (fontkey_t *) key;
-
+
if (strcmp (a->fontlist, b->fontlist) == 0) {
switch (b->preferred_map) {
case gdFTEX_Unicode:
@@ -412,8 +412,7 @@ static void *fontFetch (char **error, void *key)
for (dir = gd_strtok_r (path, PATHSEPARATOR, &strtok_ptr_path); dir;
dir = gd_strtok_r (0, PATHSEPARATOR, &strtok_ptr_path)) {
if (!strcmp(dir, ".")) {
- TSRMLS_FETCH();
-#if HAVE_GETCWD
+ #if HAVE_GETCWD
dir = VCWD_GETCWD(cur_dir, MAXPATHLEN);
#elif HAVE_GETWD
dir = VCWD_GETWD(cur_dir);
@@ -1089,7 +1088,15 @@ gdImageStringFTEx (gdImage * im, int *brect, int fg, char *fontlist, double ptsi
}
/* transform glyph image */
- FT_Get_Glyph(slot, &image);
+ if (FT_Get_Glyph(slot, &image)) {
+ if (tmpstr) {
+ gdFree(tmpstr);
+ }
+ gdCacheDelete(tc_cache);
+ gdMutexUnlock(gdFontCacheMutex);
+ return "Problem loading glyph";
+ }
+
if (brect) { /* only if need brect */
FT_Glyph_Get_CBox(image, ft_glyph_bbox_gridfit, &glyph_bbox);
glyph_bbox.xMin += penf.x;
diff --git a/ext/gd/libgd/gdhelpers.h b/ext/gd/libgd/gdhelpers.h
index 6c469726ec..768fde93b8 100644
--- a/ext/gd/libgd/gdhelpers.h
+++ b/ext/gd/libgd/gdhelpers.h
@@ -22,7 +22,7 @@ extern char *gd_strtok_r(char *s, char *sep, char **state);
#define gdPEstrdup(ptr) pestrdup(ptr, 1)
/* Returns nonzero if multiplying the two quantities will
- result in integer overflow. Also returns nonzero if
+ result in integer overflow. Also returns nonzero if
either quantity is negative. By Phil Knirsch based on
netpbm fixes by Alan Cox. */
diff --git a/ext/gd/libgd/gdkanji.c b/ext/gd/libgd/gdkanji.c
index be853c542d..3158e077c3 100644
--- a/ext/gd/libgd/gdkanji.c
+++ b/ext/gd/libgd/gdkanji.c
@@ -74,12 +74,11 @@ error (const char *format,...)
{
va_list args;
char *tmp;
- TSRMLS_FETCH();
va_start(args, format);
vspprintf(&tmp, 0, format, args);
va_end(args);
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", LIBNAME, tmp);
+ php_error_docref(NULL, E_WARNING, "%s: %s", LIBNAME, tmp);
efree(tmp);
}
diff --git a/ext/gd/libgd/gdxpm.c b/ext/gd/libgd/gdxpm.c
index b69414e60d..8db7fe0438 100644
--- a/ext/gd/libgd/gdxpm.c
+++ b/ext/gd/libgd/gdxpm.c
@@ -17,7 +17,7 @@
gdImagePtr gdImageCreateFromXpm (char *filename)
{
- XpmInfo info;
+ XpmInfo info = {0};
XpmImage image;
int i, j, k, number;
char buf[5];
diff --git a/ext/gd/libgd/webpimg.c b/ext/gd/libgd/webpimg.c
deleted file mode 100644
index f287e5414f..0000000000
--- a/ext/gd/libgd/webpimg.c
+++ /dev/null
@@ -1,914 +0,0 @@
-/*===========================================================================*
- - Copyright 2010 Google Inc.
- -
- - This code is licensed under the same terms as WebM:
- - Software License Agreement: http://www.webmproject.org/license/software/
- - Additional IP Rights Grant: http://www.webmproject.org/license/additional/
- *===========================================================================*/
-
-/*
- * Encoding/Decoding of WebP still image compression format.
- *
- * 1. WebPDecode: Takes an array of bytes (string) corresponding to the WebP
- * encoded image and generates output in the YUV format with
- * the color components U, V subsampled to 1/2 resolution along
- * each dimension.
- *
- * 2. YUV420toRGBA: Converts from YUV (with color subsampling) such as produced
- * by the WebPDecode routine into 32 bits per pixel RGBA data
- * array. This data array can be directly used by the Leptonica
- * Pix in-memory image format.
- *
- * 3. WebPEncode: Takes a Y, U, V data buffers (with color components U and V
- * subsampled to 1/2 resolution) and generates the WebP string
- *
- * 4. RGBAToYUV420: Generates Y, U, V data (with color subsampling) from 32 bits
- * per pixel RGBA data buffer. The resulting YUV data can be
- * directly fed into the WebPEncode routine.
- *
- * 5. AdjustColorspace:
- *
- * 6. AdjustColorspaceBack:
- */
-#include "gd.h"
-#ifdef HAVE_LIBVPX
-#include "webpimg.h"
-
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-
-#include "vpx/vpx_decoder.h"
-#include "vpx/vp8dx.h"
-#include "vpx/vpx_encoder.h"
-#include "vpx/vp8cx.h"
-#include "gd.h"
-
-/*---------------------------------------------------------------------*
- * color conversions *
- *---------------------------------------------------------------------*/
-
-#ifndef inline
-# define inline __inline
-#endif
-static inline int clip(float v, int a, int b) {
- return (v > b) ? b : (v < 0) ? 0 : (int)(v);
-}
-enum {
- COLOR_RED = 1,
- COLOR_GREEN = 2,
- COLOR_BLUE = 3,
- ALPHA_CHANNEL = 0
-};
-
-/* endian neutral extractions of ARGB from a 32 bit pixel */
-static const uint32 RED_SHIFT =
- 8 * (sizeof(uint32) - 1 - COLOR_RED); /* 16 */
-static const uint32 GREEN_SHIFT =
- 8 * (sizeof(uint32) - 1 - COLOR_GREEN); /* 8 */
-static const uint32 BLUE_SHIFT =
- 8 * (sizeof(uint32) - 1 - COLOR_BLUE); /* 0 */
-static const uint32 ALPHA_SHIFT =
- 8 * (sizeof(uint32) - 1 - ALPHA_CHANNEL); /* 24 */
-
-static inline int GetRed(const uint32* rgba) {
- return gdTrueColorGetRed(*rgba);
-}
-
-static inline int GetGreen(const uint32* rgba) {
- return gdTrueColorGetGreen(*rgba);
-}
-
-static inline int GetBlue(const uint32* rgba) {
- return gdTrueColorGetBlue(*rgba);
-}
-
-enum { YUV_FRAC = 16 };
-
-static inline int clip_uv(int v) {
- v = (v + (257 << (YUV_FRAC + 2 - 1))) >> (YUV_FRAC + 2);
- return ((v & ~0xff) == 0) ? v : v < 0 ? 0u : 255u;
-}
-
-
-/* YUV <-----> RGB conversions */
-/* The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
- * More information at: http://en.wikipedia.org/wiki/YCbCr
- */
-static inline int GetLumaY(int r, int g, int b) {
- const int kRound = (1 << (YUV_FRAC - 1)) + (16 << YUV_FRAC);
- // Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
- const int luma = 16839 * r + 33059 * g + 6420 * b;
- return (luma + kRound) >> YUV_FRAC;
-}
-
-static inline int GetLumaYfromPtr(uint32* rgba) {
- const int r = GetRed(rgba);
- const int g = GetGreen(rgba);
- const int b = GetBlue(rgba);
- return GetLumaY(r, g, b);
-}
-
-static inline int GetChromaU(int r, int g, int b) {
- // U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
- return clip_uv(-9719 * r - 19081 * g + 28800 * b);
-}
-
-static inline int GetChromaV(int r, int g, int b) {
- // V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
- return clip_uv(+28800 * r - 24116 * g - 4684 * b);
-}
-
-/* Converts YUV to RGB and writes into a 32 bit pixel in endian
- * neutral fashion
- */
-enum { RGB_FRAC = 16, RGB_HALF = (1 << RGB_FRAC) / 2,
- RGB_RANGE_MIN = -227, RGB_RANGE_MAX = 256 + 226 };
-
-static int init_done = 0;
-static int16_t kVToR[256], kUToB[256];
-static int32_t kVToG[256], kUToG[256];
-static uint8_t kClip[RGB_RANGE_MAX - RGB_RANGE_MIN];
-
-static void InitTables() {
- int i;
- for (i = 0; i < 256; ++i) {
- kVToR[i] = (89858 * (i - 128) + RGB_HALF) >> RGB_FRAC;
- kUToG[i] = -22014 * (i - 128) + RGB_HALF;
- kVToG[i] = -45773 * (i - 128);
- kUToB[i] = (113618 * (i - 128) + RGB_HALF) >> RGB_FRAC;
- }
- for (i = RGB_RANGE_MIN; i < RGB_RANGE_MAX; ++i) {
- const int j = ((i - 16) * 76283 + RGB_HALF) >> RGB_FRAC;
- kClip[i - RGB_RANGE_MIN] = (j < 0) ? 0 : (j > 255) ? 255 : j;
- }
-
- init_done = 1;
-}
-
-static void ToRGB(int y, int u, int v, uint32* const dst) {
- const int r_off = kVToR[v];
- const int g_off = (kVToG[v] + kUToG[u]) >> RGB_FRAC;
- const int b_off = kUToB[u];
- const int r = kClip[y + r_off - RGB_RANGE_MIN];
- const int g = kClip[y + g_off - RGB_RANGE_MIN];
- const int b = kClip[y + b_off - RGB_RANGE_MIN];
- *dst = (r << RED_SHIFT) | (g << GREEN_SHIFT) | (b << BLUE_SHIFT);
-}
-
-static inline uint32 get_le32(const uint8* const data) {
- return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
-}
-
-/* Returns the difference (in dB) between two images represented in YUV format
- *
- * Input:
- * Y1/U1/V1: The Y/U/V data of the first image
- * Y2/U2/V2: The Y/U/V data of the second image
- *
- * Returns the PSNR (http://en.wikipedia.org/wiki/Peak_signal-to-noise_ratio)
- * value computed between the two images
- */
-double GetPSNRYuv(const uint8* Y1,
- const uint8* U1,
- const uint8* V1,
- const uint8* Y2,
- const uint8* U2,
- const uint8* V2,
- int y_width,
- int y_height) {
- int x, y, row_idx;
- const int uv_width = ((y_width + 1) >> 1);
- const int uv_height = ((y_height + 1) >> 1);
- double sse = 0., count = 0.;
- for (y = 0; y < y_height; ++y) {
- count += y_width;
- row_idx = y * y_width;
- for (x = 0; x < y_width; ++x) {
- double diff = Y1[row_idx + x] - Y2[row_idx + x];
- sse += diff * diff;
- }
- }
- for (y = 0; y < uv_height; ++y) {
- count += 2 * uv_width;
- row_idx = y * uv_width;
- for (x = 0; x < uv_width; ++x) {
- const double diff_U = U1[row_idx + x] - U2[row_idx + x];
- const double diff_V = V1[row_idx + x] - V2[row_idx + x];
- sse += diff_U * diff_U + diff_V * diff_V;
- }
- }
- return -4.3429448 * log(sse / (255. * 255. * count));
-}
-
-/* Returns the difference (in dB) between two images. One represented
- * using Y,U,V vectors and the other is webp image data.
- * Input:
- * Y1/U1/V1: The Y/U/V data of the first image
- * imgdata: data buffer containing webp image
- * imgdata_size: size of the imgdata buffer
- *
- * Returns the PSNR value computed between the two images
- */
-double WebPGetPSNR(const uint8* Y1,
- const uint8* U1,
- const uint8* V1,
- uint8* imgdata,
- int imgdata_size) {
- uint8* Y2 = NULL;
- uint8* U2 = NULL;
- uint8* V2 = NULL;
- int w = 0, h = 0;
- double psnr = 0;
-
- WebPDecode(imgdata,
- imgdata_size,
- &Y2,
- &U2,
- &V2,
- &w,
- &h);
-
- psnr = GetPSNRYuv(Y1, U1, V1, Y2, U2, V2, w, h);
- free(Y2);
-
- return psnr;
-}
-
-/*---------------------------------------------------------------------*
- * Reading WebP *
- *---------------------------------------------------------------------*/
-
-/* RIFF layout is:
- * 0ffset tag
- * 0...3 "RIFF" 4-byte tag
- * 4...7 size of image data (including metadata) starting at offset 8
- * 8...11 "WEBP" our form-type signature
- * 12..15 "VP8 " 4-byte tags, describing the raw video format used
- * 16..19 size of the raw WebP image data, starting at offset 20
- * 20.... the WebP bytes
- * There can be extra chunks after the "VP8 " chunk (ICMT, ICOP, ...)
- * All 32-bits sizes are in little-endian order.
- * Note: chunk data must be padded to multiple of 2 in size
- */
-
-int SkipRiffHeader(const uint8** data_ptr, int *data_size_ptr) {
- /* 20 bytes RIFF header 10 bytes VP8 header */
- const int kHeaderSize = (20 + 10);
- uint32 chunk_size = 0xffffffffu;
-
- if (*data_size_ptr >= kHeaderSize && !memcmp(*data_ptr, "RIFF", 4)) {
- if (memcmp(*data_ptr + 8, "WEBP", 4)) {
- return 0; /* wrong image file signature */
- } else {
- const uint32 riff_size = get_le32(*data_ptr + 4);
- if (memcmp(*data_ptr + 12, "VP8 ", 4)) {
- return 0; /* invalid compression format */
- }
- chunk_size = get_le32(*data_ptr + 16);
- if ((chunk_size > riff_size + 8) || (chunk_size & 1)) {
- return 0; /* inconsistent size information. */
- }
- /* We have a RIFF container. Skip it. */
- *data_ptr += 20;
- *data_size_ptr -= 20;
- }
- }
- return chunk_size;
-}
-
-/* Generate RGBA row from an YUV row (with width upsampling of chrome data)
- * Input:
- * 1, 2, 3. y_src, u_src, v_src - Pointers to input Y, U, V row data
- * respectively. We reuse these variables, they iterate over all pixels in
- * the row.
- * 4. y_width: width of the Y image plane (aka image width)
- * Output:
- * 5. rgb_sat: pointer to the output rgb row. We reuse this variable, it
- * iterates over all pixels in the row.
- */
-static void YUV420toRGBLine(uint8* y_src,
- uint8* u_src,
- uint8* v_src,
- int y_width,
- uint32* rgb_dst) {
- int x;
- for (x = 0; x < (y_width >> 1); ++x) {
- const int U = u_src[0];
- const int V = v_src[0];
- ToRGB(y_src[0], U, V, rgb_dst);
- ToRGB(y_src[1], U, V, rgb_dst + 1);
- ++u_src;
- ++v_src;
- y_src += 2;
- rgb_dst += 2;
- }
- if (y_width & 1) { /* Rightmost pixel */
- ToRGB(y_src[0], (*u_src), (*v_src), rgb_dst);
- }
-}
-
-/* Converts from YUV (with color subsampling) such as produced by the WebPDecode
- * routine into 32 bits per pixel RGBA data array. This data array can be
- * directly used by the Leptonica Pix in-memory image format.
- * Input:
- * 1, 2, 3. Y, U, V: the input data buffers
- * 4. pixwpl: the desired words per line corresponding to the supplied
- * output pixdata.
- * 5. width, height: the dimensions of the image whose data resides in Y,
- * U, V.
- * Output:
- * 6. pixdata: the output data buffer. Caller should allocate
- * height * pixwpl bytes of memory before calling this routine.
- */
-void YUV420toRGBA(uint8* Y,
- uint8* U,
- uint8* V,
- int words_per_line,
- int width,
- int height,
- uint32* pixdata) {
- int y_width = width;
- int y_stride = y_width;
- int uv_width = ((y_width + 1) >> 1);
- int uv_stride = uv_width;
- int y;
-
- if (!init_done)
- InitTables();
-
- /* note that the U, V upsampling in height is happening here as the U, V
- * buffers sent to successive odd-even pair of lines is same.
- */
- for (y = 0; y < height; ++y) {
- YUV420toRGBLine(Y + y * y_stride,
- U + (y >> 1) * uv_stride,
- V + (y >> 1) * uv_stride,
- width,
- pixdata + y * words_per_line);
- }
-}
-
-void gd_YUV420toRGBA(uint8* Y,
- uint8* U,
- uint8* V,
- gdImagePtr im) {
- int width = im->sx;
- int height = im->sy;
- int y_width = width;
- int y_stride = y_width;
- int uv_width = ((y_width + 1) >> 1);
- int uv_stride = uv_width;
- int y;
-
- /* output im must be truecolor */
- if (!im->trueColor) {
- return;
- }
-
- if (!init_done)
- InitTables();
-
- /* note that the U, V upsampling in height is happening here as the U, V
- * buffers sent to successive odd-even pair of lines is same.
- */
- for (y = 0; y < height; ++y) {
- YUV420toRGBLine(Y + y * y_stride,
- U + (y >> 1) * uv_stride,
- V + (y >> 1) * uv_stride,
- width,
- im->tpixels[y]);
- }
-}
-
-static WebPResult VPXDecode(const uint8* data,
- int data_size,
- uint8** p_Y,
- uint8** p_U,
- uint8** p_V,
- int* p_width,
- int* p_height) {
- vpx_codec_ctx_t dec;
- vp8_postproc_cfg_t ppcfg;
- WebPResult result = webp_failure;
-
- if (!data || data_size <= 10 || !p_Y || !p_U || !p_V
- || *p_Y != NULL || *p_U != NULL || *p_V != NULL) {
- return webp_failure;
- }
-
- if (vpx_codec_dec_init(&dec,
- &vpx_codec_vp8_dx_algo, NULL, 0) != VPX_CODEC_OK) {
- return webp_failure;
- }
-
- ppcfg.post_proc_flag = VP8_NOFILTERING;
- vpx_codec_control(&dec, VP8_SET_POSTPROC, &ppcfg);
-
-
- if (vpx_codec_decode(&dec, data, data_size, NULL, 0) == VPX_CODEC_OK) {
- vpx_codec_iter_t iter = NULL;
- vpx_image_t* const img = vpx_codec_get_frame(&dec, &iter);
- if (img) {
- int y_width = img->d_w;
- int y_height = img->d_h;
- int y_stride = y_width;
- int uv_width = (y_width + 1) >> 1;
- int uv_stride = uv_width;
- int uv_height = ((y_height + 1) >> 1);
- int y;
-
- *p_width = y_width;
- *p_height = y_height;
- if ((*p_Y = (uint8 *)(calloc(y_stride * y_height
- + 2 * uv_stride * uv_height,
- sizeof(uint8)))) != NULL) {
- *p_U = *p_Y + y_height * y_stride;
- *p_V = *p_U + uv_height * uv_stride;
- for (y = 0; y < y_height; ++y) {
- memcpy(*p_Y + y * y_stride,
- img->planes[0] + y * img->stride[0],
- y_width);
- }
- for (y = 0; y < uv_height; ++y) {
- memcpy(*p_U + y * uv_stride,
- img->planes[1] + y * img->stride[1],
- uv_width);
- memcpy(*p_V + y * uv_stride,
- img->planes[2] + y * img->stride[2],
- uv_width);
- }
- result = webp_success;
- }
- }
- }
- vpx_codec_destroy(&dec);
-
- return result;
-}
-
-WebPResult WebPDecode(const uint8* data,
- int data_size,
- uint8** p_Y,
- uint8** p_U,
- uint8** p_V,
- int* p_width,
- int* p_height) {
-
- const uint32 chunk_size = SkipRiffHeader(&data, &data_size);
- if (!chunk_size) {
- return webp_failure; /* unsupported RIFF header */
- }
-
- return VPXDecode(data, data_size, p_Y, p_U, p_V, p_width, p_height);
-}
-
-/*---------------------------------------------------------------------*
- * Writing WebP *
- *---------------------------------------------------------------------*/
-
-/* Takes a pair of RGBA row data as input and generates 2 rows of Y data and one
- * row of subsampled U, V data as output
- * Input:
- * 1, 2. rgb_line1, rgb_line2 - input rgba rows
- * 3. width - image width
- * Outout:
- * 4, 5, 6: Output Y, U, V row
- */
-static void RGBALinepairToYUV420(uint32* rgb_line1,
- uint32* rgb_line2,
- int width,
- uint8* Y_dst1,
- uint8* Y_dst2,
- uint8* u_dst,
- uint8* v_dst) {
- int x;
- for (x = (width >> 1); x > 0; --x) {
- const int sum_r =
- GetRed(rgb_line1 + 0) + GetRed(rgb_line1 + 1) +
- GetRed(rgb_line2 + 0) + GetRed(rgb_line2 + 1);
- const int sum_g =
- GetGreen(rgb_line1 + 0) + GetGreen(rgb_line1 + 1) +
- GetGreen(rgb_line2 + 0) + GetGreen(rgb_line2 + 1);
- const int sum_b =
- GetBlue(rgb_line1 + 0) + GetBlue(rgb_line1 + 1) +
- GetBlue(rgb_line2 + 0) + GetBlue(rgb_line2 + 1);
-
- Y_dst1[0] = GetLumaYfromPtr(rgb_line1 + 0);
- Y_dst1[1] = GetLumaYfromPtr(rgb_line1 + 1);
- Y_dst2[0] = GetLumaYfromPtr(rgb_line2 + 0);
- Y_dst2[1] = GetLumaYfromPtr(rgb_line2 + 1);
-
- *u_dst++ = GetChromaU(sum_r, sum_g, sum_b);
- *v_dst++ = GetChromaV(sum_r, sum_g, sum_b);
-
- rgb_line1 += 2;
- rgb_line2 += 2;
- Y_dst1 += 2;
- Y_dst2 += 2;
- }
-
- if (width & 1) { /* rightmost pixel. */
- const int sum_r = GetRed(rgb_line1) + GetRed(rgb_line2);
- const int sum_g = GetGreen(rgb_line1) + GetGreen(rgb_line2);
- const int sum_b = GetBlue(rgb_line1) + GetBlue(rgb_line2);
-
- Y_dst1[0] = GetLumaYfromPtr(rgb_line1);
- Y_dst2[0] = GetLumaYfromPtr(rgb_line2);
- *u_dst = GetChromaU(2 * sum_r, 2 * sum_g, 2 * sum_b);
- *v_dst = GetChromaV(2 * sum_r, 2 * sum_g, 2 * sum_b);
- }
-}
-
-/* Generates Y, U, V data (with color subsampling) from 32 bits
- * per pixel RGBA data buffer. The resulting YUV data can be directly fed into
- * the WebPEncode routine.
- * Input:
- * 1. pixdatainput rgba data buffer
- * 2. words per line corresponding to pixdata
- * 3, 4. image width and height respectively
- * Output:
- * 5, 6, 7. Output YUV data buffers
- */
-void gd_RGBAToYUV420(gdImagePtr im2,
- uint8* Y,
- uint8* U,
- uint8* V) {
- int y_width = im2->sx;
- int y_height = im2->sy;
- int y_stride = y_width;
- int uv_width = ((y_width + 1) >> 1);
- int uv_stride = uv_width;
- int y;
- gdImagePtr im = NULL;
- int free_im = 0;
-
- if (!im2->trueColor) {
- /* Todo: Replace the color/YUV functions with our own and simplify
- that should boost the conversion a bit as well, not only for
- palette image. */
- im = gdImageCreateTrueColor(im2->sx, im2->sy);
- if (!im) {
- php_gd_error("gd-webp error: cannot convert palette input to truecolor");
- return;
- }
- gdImageCopy(im, im2, 0, 0, 0, 0, im->sx, im->sy);
- free_im = 1;
- } else {
- im = im2;
- }
- for (y = 0; y < (y_height >> 1); ++y) {
- RGBALinepairToYUV420(im->tpixels[2 * y],
- im->tpixels[2 * y + 1],
- y_width,
- Y + 2 * y * y_stride,
- Y + (2 * y + 1) * y_stride,
- U + y * uv_stride,
- V + y * uv_stride);
- }
- if (y_height & 1) {
- RGBALinepairToYUV420(im->tpixels[y_height - 1],
- im->tpixels[y_height - 1],
- y_width,
- Y + (y_height - 1) * y_stride,
- Y + (y_height - 1) * y_stride,
- U + (y_height >> 1) * uv_stride,
- V + (y_height >> 1) * uv_stride);
- }
- if (free_im) {
- gdImageDestroy(im);
- }
-}
-
-/* Generates Y, U, V data (with color subsampling) from 32 bits
- * per pixel RGBA data buffer. The resulting YUV data can be directly fed into
- * the WebPEncode routine.
- * Input:
- * 1. pixdatainput rgba data buffer
- * 2. words per line corresponding to pixdata
- * 3, 4. image width and height respectively
- * Output:
- * 5, 6, 7. Output YUV data buffers
- */
-void RGBAToYUV420(uint32* pixdata,
- int words_per_line,
- int width,
- int height,
- uint8* Y,
- uint8* U,
- uint8* V) {
- int y_width = width;
- int y_height = height;
- int y_stride = y_width;
- int uv_width = ((y_width + 1) >> 1);
- int uv_stride = uv_width;
- int y;
-
- for (y = 0; y < (y_height >> 1); ++y) {
- RGBALinepairToYUV420(pixdata + 2 * y * words_per_line,
- pixdata + (2 * y + 1) * words_per_line,
- y_width,
- Y + 2 * y * y_stride,
- Y + (2 * y + 1) * y_stride,
- U + y * uv_stride,
- V + y * uv_stride);
- }
- if (y_height & 1) {
- RGBALinepairToYUV420(pixdata + (y_height - 1) * words_per_line,
- pixdata + (y_height - 1) * words_per_line,
- y_width,
- Y + (y_height - 1) * y_stride,
- Y + (y_height - 1) * y_stride,
- U + (y_height >> 1) * uv_stride,
- V + (y_height >> 1) * uv_stride);
- }
-}
-
-static int codec_ctl(vpx_codec_ctx_t *enc,
- enum vp8e_enc_control_id id,
- int value) {
- const vpx_codec_err_t res = vpx_codec_control_(enc, id, value);
- if (res != VPX_CODEC_OK) {
- return webp_failure;
- }
- return webp_success;
-}
-
-static void SetupParams(vpx_codec_enc_cfg_t* cfg,
- int QP) {
- cfg->g_threads = 2;
- cfg->rc_min_quantizer = QP;
- cfg->rc_max_quantizer = QP;
- cfg->kf_mode = VPX_KF_FIXED;
-}
-
-/* VPXEncode: Takes a Y, U, V data buffers (with color components U and V
- * subsampled to 1/2 resolution) and generates the VPX string.
- * Output VPX string is placed in the *p_out buffer. container_size
- * indicates number of bytes to be left blank at the beginning of
- * *p_out buffer to accommodate for a container header.
- *
- * Return: success/failure
- */
-static WebPResult VPXEncode(const uint8* Y,
- const uint8* U,
- const uint8* V,
- int y_width,
- int y_height,
- int y_stride,
- int uv_width,
- int uv_height,
- int uv_stride,
- int QP,
- int container_size,
- unsigned char** p_out,
- int* p_out_size_bytes) {
- vpx_codec_iface_t* iface = &vpx_codec_vp8_cx_algo;
- vpx_codec_err_t res;
- vpx_codec_enc_cfg_t cfg;
- vpx_codec_ctx_t enc;
- WebPResult result = webp_failure;
- vpx_image_t img;
-
- *p_out = NULL;
- *p_out_size_bytes = 0;
-
-
- /* validate input parameters. */
- if (!p_out || !Y || !U || !V
- || y_width <= 0 || y_height <= 0 || uv_width <= 0 || uv_height <= 0
- || y_stride < y_width || uv_stride < uv_width
- || QP < 0 || QP > 63) {
- return webp_failure;
- }
-
- res = vpx_codec_enc_config_default(iface, &cfg, 0);
- if (res != VPX_CODEC_OK) {
- return webp_failure;
- }
-
- SetupParams(&cfg, QP);
- cfg.g_w = y_width;
- cfg.g_h = y_height;
-
- res = vpx_codec_enc_init(&enc, iface, &cfg, 0);
-
- if (res == VPX_CODEC_OK) {
- codec_ctl(&enc, VP8E_SET_CPUUSED, 3);
- codec_ctl(&enc, VP8E_SET_NOISE_SENSITIVITY, 0);
- codec_ctl(&enc, VP8E_SET_SHARPNESS, 0);
- codec_ctl(&enc, VP8E_SET_ENABLEAUTOALTREF, 0);
- codec_ctl(&enc, VP8E_SET_ARNR_MAXFRAMES, 0);
- codec_ctl(&enc, VP8E_SET_ARNR_TYPE, 0);
- codec_ctl(&enc, VP8E_SET_ARNR_STRENGTH, 0);
- codec_ctl(&enc, VP8E_SET_STATIC_THRESHOLD, 0);
- codec_ctl(&enc, VP8E_SET_TOKEN_PARTITIONS, 2);
-
- vpx_img_wrap(&img, VPX_IMG_FMT_I420,
- y_width, y_height, 16, (uint8*)(Y));
- img.planes[VPX_PLANE_Y] = (uint8*)(Y);
- img.planes[VPX_PLANE_U] = (uint8*)(U);
- img.planes[VPX_PLANE_V] = (uint8*)(V);
- img.stride[VPX_PLANE_Y] = y_stride;
- img.stride[VPX_PLANE_U] = uv_stride;
- img.stride[VPX_PLANE_V] = uv_stride;
-
- res = vpx_codec_encode(&enc, &img, 0, 1, 0, VPX_DL_BEST_QUALITY);
-
- if (res == VPX_CODEC_OK) {
- vpx_codec_iter_t iter = NULL;
- const vpx_codec_cx_pkt_t* pkt = vpx_codec_get_cx_data(&enc, &iter);
- if (pkt != NULL) {
- *p_out = (unsigned char*)(calloc(container_size + pkt->data.frame.sz,
- 1));
-
- memcpy(*p_out + container_size,
- (const void*)(pkt->data.frame.buf),
- pkt->data.frame.sz);
- *p_out_size_bytes = container_size + pkt->data.frame.sz;
-
- result = webp_success;
- }
- }
- }
-
- vpx_codec_destroy(&enc);
-
- return result;
-}
-
-WebPResult WebPEncode(const uint8* Y,
- const uint8* U,
- const uint8* V,
- int y_width,
- int y_height,
- int y_stride,
- int uv_width,
- int uv_height,
- int uv_stride,
- int QP,
- unsigned char** p_out,
- int* p_out_size_bytes,
- double *psnr) {
-
- const int kRiffHeaderSize = 20;
-
- if (VPXEncode(Y, U, V,
- y_width, y_height, y_stride,
- uv_width, uv_height, uv_stride,
- QP, kRiffHeaderSize,
- p_out, p_out_size_bytes) != webp_success) {
- return webp_failure;
- } else {
- /* Write RIFF header */
- const int img_size_bytes = *p_out_size_bytes - kRiffHeaderSize;
- const int chunk_size = (img_size_bytes + 1) & ~1; /* make size even */
- const int riff_size = chunk_size + 12;
- const uint8_t kRiffHeader[20] = { 'R', 'I', 'F', 'F',
- (riff_size >> 0) & 255,
- (riff_size >> 8) & 255,
- (riff_size >> 16) & 255,
- (riff_size >> 24) & 255,
- 'W', 'E', 'B', 'P',
- 'V', 'P', '8', ' ',
- (chunk_size >> 0) & 255,
- (chunk_size >> 8) & 255,
- (chunk_size >> 16) & 255,
- (chunk_size >> 24) & 255 };
- memcpy(*p_out, kRiffHeader, kRiffHeaderSize);
-
- if (img_size_bytes & 1) { /* write a padding byte */
- const int new_size = *p_out_size_bytes + 1;
- unsigned char* p = (unsigned char*)realloc(*p_out, new_size);
- if (p == NULL) {
- free(*p_out);
- *p_out = NULL;
- *p_out_size_bytes = 0;
- return webp_failure;
- }
- p[new_size - 1] = 0;
- *p_out = p;
- *p_out_size_bytes = new_size;
- }
-
- if (psnr) {
- *psnr = WebPGetPSNR(Y, U, V, *p_out, *p_out_size_bytes);
- }
-
- return webp_success;
- }
-}
-
-void AdjustColorspace(uint8* Y, uint8* U, uint8* V, int width, int height) {
- int y_width = width;
- int y_height = height;
- int y_stride = y_width;
- int uv_width = ((y_width + 1) >> 1);
- int uv_height = ((y_height + 1) >> 1);
- int uv_stride = uv_width;
- int x, y;
- /* convert luma */
- for (y = 0; y < y_height; ++y) {
- uint8* const Yrow = Y + y * y_stride;
- for (x = 0; x < y_width; ++x) {
- /* maps [0..255] to [16..235] */
- Yrow[x] = ((Yrow[x] * 55 + 32) >> 6) + 16;
- }
- }
- /* convert chroma */
- for (y = 0; y < uv_height; ++y) {
- uint8* const Urow = U + y * uv_stride;
- uint8* const Vrow = V + y * uv_stride;
- for (x = 0; x < uv_width; ++x) {
- /* maps [0..255] to [16..240] */
- Urow[x] = (((Urow[x] - 127) * 7) >> 3) + 128;
- Vrow[x] = (((Vrow[x] - 127) * 7) >> 3) + 128;
- }
- }
-}
-
-void AdjustColorspaceBack(uint8* Y, uint8* U, uint8* V, int width, int height) {
- int y_width = width;
- int y_height = height;
- int y_stride = y_width;
- int uv_width = ((y_width + 1) >> 1);
- int uv_height = ((y_height + 1) >> 1);
- int uv_stride = uv_width;
- int x, y;
- /* convert luma */
- for (y = 0; y < y_height; ++y) {
- uint8* const Yrow = Y + y * y_stride;
- for (x = 0; x < y_width; ++x) {
- /* maps [16..235] to [0..255] */
- const int v = ((Yrow[x] - 16) * 149 + 64) >> 7;
- Yrow[x] = (v < 0) ? 0 : (v > 255) ? 255u : v;
- }
- }
- /* convert chroma */
- for (y = 0; y < uv_height; ++y) {
- uint8* const Urow = U + y * uv_stride;
- uint8* const Vrow = V + y * uv_stride;
- for (x = 0; x < uv_width; ++x) {
- /* maps [0..255] to [16..240] */
- const int ru = (((Urow[x] - 128) * 73) >> 6) + 128;
- const int rv = (((Vrow[x] - 128) * 73) >> 6) + 128;
- Urow[x] = (ru < 0) ? 0 : (ru > 255) ? 255u : ru;
- Vrow[x] = (rv < 0) ? 0 : (rv > 255) ? 255u : rv;
- }
- }
-}
-
-WebPResult WebPGetInfo(const uint8* data,
- int data_size,
- int *width,
- int *height) {
- const uint32 chunk_size = SkipRiffHeader(&data, &data_size);
-
- if (width) *width = 0;
- if (height) *height = 0;
-
- if (!chunk_size) {
- return webp_failure; /* unsupported RIFF header */
- }
-
- /* Validate raw video data */
- if (data_size < 10) {
- return webp_failure; /* not enough data */
- }
-
- /* check signature */
- if (data[3] != 0x9d || data[4] != 0x01 || data[5] != 0x2a) {
- return webp_failure; /* Wrong signature. */
- } else {
- const uint32 bits = data[0] | (data[1] << 8) | (data[2] << 16);
-
- if ((bits & 1)) { /* Not a keyframe. */
- return webp_failure;
- } else {
- const int profile = (bits >> 1) & 7;
- const int show_frame = (bits >> 4) & 1;
- const uint32 partition_length = (bits >> 5);
-
- if (profile > 3) {
- return webp_failure; /* unknown profile */
- }
- if (!show_frame) {
- return webp_failure; /* first frame is invisible! */
- }
- if (partition_length >= chunk_size) {
- return webp_failure; /* inconsistent size information. */
- } else {
- const int w = ((data[7] << 8) | data[6]) & 0x3fff;
- const int h = ((data[9] << 8) | data[8]) & 0x3fff;
- if (width) *width = w;
- if (height) *height = h;
-
- return webp_success;
- }
- }
- }
- return webp_failure;
-}
-#endif /* HAVE_LIBVPX */
diff --git a/ext/gd/libgd/webpimg.h b/ext/gd/libgd/webpimg.h
deleted file mode 100644
index bc0f9722bd..0000000000
--- a/ext/gd/libgd/webpimg.h
+++ /dev/null
@@ -1,181 +0,0 @@
-/*===========================================================================*
- - Copyright 2010 Google Inc.
- -
- - This code is licensed under the same terms as WebM:
- - Software License Agreement: http://www.webmproject.org/license/software/
- - Additional IP Rights Grant: http://www.webmproject.org/license/additional/
- *===========================================================================*/
-
-/*
- * Encoding/Decoding of WebP still image compression format.
- *
- * 1. WebPDecode: Takes an array of bytes (string) corresponding to the WebP
- * encoded image and generates output in the YUV format with
- * the color components U, V subsampled to 1/2 resolution along
- * each dimension.
- *
- * 2. YUV420toRGBA: Converts from YUV (with color subsampling) such as produced
- * by the WebPDecode routine into 32 bits per pixel RGBA data
- * array. This data array can be directly used by the Leptonica
- * Pix in-memory image format.
- *
- * 3. WebPEncode: Takes a Y, U, V data buffers (with color components U and V
- * subsampled to 1/2 resolution) and generates the WebP string
- *
- * 4. RGBAToYUV420: Generates Y, U, V data (with color subsampling) from 32 bits
- * per pixel RGBA data buffer. The resulting YUV data can be
- * directly fed into the WebPEncode routine.
- *
- * 5. AdjustColorspace:
- *
- * 6. AdjustColorspaceBack:
- */
-
-#ifndef THIRD_PARTY_VP8_VP8IMG_H_
-#define THIRD_PARTY_VP8_VP8IMG_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-typedef unsigned char uint8;
-typedef unsigned int uint32;
-typedef enum WebPResultType {
- webp_success = 0,
- webp_failure = -1
-} WebPResult;
-
-/* Takes an array of bytes (string) corresponding to the WebP
- * encoded image and generates output in the YUV format with
- * the color components U, V subsampled to 1/2 resolution along
- * each dimension.
- * Input:
- * 1. data: the WebP data stream (array of bytes)
- * 2. data_size: count of bytes in the WebP data stream
- *
- * Output:
- * 3. p_Y/p_U/p_V : pointer to the Y/U/V data buffer (this routine will
- * allocate memory for the buffer, fill the buffer with
- * appropriate data and transfer owner ship of the buffer
- * to caller. Caller is responsible for freeing the memory).
- * Note that the memory for Y, U, V buffers is alloacted
- * in one chunk, hence one should call free(*p_Y) only.
- * Do not try to free the U and V buffers.
- *
- * 6. p_width: this routine returns the width of the decoded image here
- * 7. p_height: this routine returns the width of the decoded image here
- * Return: success/failure
- */
-WebPResult WebPDecode(const uint8* data,
- int data_size,
- uint8** p_Y,
- uint8** p_U,
- uint8** p_V,
- int* p_width,
- int* p_height);
-
-/* WebPEncode: Takes a Y, U, V data buffers (with color components U and V
- * subsampled to 1/2 resolution) and generates the WebP string.
- * Input:
- * 1, 2, 3. Y, U, V: The input YUV data buffers
- * 4, 5. y_width, y_height: The width and height of the image whose data
- * is in Y, U, V. This matches the Y plane. The U
- * and V planes typically have 1/2 width and
- * height.
- * 6. y_stride: The width (in bytes) of one row of Y data. This may not
- * match width if there is end of row padding (e.g., for 32
- * bit row alignment).
- * 7. QP: the quantization parameter. This parameter controls the
- * compression vs quality tradeoff. Use smaller numbers for better
- * quality (compression will be lesser) and vice versa. 20 is a
- * good optimal value.
- * Output:
- * 8. p_out: the output array of bytes corresponding to the encoded WebP
- * image. This routine allocates memory for the buffer, fills it
- * with appropriate values and transfers ownership to caller.
- * Caller responsible for freeing of memory.
- * Return: success/failure
- */
-WebPResult WebPEncode(const uint8* Y,
- const uint8* U,
- const uint8* V,
- int y_width,
- int y_height,
- int y_stride,
- int uv_width,
- int uv_height,
- int uv_stride,
- int QP,
- unsigned char** p_out,
- int* p_out_size_bytes,
- double* psnr);
-
-/* Converts from YUV (with color subsampling) such as produced by the WebPDecode
- * routine into 32 bits per pixel RGBA data array. This data array can be
- * directly used by the Leptonica Pix in-memory image format.
- * Input:
- * 1, 2, 3. Y, U, V: the input data buffers
- * 4. pixwpl: the desired words per line corresponding to the supplied
- * output pixdata.
- * 5. width, height: the dimensions of the image whose data resides in Y,
- * U, V.
- * Output:
- * 6. pixdata: the output data buffer. Caller should allocate
- * height * pixwpl bytes of memory before calling this routine.
- */
-void YUV420toRGBA(uint8* Y,
- uint8* U,
- uint8* V,
- int words_per_line,
- int width,
- int height,
- uint32* pixdata);
-
-/* Generates Y, U, V data (with color subsampling) from 32 bits
- * per pixel RGBA data buffer. The resulting YUV data can be directly fed into
- * the WebPEncode routine.
- * Input:
- * 1. pix data input rgba data buffer
- * 2. words per line corresponding to pixdata
- * 3, 4. image width and height respectively
- * Output:
- * 5, 6, 7. Output YUV data buffers
- */
-void RGBAToYUV420(uint32* pixdata,
- int words_per_line,
- int width,
- int height,
- uint8* Y,
- uint8* U,
- uint8* V);
-
-/* This function adjust from YUV420J (jpeg decoding) to YUV420 (webp input)
- * Hints: http://en.wikipedia.org/wiki/YCbCr
- */
-void AdjustColorspace(uint8* Y, uint8* U, uint8* V, int width, int height);
-
-/* Inverse function: convert from YUV420 to YUV420J */
-void AdjustColorspaceBack(uint8* Y, uint8* U, uint8* V, int width, int height);
-
-/* Checks WebP image header and outputs height and width information of
- * the image
- *
- * Input:
- * 1. data: the WebP data stream (array of bytes)
- * 2. data_size: count of bytes in the WebP data stream
- *
- * Outut:
- * width/height: width and height of the image
- *
- * Return: success/failure
- */
-WebPResult WebPGetInfo(const uint8* data,
- int data_size,
- int *width,
- int *height);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* THIRD_PARTY_VP8_VP8IMG_H_ */
diff --git a/ext/gd/libgd/xbm.c b/ext/gd/libgd/xbm.c
index 503ac824bc..b351814abb 100644
--- a/ext/gd/libgd/xbm.c
+++ b/ext/gd/libgd/xbm.c
@@ -1,6 +1,6 @@
/*
+----------------------------------------------------------------------+
- | PHP Version 5 |
+ | PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2016 The PHP Group |
+----------------------------------------------------------------------+