/hphp/runtime/ext/gd/libgd/gd_webp.cpp

https://gitlab.com/Blueprint-Marketing/hhvm · C++ · 210 lines · 170 code · 30 blank · 10 comment · 25 complexity · c6ed86ff9b67a0ec08d59578ab6e0a9c MD5 · raw file

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include "gd.h"
  6. #ifdef HAVE_LIBVPX
  7. #include "webpimg.h"
  8. #include "gdhelpers.h"
  9. extern void gd_YUV420toRGBA(uint8* Y,
  10. uint8* U,
  11. uint8* V,
  12. gdImagePtr im);
  13. extern void gd_RGBAToYUV420(gdImagePtr im2,
  14. uint8* Y,
  15. uint8* U,
  16. uint8* V);
  17. const char * gdWebpGetVersionString()
  18. {
  19. return "not defined";
  20. }
  21. gdImagePtr gdImageCreateFromWebp (FILE * inFile)
  22. {
  23. gdImagePtr im;
  24. gdIOCtx *in = gdNewFileCtx(inFile);
  25. im = gdImageCreateFromWebpCtx(in);
  26. in->gd_free(in);
  27. return im;
  28. }
  29. gdImagePtr gdImageCreateFromWebpPtr (int size, void *data)
  30. {
  31. int width, height, ret;
  32. unsigned char *Y = NULL;
  33. unsigned char *U = NULL;
  34. unsigned char *V = NULL;
  35. gdImagePtr im;
  36. ret = WebPDecode((const uint8*) data, size, &Y, &U, &V, &width, &height);
  37. if (ret != webp_success) {
  38. if (Y) free(Y);
  39. if (U) free(U);
  40. if (V) free(V);
  41. php_gd_error("WebP decode: fail to decode input data");
  42. return NULL;
  43. }
  44. im = gdImageCreateTrueColor(width, height);
  45. if (!im) {
  46. return NULL;
  47. }
  48. gd_YUV420toRGBA(Y, U, V, im);
  49. return im;
  50. }
  51. #define GD_WEBP_ALLOC_STEP (4*1024)
  52. gdImagePtr gdImageCreateFromWebpCtx (gdIOCtx * infile)
  53. {
  54. int width, height, ret;
  55. unsigned char *filedata = NULL;
  56. unsigned char *read, *temp;
  57. unsigned char *Y = NULL;
  58. unsigned char *U = NULL;
  59. unsigned char *V = NULL;
  60. size_t size = 0, n;
  61. gdImagePtr im;
  62. do {
  63. temp = (unsigned char*) gdRealloc(filedata, size+GD_WEBP_ALLOC_STEP);
  64. if (temp) {
  65. filedata = temp;
  66. read = temp + size;
  67. } else {
  68. if (filedata) {
  69. gdFree(filedata);
  70. }
  71. php_gd_error("WebP decode: realloc failed");
  72. return NULL;
  73. }
  74. n = gdGetBuf(read, GD_WEBP_ALLOC_STEP, infile);
  75. /* differs from upstream where gdGetBuf return 0 instead of EOF */
  76. if (n>0 && n!=EOF) {
  77. size += n;
  78. }
  79. } while (n>0 && n!=EOF);
  80. ret = WebPDecode(filedata, size, &Y, &U, &V, &width, &height);
  81. gdFree(filedata);
  82. if (ret != webp_success) {
  83. if (Y) free(Y);
  84. if (U) free(U);
  85. if (V) free(V);
  86. php_gd_error("WebP decode: fail to decode input data");
  87. return NULL;
  88. }
  89. im = gdImageCreateTrueColor(width, height);
  90. gd_YUV420toRGBA(Y, U, V, im);
  91. return im;
  92. }
  93. void gdImageWebpEx (gdImagePtr im, FILE * outFile, int64_t quantization)
  94. {
  95. gdIOCtx *out = gdNewFileCtx(outFile);
  96. gdImageWebpCtx(im, out, quantization);
  97. out->gd_free(out);
  98. }
  99. void gdImageWebp (gdImagePtr im, FILE * outFile)
  100. {
  101. gdIOCtx *out = gdNewFileCtx(outFile);
  102. gdImageWebpCtx(im, out, -1);
  103. out->gd_free(out);
  104. }
  105. void * gdImageWebpPtr (gdImagePtr im, int *size)
  106. {
  107. void *rv;
  108. gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
  109. gdImageWebpCtx(im, out, -1);
  110. rv = gdDPExtractData(out, size);
  111. out->gd_free(out);
  112. return rv;
  113. }
  114. void * gdImageWebpPtrEx (gdImagePtr im, int *size, int64_t quantization)
  115. {
  116. void *rv;
  117. gdIOCtx *out = gdNewDynamicCtx(2048, NULL);
  118. gdImageWebpCtx(im, out, quantization);
  119. rv = gdDPExtractData(out, size);
  120. out->gd_free(out);
  121. return rv;
  122. }
  123. /*
  124. * Maps normalized QP (quality) to VP8 QP
  125. */
  126. int mapQualityToVP8QP(int quality) {
  127. #define MIN_QUALITY 0
  128. #define MAX_QUALITY 100
  129. #define MIN_VP8QP 1
  130. #define MAX_VP8QP 63
  131. const float scale = MAX_VP8QP - MIN_VP8QP;
  132. const float vp8qp =
  133. scale * (MAX_QUALITY - quality) / (MAX_QUALITY - MIN_QUALITY) + MIN_VP8QP;
  134. if (quality < MIN_QUALITY || quality > MAX_QUALITY) {
  135. php_gd_error("Wrong quality value %i.", quality);
  136. return -1;
  137. }
  138. return (int)(vp8qp + 0.5);
  139. }
  140. /* This routine is based in part on code from Dale Lutz (Safe Software Inc.)
  141. * and in part on demo code from Chapter 15 of "PNG: The Definitive Guide"
  142. * (http://www.cdrom.com/pub/png/pngbook.html).
  143. */
  144. void gdImageWebpCtx (gdImagePtr im, gdIOCtx * outfile, int64_t quantization)
  145. {
  146. int width = im->sx;
  147. int height = im->sy;
  148. int yuv_width, yuv_height, yuv_nbytes, ret;
  149. int vp8_quality;
  150. unsigned char *Y = NULL,
  151. *U = NULL,
  152. *V = NULL;
  153. unsigned char *filedata = NULL;
  154. /* Conversion to Y,U,V buffer */
  155. yuv_width = (width + 1) >> 1;
  156. yuv_height = (height + 1) >> 1;
  157. yuv_nbytes = width * height + 2 * yuv_width * yuv_height;
  158. if ((Y = (unsigned char *)gdCalloc(yuv_nbytes, sizeof(unsigned char))) == NULL) {
  159. php_gd_error("gd-webp error: cannot allocate Y buffer");
  160. return;
  161. }
  162. vp8_quality = mapQualityToVP8QP(quantization);
  163. U = Y + width * height;
  164. V = U + yuv_width * yuv_height;
  165. gd_RGBAToYUV420(im, Y, U, V);
  166. /* Encode Y,U,V and write data to file */
  167. ret = WebPEncode(Y, U, V, width, height, width, yuv_width, yuv_height, yuv_width,
  168. vp8_quality, &filedata, &yuv_nbytes, NULL);
  169. gdFree(Y);
  170. if (ret != webp_success) {
  171. if (filedata) {
  172. free(filedata);
  173. }
  174. php_gd_error("gd-webp error: WebP Encoder failed");
  175. return;
  176. }
  177. gdPutBuf (filedata, yuv_nbytes, outfile);
  178. free(filedata);
  179. }
  180. #endif /* HAVE_LIBVPX */