Skip to content

Commit 3461913

Browse files
committed
Replaced libvpx by libwebp (first draft; Windows only)
ext/gd/libgd/gd_webp.c has been taken from libgd[1]. Mainly, gd_error(X) has been subsituted by zend_error(E_ERROR, X) and BGD_DECLARE(X) by X. Further modifications are obvious from the diff. All GD tests are passing, what raises hope, but we need more WebP tests, anyway. [1] <https://github.com/libgd/libgd/blob/7ec030c4f1dae75ed5d82c3eed2abe6775742c75/src/gd_webp.c>
1 parent c20f00f commit 3461913

File tree

4 files changed

+110
-1213
lines changed

4 files changed

+110
-1213
lines changed

ext/gd/config.w32

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// vim:ft=javascript
33

44
ARG_WITH("gd", "Bundled GD support", "yes,shared");
5-
ARG_WITH("libvpx", "vpx support", "yes");
5+
ARG_WITH("libwebp", "webp support", "yes");
66

77
if (PHP_GD != "no") {
88
if (
@@ -21,12 +21,13 @@ if (PHP_GD != "no") {
2121
CHECK_HEADER_ADD_INCLUDE("xpm.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\X11")
2222
) {
2323

24-
if (PHP_LIBVPX != "no") {
25-
if (CHECK_LIB("vpxmt.lib", "gd", PHP_GD) &&
26-
CHECK_HEADER_ADD_INCLUDE("vp8.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\vpx")) {
27-
ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBVPX /D HAVE_GD_WEBP");
24+
if (PHP_LIBWEBP != "no") {
25+
if (CHECK_LIB("libwebp.lib", "gd", PHP_GD) &&
26+
CHECK_HEADER_ADD_INCLUDE("decode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp") &&
27+
CHECK_HEADER_ADD_INCLUDE("encode.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\webp")) {
28+
ADD_FLAG("CFLAGS_GD", "/D HAVE_LIBWEBP /D HAVE_GD_WEBP");
2829
} else {
29-
WARNING("libvpx not enabled; libraries and headers not found");
30+
WARNING("libwebp not enabled; libraries and headers not found");
3031
}
3132
}
3233
CHECK_LIB("User32.lib", "gd", PHP_GD);
@@ -38,7 +39,7 @@ if (PHP_GD != "no") {
3839
gdft.c gd_gd2.c gd_gd.c gd_gif_in.c gd_gif_out.c gdhelpers.c gd_io.c gd_io_dp.c \
3940
gd_io_file.c gd_io_ss.c gd_jpeg.c gdkanji.c gd_png.c gd_ss.c \
4041
gdtables.c gd_topal.c gd_wbmp.c gdxpm.c wbmp.c xbm.c gd_security.c gd_transform.c \
41-
gd_filter.c gd_pixelate.c gd_arc.c gd_rotate.c gd_color.c webpimg.c gd_webp.c \
42+
gd_filter.c gd_pixelate.c gd_arc.c gd_rotate.c gd_color.c gd_webp.c \
4243
gd_crop.c gd_interpolation.c gd_matrix.c", "gd");
4344
AC_DEFINE('HAVE_LIBGD', 1, 'GD support');
4445
ADD_FLAG("CFLAGS_GD", " \

ext/gd/libgd/gd_webp.c

Lines changed: 102 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,14 @@
1+
#ifdef HAVE_LIBWEBP
12
#include <stdio.h>
23
#include <math.h>
34
#include <string.h>
45
#include <stdlib.h>
56
#include "gd.h"
6-
7-
8-
#ifdef HAVE_LIBVPX
9-
#include "webpimg.h"
107
#include "gdhelpers.h"
8+
#include "webp/decode.h"
9+
#include "webp/encode.h"
1110

12-
extern void gd_YUV420toRGBA(uint8* Y,
13-
uint8* U,
14-
uint8* V,
15-
gdImagePtr im);
16-
17-
extern void gd_RGBAToYUV420(gdImagePtr im2,
18-
uint8* Y,
19-
uint8* U,
20-
uint8* V);
21-
22-
const char * gdWebpGetVersionString()
23-
{
24-
return "not defined";
25-
}
11+
#define GD_WEBP_ALLOC_STEP (4*1024)
2612

2713
gdImagePtr gdImageCreateFromWebp (FILE * inFile)
2814
{
@@ -34,42 +20,28 @@ gdImagePtr gdImageCreateFromWebp (FILE * inFile)
3420
return im;
3521
}
3622

23+
3724
gdImagePtr gdImageCreateFromWebpPtr (int size, void *data)
3825
{
39-
int width, height, ret;
40-
unsigned char *Y = NULL;
41-
unsigned char *U = NULL;
42-
unsigned char *V = NULL;
4326
gdImagePtr im;
44-
45-
ret = WebPDecode(data, size, &Y, &U, &V, &width, &height);
46-
if (ret != webp_success) {
47-
if (Y) free(Y);
48-
if (U) free(U);
49-
if (V) free(V);
50-
php_gd_error("WebP decode: fail to decode input data");
51-
return NULL;
52-
}
53-
im = gdImageCreateTrueColor(width, height);
54-
if (!im) {
55-
return NULL;
56-
}
57-
gd_YUV420toRGBA(Y, U, V, im);
27+
gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
28+
if (!in)
29+
return 0;
30+
im = gdImageCreateFromWebpCtx(in);
31+
in->gd_free(in);
5832
return im;
5933
}
6034

61-
#define GD_WEBP_ALLOC_STEP (4*1024)
62-
6335
gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
6436
{
65-
int width, height, ret;
66-
unsigned char *filedata = NULL;
37+
int width, height;
38+
uint8_t *filedata = NULL;
39+
uint8_t *argb = NULL;
6740
unsigned char *read, *temp;
68-
unsigned char *Y = NULL;
69-
unsigned char *U = NULL;
70-
unsigned char *V = NULL;
7141
size_t size = 0, n;
7242
gdImagePtr im;
43+
int x, y;
44+
uint8_t *p;
7345

7446
do {
7547
temp = gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
@@ -80,31 +52,106 @@ gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
8052
if (filedata) {
8153
gdFree(filedata);
8254
}
83-
php_gd_error("WebP decode: realloc failed");
55+
zend_error(E_ERROR, "WebP decode: realloc failed");
8456
return NULL;
8557
}
8658

8759
n = gdGetBuf(read, GD_WEBP_ALLOC_STEP, infile);
88-
/* differs from upstream where gdGetBuf return 0 instead of EOF */
8960
if (n>0 && n!=EOF) {
9061
size += n;
9162
}
9263
} while (n>0 && n!=EOF);
9364

94-
ret = WebPDecode(filedata, size, &Y, &U, &V, &width, &height);
95-
gdFree(filedata);
96-
if (ret != webp_success) {
97-
if (Y) free(Y);
98-
if (U) free(U);
99-
if (V) free(V);
100-
php_gd_error("WebP decode: fail to decode input data");
65+
if (WebPGetInfo(filedata,size, &width, &height) == 0) {
66+
zend_error(E_ERROR, "gd-webp cannot get webp info");
67+
gdFree(temp);
10168
return NULL;
10269
}
70+
10371
im = gdImageCreateTrueColor(width, height);
104-
gd_YUV420toRGBA(Y, U, V, im);
72+
if (!im) {
73+
gdFree(temp);
74+
return NULL;
75+
}
76+
argb = WebPDecodeARGB(filedata, size, &width, &height);
77+
if (!argb) {
78+
zend_error(E_ERROR, "gd-webp cannot allocate temporary buffer");
79+
gdFree(temp);
80+
gdImageDestroy(im);
81+
return NULL;
82+
}
83+
for (y = 0, p = argb; y < height; y++) {
84+
for (x = 0; x < width; x++) {
85+
register uint8_t a = gdAlphaMax - (*(p++) >> 1);
86+
register uint8_t r = *(p++);
87+
register uint8_t g = *(p++);
88+
register uint8_t b = *(p++);
89+
im->tpixels[y][x] = gdTrueColorAlpha(r, g, b, a);
90+
}
91+
}
92+
gdFree(filedata);
93+
/* do not use gdFree here, in case gdFree/alloc is mapped to something else than libc */
94+
free(argb);
95+
gdFree(temp);
96+
im->saveAlphaFlag = 1;
10597
return im;
10698
}
10799

100+
void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
101+
{
102+
uint8_t *argb;
103+
int x, y;
104+
uint8_t *p;
105+
uint8_t *out;
106+
size_t out_size;
107+
108+
if (im == NULL) {
109+
return;
110+
}
111+
112+
if (!gdImageTrueColor(im)) {
113+
zend_error(E_ERROR, "Paletter image not supported by webp");
114+
return;
115+
}
116+
117+
if (quantization == -1) {
118+
quantization = 80;
119+
}
120+
121+
argb = (uint8_t *)gdMalloc(gdImageSX(im) * 4 * gdImageSY(im));
122+
if (!argb) {
123+
return;
124+
}
125+
p = argb;
126+
for (y = 0; y < gdImageSY(im); y++) {
127+
for (x = 0; x < gdImageSX(im); x++) {
128+
register int c;
129+
register char a;
130+
c = im->tpixels[y][x];
131+
a = gdTrueColorGetAlpha(c);
132+
if (a == 127) {
133+
a = 0;
134+
} else {
135+
a = 255 - ((a << 1) + (a >> 6));
136+
}
137+
*(p++) = gdTrueColorGetRed(c);
138+
*(p++) = gdTrueColorGetGreen(c);
139+
*(p++) = gdTrueColorGetBlue(c);
140+
*(p++) = a;
141+
}
142+
}
143+
out_size = WebPEncodeRGBA(argb, gdImageSX(im), gdImageSY(im), gdImageSX(im) * 4, quantization, &out);
144+
if (out_size == 0) {
145+
zend_error(E_ERROR, "gd-webp encoding failed");
146+
goto freeargb;
147+
}
148+
gdPutBuf(out, out_size, outfile);
149+
free(out);
150+
151+
freeargb:
152+
gdFree(argb);
153+
}
154+
108155
void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
109156
{
110157
gdIOCtx *out = gdNewFileCtx(outFile);
@@ -115,7 +162,7 @@ void gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization)
115162
void gdImageWebp (gdImagePtr im, FILE * outFile)
116163
{
117164
gdIOCtx *out = gdNewFileCtx(outFile);
118-
gdImageWebpCtx(im, out, -1);
165+
gdImageWebpCtx(im, out, -1);
119166
out->gd_free(out);
120167
}
121168

@@ -139,74 +186,4 @@ void * gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization)
139186
out->gd_free(out);
140187
return rv;
141188
}
142-
143-
/*
144-
* Maps normalized QP (quality) to VP8 QP
145-
*/
146-
int mapQualityToVP8QP(int quality) {
147-
#define MIN_QUALITY 0
148-
#define MAX_QUALITY 100
149-
#define MIN_VP8QP 1
150-
#define MAX_VP8QP 63
151-
const float scale = MAX_VP8QP - MIN_VP8QP;
152-
const float vp8qp =
153-
scale * (MAX_QUALITY - quality) / (MAX_QUALITY - MIN_QUALITY) + MIN_VP8QP;
154-
if (quality < MIN_QUALITY || quality > MAX_QUALITY) {
155-
php_gd_error("Wrong quality value %d.", quality);
156-
return -1;
157-
}
158-
159-
return (int)(vp8qp + 0.5);
160-
}
161-
162-
/* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
163-
* and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
164-
* (http://www.cdrom.com/pub/png/pngbook.html).
165-
*/
166-
void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int quantization)
167-
{
168-
int width = im->sx;
169-
int height = im->sy;
170-
int colors = im->colorsTotal;
171-
int *open = im->open;
172-
173-
int yuv_width, yuv_height, yuv_nbytes, ret;
174-
int vp8_quality;
175-
unsigned char *Y = NULL,
176-
*U = NULL,
177-
*V = NULL;
178-
unsigned char *filedata = NULL;
179-
180-
/* Conversion to Y,U,V buffer */
181-
yuv_width = (width + 1) >> 1;
182-
yuv_height = (height + 1) >> 1;
183-
yuv_nbytes = width * height + 2 * yuv_width * yuv_height;
184-
185-
if ((Y = (unsigned char *)gdCalloc(yuv_nbytes, sizeof(unsigned char))) == NULL) {
186-
php_gd_error("gd-webp error: cannot allocate Y buffer");
187-
return;
188-
}
189-
vp8_quality = mapQualityToVP8QP(quantization);
190-
191-
U = Y + width * height;
192-
V = U + yuv_width * yuv_height;
193-
gd_RGBAToYUV420(im, Y, U, V);
194-
195-
/* Encode Y,U,V and write data to file */
196-
ret = WebPEncode(Y, U, V, width, height, width, yuv_width, yuv_height, yuv_width,
197-
vp8_quality, &filedata, &yuv_nbytes, NULL);
198-
gdFree(Y);
199-
200-
if (ret != webp_success) {
201-
if (filedata) {
202-
free(filedata);
203-
}
204-
php_gd_error("gd-webp error: WebP Encoder failed");
205-
return;
206-
}
207-
208-
gdPutBuf (filedata, yuv_nbytes, outfile);
209-
free(filedata);
210-
}
211-
212-
#endif /* HAVE_LIBVPX */
189+
#endif /* HAVE_LIBWEBP */

0 commit comments

Comments
 (0)