phippu Posted March 29, 2015 Share Posted March 29, 2015 (edited) Hello! I read a lot about the ImageSizer class from processwire, because I want to contribute to get better image resizing. Processwire (horst in special) has implemented a gamma correction before resizing images. Why this has to be done is explained here: http://www.4p8.com/eric.brasseur/gamma.html . I have this link also from a post from Horst. Now I stumbled upon a bug that causes to loose image information. This is the function I am talking about in ImageSizer.php protected function gammaCorrection(&$image, $mode) { if(-1 == $this->defaultGamma || !is_bool($mode)) return; if($mode) { // linearizes to 1.0 if(imagegammacorrect($image, $this->defaultGamma, 1.0)) $this->gammaLinearized = true; } else { if(!isset($this->gammaLinearized) || !$this->gammaLinearized) return; // switch back to original Gamma if(imagegammacorrect($image, 1.0, $this->defaultGamma)) unset($this->gammaLinearized); } } This function uses the gd-lib function imagegammacorrect to set the gamma value to 1.0 before resizing and set it back after resizing. The imagegammacorrect function provides a datatype int, which has on my server the size of 8 bits, just enough to store a picture that also stores each pixel in 8 bit value.What the imagegammacorrect function does: It exponentiates each pixel-value of the image with the gamma value entered (2.0 by default on pwire). Then it resizes the image. After that to set back the gamma it exponantiates with the inverse value that was before exponentiated. (1/2.0=0.5 with default value). Because only integer (8bits) is provided the function is rounding the values and makes some error. Here is my test picture (2400x2400 pixels) I resized every image to 300x300 pixels. Here are the resized ones with different gamma values: Gamma function omitted Gamma value 2.0 (standard) Gamma value 3.0 Gamma value 4.0 Now I was curious if I could reconstruct the error in an other program. So I wrote a little script in Matlab and did the same. Heres the script: % load image [img,map,alpha] = imread('gamma_dalai_lama_gray.jpg'); %imshow(img, 'InitialMagnification', 100); gamma = 2; scale_factor = 300/2400; figure(1); imshow(img, 'InitialMagnification', 200); figure(2); tmp = double(img).^gamma; img_gamma = uint8(tmp./((255^gamma)/255)); img_resized = imresize(img_gamma, 0.5); tmp2 = double(img_resized).^(1/gamma); img_gamma = uint8(tmp2./((255^(1/gamma))/255)); imshow(img_gamma, 'InitialMagnification', 400); imwrite(img_gamma, 'testbild_300_gamma_2.0.jpg'); Here's the result pictures: Gamma value 2.0 (with matlab) Gamma value 3.0 (matlab) Gamma value 4.0 (matlab) Theoretical we would need more than 8bits per pixel to not loose any data. That would be for Gamma 4.0: (2^8)^4=32bits per pixel. Or for Gamma 2.0: (2^8)^2=16bits per pixel. I don't know how to solve this problem in php so I'm writing in here in the hope someone has a good solution or a hint what I'm doing wrong... Processwire Version 2.5.3 PHP-Version is 5.6.0 If you need more informations let me know. Edit: My integer size has not the size of 8bits that was 8bytes so 64bits... But as I confirmed with matlab script there is an 8bit cropping going on, maybe in the gd-lib? Edit: I think I found out where this is caused. It's in the php sources (php-src/ext/gd/gd.c on line 3133). The cropping happens, because an integer is used instead of a double or float value (the dark pattern in my test image gets even darker with gamma correction). My suggestion is to take out the Gamma Correction and contribute code to GD-Lib to implement it there. With plain php we can't make it better for now. Edited March 30, 2015 by phippu 2 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now