<?php /* Question2Answer by Gideon Greenspan and contributors http://www.question2answer.org/ File: qa-include/util/image.php Description: Some useful image-related functions (using GD) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. More about this license: http://www.question2answer.org/license.php */ if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser header('Location: ../'); exit; } function qa_has_gd_image() /* Return true if PHP has the GD extension installed and it appears to be usable */ { return extension_loaded('gd') && function_exists('imagecreatefromstring') && function_exists('imagejpeg'); } function qa_image_file_too_big($imagefile, $size=null) /* Check if the image in $imagefile will be too big for PHP/GD to process given memory usage and limits Pass the width and height limit beyond which the image will require scaling in $size (if any) Returns false if the image will fit fine, otherwise a safe estimate of the factor the image should be sized by */ { if (function_exists('memory_get_usage')) { $gotbytes=trim(@ini_get('memory_limit')); $gotbytes = convert_to_bytes(substr($gotbytes, -1), $gotbytes); if ($gotbytes>0) { // otherwise we clearly don't know our limit $gotbytes=($gotbytes-memory_get_usage())*0.9; // safety margin of 10% $needbytes=filesize($imagefile); // memory to store file contents $imagesize=@getimagesize($imagefile); if (is_array($imagesize)) { // if image can't be parsed, don't worry about anything else $width=$imagesize[0]; $height=$imagesize[1]; $bits=isset($imagesize['bits']) ? $imagesize['bits'] : 8; // these elements can be missing (PHP bug) so assume this as default $channels=isset($imagesize['channels']) ? $imagesize['channels'] : 3; // for more info: http://gynvael.coldwind.pl/?id=223 $needbytes+=$width*$height*$bits*$channels/8*2; // memory to load original image if (isset($size) && qa_image_constrain($width, $height, $size)) // memory for constrained image $needbytes+=$width*$height*3*2; // *2 here and above based on empirical tests } if ($needbytes>$gotbytes) return sqrt($gotbytes/($needbytes*1.5)); // additional 50% safety margin since JPEG quality may change } } return false; } function qa_image_constrain_data($imagedata, &$width, &$height, $maxwidth, $maxheight=null) /* Given $imagedata containing JPEG/GIF/PNG data, constrain it proportionally to fit in $maxwidth x $maxheight. Return the new image data (will always be a JPEG), and set the $width and $height variables. If $maxheight is omitted or set to null, assume it to be the same as $maxwidth. */ { $inimage=@imagecreatefromstring($imagedata); if (is_resource($inimage)) { $width=imagesx($inimage); $height=imagesy($inimage); // always call qa_gd_image_resize(), even if the size is the same, to take care of possible PNG transparency qa_image_constrain($width, $height, $maxwidth, $maxheight); qa_gd_image_resize($inimage, $width, $height); } if (is_resource($inimage)) { $imagedata=qa_gd_image_jpeg($inimage); imagedestroy($inimage); return $imagedata; } return null; } function qa_image_constrain(&$width, &$height, $maxwidth, $maxheight=null) /* Given and $width and $height, return true if those need to be contrained to fit in $maxwidth x $maxheight. If so, also set $width and $height to the new proportionally constrained values. If $maxheight is omitted or set to null, assume it to be the same as $maxwidth. */ { if (!isset($maxheight)) $maxheight=$maxwidth; if (($width>$maxwidth) || ($height>$maxheight)) { $multiplier=min($maxwidth/$width, $maxheight/$height); $width=floor($width*$multiplier); $height=floor($height*$multiplier); return true; } return false; } function qa_gd_image_resize(&$image, $width, $height) /* Resize the GD $image to $width and $height, setting it to null if the resize failed */ { $oldimage=$image; $image=null; $newimage=imagecreatetruecolor($width, $height); $white=imagecolorallocate($newimage, 255, 255, 255); // fill with white first in case we have a transparent PNG imagefill($newimage, 0, 0, $white); if (is_resource($newimage)) { if (imagecopyresampled($newimage, $oldimage, 0, 0, 0, 0, $width, $height, imagesx($oldimage), imagesy($oldimage))) $image=$newimage; else imagedestroy($newimage); } imagedestroy($oldimage); } function qa_gd_image_jpeg($image, $output=false) /* Return the JPEG data for GD $image, also echoing it to browser if $output is true */ { ob_start(); imagejpeg($image, null, 90); return $output ? ob_get_flush() : ob_get_clean(); } function qa_gd_image_formats() /* Return an array of strings listing the image formats that are supported */ { $imagetypebits=imagetypes(); $bitstrings=array( IMG_GIF => 'GIF', IMG_JPG => 'JPG', IMG_PNG => 'PNG', ); foreach (array_keys($bitstrings) as $bit) if (!($imagetypebits&$bit)) unset($bitstrings[$bit]); return $bitstrings; } /* Omit PHP closing tag to help avoid accidental output */