Question

I want to allow users to upload avatar-type images in a variety of formats (GIF, JPEG, and PNG at least), but to save them all as PNG database BLOBs. If the images are oversized, pixelwise, I want to resize them before DB-insertion.

What is the best way to use GD to do the resizing and PNG conversion?

Edit: Sadly, only GD is available on the server I need to use, no ImageMagick.

Was it helpful?

Solution

<?php                                              
/*
Resizes an image and converts it to PNG returning the PNG data as a string
*/
function imageToPng($srcFile, $maxSize = 100) {  
    list($width_orig, $height_orig, $type) = getimagesize($srcFile);        

    // Get the aspect ratio
    $ratio_orig = $width_orig / $height_orig;

    $width  = $maxSize; 
    $height = $maxSize;

    // resize to height (orig is portrait) 
    if ($ratio_orig < 1) {
        $width = $height * $ratio_orig;
    } 
    // resize to width (orig is landscape)
    else {
        $height = $width / $ratio_orig;
    }

    // Temporarily increase the memory limit to allow for larger images
    ini_set('memory_limit', '32M'); 

    switch ($type) 
    {
        case IMAGETYPE_GIF: 
            $image = imagecreatefromgif($srcFile); 
            break;   
        case IMAGETYPE_JPEG:  
            $image = imagecreatefromjpeg($srcFile); 
            break;   
        case IMAGETYPE_PNG:  
            $image = imagecreatefrompng($srcFile);
            break; 
        default:
            throw new Exception('Unrecognized image type ' . $type);
    }

    // create a new blank image
    $newImage = imagecreatetruecolor($width, $height);

    // Copy the old image to the new image
    imagecopyresampled($newImage, $image, 0, 0, 0, 0, $width, $height, $width_orig, $height_orig);

    // Output to a temp file
    $destFile = tempnam();
    imagepng($newImage, $destFile);  

    // Free memory                           
    imagedestroy($newImage);

    if ( is_file($destFile) ) {
        $f = fopen($destFile, 'rb');   
        $data = fread($f);       
        fclose($f);

        // Remove the tempfile
        unlink($destFile);    
        return $data;
    }

    throw new Exception('Image conversion failed.');
}

OTHER TIPS

Your process steps should look like this:

  1. Verify the filetype
  2. Load the image if it is a supported filetype into GD using imagecreatefrom*
  3. Resizing using imagecopyresize or imagecopyresampled
  4. Save the image using imagepng($handle, 'filename.png', $quality, $filters)

ImageMagick is faster, generates better images, is more configurable, and finally is (IMO) much easier to code for.

@ceejayoz Just wait for the new GD - it's OOP like MySQLi and it's actually not bad :)

If you want to use gdlib, use gdlib 2 or higher. It has a function called imagecopyresampled(), which will interpolate pixels while resizing and look much better.

Also, I've always heard noted around the net that storing images in the database is bad form:

  • It's slower to access than the disk
  • Your server will need to run a script to get to the image instead of simply serving a file
  • Your script now is responsible for a lot of stuff the web server used to handle:
    • Setting the proper Content-Type header
    • Setting the proper caching/timeout/E-tag headers, so clients can properly cache the image. If do not do this properly, the image serving script will be hit on every request, increasing the load on the server even more.

The only advantage I can see is that you don't need to keep your database and image files synchronized. I would still recommend against it though.

Are you sure you have no ImageMagick on server?

I guest you use PHP (question is tagged with PHP). Hosting company which I use has no ImageMagick extension turned on according to phpinfo().

But when I asked them about they said here is the list of ImageMagick programs available from PHP code. So simply -- there are no IM interface in PHP, but I can call IM programs directly from PHP.

I hope you have the same option.

And I strongly agree -- storing images in database is not good idea.

Something like this, perhaps:


<?php
   //Input file
   $file = "myImage.png";
   $img = ImageCreateFromPNG($file);

   //Dimensions
   $width = imagesx($img);
   $height = imagesy($img);
   $max_width = 300;
   $max_height = 300;
   $percentage = 1;

   //Image scaling calculations
   if ( $width > $max_width ) { 
      $percentage = ($height / ($width / $max_width)) > $max_height ?
           $height / $max_height :
           $width / $max_width;
   }
   elseif ( $height > $max_height) {
      $percentage = ($width / ($height / $max_height)) > $max_width ? 
           $width / $max_width :
           $height / $max_height;
   }
   $new_width = $width / $percentage;
   $new_height = $height / $percentage;

   //scaled image
   $out = imagecreatetruecolor($new_width, $new_height);
   imagecopyresampled($out, $img, 0, 0, 0, 0, $new_width, $new_height, $width, $height);

   //output image
   imagepng($out);
?>

I haven't tested the code so there might be some syntax errors, however it should give you a fair presentation on how it could be done. Also, I assumed a PNG file. You might want to have some kind of switch statement to determine the file type.

This article seems like it would fit what you want. You'll need to change the saving imagejpeg() function to imagepng() and have it save the file to a string rather than output it to the page, but other than that it should be easy copy/paste into your existing code.

Is GD absolutely required? ImageMagick is faster, generates better images, is more configurable, and finally is (IMO) much easier to code for.

I think this page is a good starting point. It uses imagecreatefrom(jpeg/gif/png) and resize and converts the image and then outputs to the browser. Instead of outputting the browser you could output to a BLOB in a DB without many minuttes of code-rewrite.

phpThumb is a high-level abstraction that may be worth looking at.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top