php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #49696 PHP GD library can use underlying JPEG library's capability to prescale image
Submitted: 2009-09-28 05:03 UTC Modified: 2017-01-21 23:53 UTC
From: sriram dot natarajan at gmail dot com Assigned: pajoye (profile)
Status: Suspended Package: GD related
PHP Version: 5.3SVN-2009-09-28 (snap) OS: unix/linux
Private report: No CVE-ID: None
 [2009-09-28 05:03 UTC] sriram dot natarajan at gmail dot com
Description:
------------
GD library is commonly used in PHP5 applications for image processing. When creating thumbnails from a large jpeg image, the original image currently has to be decoded to a full-size copy before being resampled or resized. This is a relatively expensive step. The underlying jpeg library has a capability of prescaling an image when it is being decoded, so for example the decoded image could be only 1/16 the size of the fullsize image by prescaling by a factor of 4. This saves a substantial amount of cpu time.

Expected result:
----------------
we can update php libgd library and our php gd extension to leverage underlying jpeg's ability to prescale image at the time of creating jpeg images. 

for example, we can introduce new API or patch our existing gdImageCreateFromJpeg API to have an extra argument for prescale size so that we can set the value of 'prescale' value like below

cinfo.scale_denom = prescale;

before calling "jpeg_start_decompress (&cinfo)" function. 

[credits: thanks to Richard Smith for coming up with this nice suggestion]

af course, this will allow users to invoke our 'imagecreatefromjpeg' with an optional argument which specifies the prescale size of this jpeg. 

$src_img=imagecreatefromjpeg($name, 4);

Actual result:
--------------
better performance while producing jpeg based thumbnails 

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2009-09-28 08:36 UTC] pajoye@php.net
I have a patch for libgd and jpeglib7 to allow exactly that. However a manual scale is still necessary if you like to have a good result.


 [2009-10-01 18:52 UTC] sriram dot natarajan at gmail dot com
here is a suggested patch (against 5.3). i have made this patch so that it uses this prescale value only against bundled libgd. let me know , if this makes sense to you. 

Index: ext/gd/libgd/gd_jpeg.c
===================================================================
--- ext/gd/libgd/gd_jpeg.c	(revision 289063)
+++ ext/gd/libgd/gd_jpeg.c	(working copy)
@@ -260,21 +260,21 @@
 	gdFree (row);
 }
 
-gdImagePtr gdImageCreateFromJpeg (FILE * inFile, int ignore_warning)
+gdImagePtr gdImageCreateFromJpeg (FILE * inFile, int ignore_warning, int prescale)
 {
 	gdImagePtr im;
 	gdIOCtx *in = gdNewFileCtx(inFile);
-	im = gdImageCreateFromJpegCtx(in, ignore_warning);
+	im = gdImageCreateFromJpegCtx(in, ignore_warning, prescale);
 	in->gd_free (in);
 
 	return im;
 }
 
