Fixed XenForo_Image_Gd PNG transparency

Rasmus Vind

Well-known member
I was using the Addon called Custom Node Icon. I was not very happy with the fact that when I uploaded a PNG, the transparency disappeared. Turns out that this is an issue with XenForo, not Custom Node Icon. Well, I suppose they could have rewritten XenForo_Image_Gd, but the whole point of XenForo is that we can all re-use what you guys have created for us. The Addon takes an image you upload, maybe resizes it and outputs it into a folder, but most of the time it does not process the image at all, it merely loads it in and saves it back to disk. This process should not cause any significant data loss I think. But it does, the transparency of PNG files (and possibly other formats too, GIF?) disappears. I found on StackOverflow that you have to add a few lines of code to make sure that transparency is kept. Here is my modified output function for XenForo_Image_Gd:
PHP:
    public function output($outputType, $outputFile = null, $quality = 85)
    {
        switch ($outputType)
        {
            case IMAGETYPE_GIF: $success = imagegif($this->_image, $outputFile); break;
            case IMAGETYPE_JPEG: $success = imagejpeg($this->_image, $outputFile, $quality); break;
            case IMAGETYPE_PNG:
                // Ralle: hack to save transparency
                $background = imagecolorallocate($this->_image, 0, 0, 0);
                imagecolortransparent($this->_image, $background);
                imagealphablending($this->_image, false);
                imagesavealpha($this->_image, true);
                // Ralle end

                // "quality" seems to be misleading, always force 9
                $success = imagepng($this->_image, $outputFile, 9, PNG_ALL_FILTERS);
                break;

            default:
                throw new XenForo_Exception('Invalid output type given. Expects IMAGETYPE_XXX constant.');
        }

        return $success;
    }

I read somewhere that this was a feature because you want people to use real life pictures as your profile picture. But if the image class has to be useful for Addons too, this quickly becomes a flaw.
I hope you will consider adding this to the XenForo codebase.

Thank you.
 
I have an addon that resizes PNG images (using XenForo's normal function with GD), and it preserves the transparency just fine. Maybe it's something to do with the version of PHP (maybe GD was improved in the newer versions?). I'm using PHP 5.5.6.
 
Transparency seems to be maintained for me in PHP 5.3 and 5.4 as well.

Can you provide a simplified test case with your code that reproduces the issue? (Please include the image that reproduces it, as that may be relevant.)
 
I will upload a test case at another time. I believe the bug would appear when digitalpoint removes line 2 from his code, but I have not tested it in this exact case. The bug in my addon appears when it does not have to transform the image in any way.
I am running PHP version 5.4.17.

Edit: I just looked at the source again. The code I added to the Gd.php file is run when you call the thumbnail function, but not if you don't.
 
I will upload a test case at another time. I believe the bug would appear when digitalpoint removes line 2 from his code, but I have not tested it in this exact case. The bug in my addon appears when it does not have to transform the image in any way.
I am running PHP version 5.4.17.

Edit: I just looked at the source again. The code I added to the Gd.php file is run when you call the thumbnail function, but not if you don't.
Just out of curiosity, why would you want to load it into the Image class and output it when you aren't manipulating the image in any way? Wouldn't it make more sense to just use the original image?
 
Just out of curiosity, why would you want to load it into the Image class and output it when you aren't manipulating the image in any way? Wouldn't it make more sense to just use the original image?
Agreed, it is stupid. But the code should not change the image in any significant way. But it removes the transparency, which I consider a fault in the library. The code that preserves the transparency should be moved from the thumbnail function to somewhere else so it is called even if no thumbnail is created.
Anyway, this addon I was talking about checks if the image has the exact size of the node icons. If not, it resizes them, but I was uploading the correct size every time which resulted in the addon not having to modify the image.
 
I can't reproduce it without transforms either. Please include the test case and an example image. It'd also be worth seeing the details about your GD install from PHP info.
 
I finally found time to reproduce this and make a simple test.

I am running on a Mac running OS X Mavericks using the built-in PHP, Apache and have installed MySQL myself. So far it has worked fine.

Here is my phpinfo():
https://dl.dropboxusercontent.com/u/323865/2013-12-05 phpinfo for xenforo.html

Here is the image I was testing with, I zipped it so service will convert it and skew the results:
https://dl.dropboxusercontent.com/u/323865/2013-12-05 test image for xenforo.zip

Here is my test script:
PHP:
<?php

$startTime = microtime(true);
$fileDir = dirname(__FILE__);

require($fileDir . '/library/XenForo/Autoloader.php');
XenForo_Autoloader::getInstance()->setupAutoloader($fileDir . '/library');

XenForo_Application::initialize($fileDir . '/library', $fileDir);
XenForo_Application::set('page_start_time', $startTime);

$filename = 'test.png';
$filename2 = 'test2.png';

$image = XenForo_Image_Abstract::createFromFile($filename, IMAGETYPE_PNG);
// $image->thumbnail(30);
$image->output(IMAGETYPE_PNG, $filename2);

It works fine if I uncomment the thumbnail() call (and the image is bigger than the size).

Otherwise this is what:
https://dl.dropboxusercontent.com/u/323865/2013-12-05 result image for xenforo.zip

Which has no transparency.
 
This appears to be image specific, though I haven't delved into the specific conditions. I was able to reproduce with the given image, but not with the XF smilies sprite, for example.

But disabling alpha blending and saving the alpha channel is what's needed for PNGs.
 
Top Bottom