-gdImagePtr gdImageCreateFromJpegPtr (int size, void *data, int ignore_warning)
+gdImagePtr gdImageCreateFromJpegPtr (int size, void *data, int ignore_warning, int prescale)
 {
 	gdImagePtr im;
 	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
-	im = gdImageCreateFromJpegCtx(in, ignore_warning);
+	im = gdImageCreateFromJpegCtx(in, ignore_warning, prescale);
 	in->gd_free(in);
 
 	return im;
@@ -289,7 +289,7 @@
  * Create a gd-format image from the JPEG-format INFILE.  Returns the
  * image, or NULL upon error.
  */
-gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile, int ignore_warning)
+gdImagePtr gdImageCreateFromJpegCtx (gdIOCtx * infile, int ignore_warning, int prescale)
 {
 	struct jpeg_decompress_struct cinfo;
 	struct jpeg_error_mgr jerr;
@@ -327,6 +327,8 @@
 
 	cinfo.err->error_exit = fatal_jpeg_error;
 
+	cinfo.scale_denom = prescale;
+
 	jpeg_create_decompress (&cinfo);
 
 	jpeg_gdIOCtx_src (&cinfo, infile);
Index: ext/gd/libgd/gd.h
===================================================================
--- ext/gd/libgd/gd.h	(revision 289063)
+++ ext/gd/libgd/gd.h	(working copy)
@@ -247,8 +247,8 @@
 gdImagePtr gdImageCreateFromPngCtx(gdIOCtxPtr in);
 gdImagePtr gdImageCreateFromWBMP(FILE *inFile);
 gdImagePtr gdImageCreateFromWBMPCtx(gdIOCtx *infile);
-gdImagePtr gdImageCreateFromJpeg(FILE *infile, int ignore_warning);
-gdImagePtr gdImageCreateFromJpegCtx(gdIOCtx *infile, int ignore_warning);
+gdImagePtr gdImageCreateFromJpeg(FILE *infile, int ignore_warning, int prescale);
+gdImagePtr gdImageCreateFromJpegCtx(gdIOCtx *infile, int ignore_warning, int prescale);
 
 int gdJpegGetVersionInt();
 const char * gdPngGetVersionString();
Index: ext/gd/gd.c
===================================================================
--- ext/gd/gd.c	(revision 289063)
+++ ext/gd/gd.c	(working copy)
@@ -342,6 +342,7 @@
 #ifdef HAVE_GD_JPG
 ZEND_BEGIN_ARG_INFO(arginfo_imagecreatefromjpeg, 0)
 	ZEND_ARG_INFO(0, filename)
+	ZEND_ARG_INFO(0, prescale)
 ZEND_END_ARG_INFO()
 #endif
 
@@ -2407,7 +2408,10 @@
 	FILE * fp = NULL;
 #ifdef HAVE_GD_JPG
 	long ignore_warning;
+#if HAVE_GD_BUNDLED
+	long prescale = 0;
 #endif
+#endif
 	if (image_type == PHP_GDIMG_TYPE_GD2PART) {
 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sllll", &file, &file_len, &srcx, &srcy, &width, &height) == FAILURE) {
 			return;
@@ -2416,6 +2420,12 @@
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero width or height not allowed");
 			RETURN_FALSE;
 		}
+#if defined(HAVE_GD_JPG) && defined(HAVE_GD_BUNDLED)
+	} else if (image_type == PHP_GDIMG_TYPE_JPG) {
+		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &file, &file_len, &prescale) == FAILURE) {
+			return;
+		}
+#endif
 	} else {
 		if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &file_len) == FAILURE) {
 			return;
@@ -2460,6 +2470,10 @@
 
 		if (image_type == PHP_GDIMG_TYPE_GD2PART) {
 			im = (*ioctx_func_p)(io_ctx, srcx, srcy, width, height);
+#if defined(HAVE_GD_JPG) && defined(HAVE_GD_BUNDLED)
+		} else if (image_type == PHP_GDIMG_TYPE_JPG) {
+			im = (*ioctx_func_p)(io_ctx, prescale);
+#endif
 		} else {
 			im = (*ioctx_func_p)(io_ctx);
 		}
@@ -2493,7 +2507,7 @@
 			case PHP_GDIMG_TYPE_JPG:
 				ignore_warning = INI_INT("gd.jpeg_ignore_warning");
 #ifdef HAVE_GD_BUNDLED
-				im = gdImageCreateFromJpeg(fp, ignore_warning);
+				im = gdImageCreateFromJpeg(fp, ignore_warning, prescale);
 #else
 				im = gdImageCreateFromJpeg(fp);
 #endif
@@ -2533,7 +2547,7 @@
 #endif /* HAVE_GD_GIF_READ */
 
 #ifdef HAVE_GD_JPG
-/* {{{ proto resource imagecreatefromjpeg(string filename)
+/* {{{ proto resource imagecreatefromjpeg(string filename[, int prescale])
    Create a new image from JPEG file or URL */
 PHP_FUNCTION(imagecreatefromjpeg)
 {
 [2009-10-01 18:54 UTC] pajoye@php.net
Thanks for the patch. However you seemed to have missed my answer where I said that I have a patch already.
 [2009-10-01 18:56 UTC] pajoye@php.net
Sorry, my last comment has been submitted too quickly.

I won't use this patch as it breaks API and ABI backward compatibility. It is also better to provide more user friendly functions to get a resized image without worrying about which scale can actually be used.

The patch is also missing the tests if libjpeg7 is actually used. I won't support patched jpeg6 as there are dozen versions out there.
 [2009-10-01 19:00 UTC] sriram dot natarajan at gmail dot com
oh, i missed your earlier post that you do have a patch. and your points on jpeg 6 is very true. i was just working on the test script. i guess, i will get back to my work :-)
 [2010-11-24 10:59 UTC] jani@php.net
-Package: Feature/Change Request +Package: GD related
 [2017-01-21 23:53 UTC] cmb@php.net
-Status: Assigned +Status: Suspended
 [2017-01-21 23:53 UTC] cmb@php.net
In my opinion, it doesn't make sense to implement this only for
PHP's bundled libgd, but rather it should be implemented in libgd,
generally. Therefore I've submitted a respective feature
request[1], and suspend this ticket.

[1] <https://github.com/libgd/libgd/issues/368>
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Oct 31 22:01:27 2024 UTC