5 # A PHP Object to Support Image File Manipulation
7 # NOTE: To use this object, either PHP must have internal support for the image formats
8 # to be manipulated (can be checked with the imagetypes() function) or the web server
9 # must be running with safe_mode off and certain external executables must be available
10 # to be invoked by the server. (A list of the needed executables can be obtained via
11 # the Image::RequiredExternalExecutables() method.)
13 # Copyright 2002-2004 Axis Data
14 # This code is free software that can be used or redistributed under the
15 # terms of Version 2 of the GNU General Public License, as published by the
16 # Free Software Foundation (http://www.fsf.org).
18 # Author: Edward Almasy (ealmasy@axisdata.com)
20 # Part of the AxisPHP library v1.2.5
21 # For more information see http://www.axisdata.com/AxisPHP/
26 # ---- PUBLIC INTERFACE --------------------------------------------------
33 # save source file name
37 $this->JpegSaveQuality = 80;
39 $this->FailedCommand =
"";
41 # get GD library version
42 if (extension_loaded(
"gd"))
44 if (in_array(
"imagecreatetruecolor", get_extension_funcs(
"gd")))
58 # if source file is readable
61 # if internal support is available for this image type
64 if ($this->DebugLevel > 0) { print(
"AI: using internal funcs for decoding image<br>\n"); }
66 # create PHP image object
67 switch ($this->
Type())
70 if ($this->DebugLevel > 1) { print(
"AI: file format is JPEG<br>\n"); }
71 $this->ImageObj = imagecreatefromjpeg($this->SourceFileName);
75 if ($this->DebugLevel > 1) { print(
"AI: file format is GIF<br>\n"); }
76 $this->ImageObj = imagecreatefromgif($this->SourceFileName);
80 if ($this->DebugLevel > 1) { print(
"AI: file format is BMP<br>\n"); }
81 $this->ImageObj = imagecreatefrombmp($this->SourceFileName);
85 if ($this->DebugLevel > 1) { print(
"AI: file format is PNG<br>\n"); }
86 $this->ImageObj = imagecreatefrompng($this->SourceFileName);
94 # if PHP image object creation failed
95 if (FALSE === $this->ImageObj)
102 # if external command execution possible
103 if (ini_get(
"safe_mode") !=
"1")
105 # determine external save command to convert image to portable format
106 switch ($this->
Type())
109 $this->DecodeCommand =
"bmptoppm ";
113 $this->DecodeCommand =
"giftopnm ";
117 $this->DecodeCommand =
"pngtopnm ";
121 $this->DecodeCommand =
"djpeg ";
128 $this->DecodeCommand .= realpath($this->SourceFileName).
" ";
132 # if format wasn't supported internally
135 # set error status to indicate unsupported image format
147 # save image with a new name and (optionally) a new type
148 function SaveAs($FileName, $NewImageType = NULL)
150 # assume we will succeed
153 # if destination file exists and is not writable
154 if (file_exists($FileName) && (is_writable($FileName) != TRUE))
159 # else if destination directory is not writable
160 elseif (is_writable(dirname($FileName)) != TRUE)
167 # if no image type specified try to determine based on file name or use source file type
168 if ($NewImageType == NULL)
171 { $NewImageType = $this->
Type($FileName); }
173 { $NewImageType = $this->
Type(); }
176 # if input and output types both supported by internal functions
179 # if image cropping or scaling was requested
180 if (isset($this->CroppedXSize)
181 || isset($this->ScaledXSize)
182 || isset($this->ScaledYSize))
184 # determine destination image size
185 if (isset($this->ScaledXSize) && isset($this->ScaledYSize)
186 && ($this->MaintainAspectRatio != TRUE))
191 elseif (isset($this->ScaledXSize)
192 || ($this->ScaledXSize > $this->ScaledYSize))
195 $DstYSize = ($this->ScaledXSize * $this->
YSize())
198 elseif (isset($this->ScaledYSize))
200 $DstXSize = ($this->ScaledYSize * $this->
XSize())
204 elseif (isset($this->CroppedXSize))
211 $DstXSize = $this->
XSize();
212 $DstYSize = $this->
YSize();
215 # create destination image object
216 if (($NewImageType ==
IMGTYPE_GIF) || ($this->GDVersion < 2))
218 $DstImage = imagecreate($DstXSize, $DstYSize);
222 $DstImage = imagecreatetruecolor($DstXSize, $DstYSize);
225 # determine area of source image to use
226 if (isset($this->CroppedXSize))
233 $SrcXSize = $this->
XSize();
234 $SrcYSize = $this->
YSize();
237 # copy/scale portion of original image to destination image
238 if ($this->GDVersion >= 2)
240 imagecopyresampled($DstImage, $this->ImageObj,
242 $this->CroppedXOrigin, $this->CroppedYOrigin,
243 $DstXSize, $DstYSize,
244 $SrcXSize, $SrcYSize);
248 imagecopyresized($DstImage, $this->ImageObj,
250 $this->CroppedXOrigin, $this->CroppedYOrigin,
251 $DstXSize, $DstYSize,
252 $SrcXSize, $SrcYSize);
260 # save image to new file
261 switch ($NewImageType)
264 imagegif($DstImage, $FileName);
268 imagejpeg($DstImage, $FileName, $this->JpegSaveQuality);
272 imagepng($DstImage, $FileName);
276 imagewbmp($DstImage, $FileName);
285 # build command (convert image to intermediate form)
288 # build command (crop if requested)
289 if (isset($this->CroppedXSize))
291 $Command .=
"| pnmcut ".$this->CroppedXOrigin.
" ".$this->CroppedYOrigin.
" "
292 .$this->CroppedXSize.
" ".$this->CroppedYSize.
" ";
295 # build command (scale if requested)
296 if (isset($this->ScaledXSize) || isset($this->ScaledYSize))
298 $Command .=
"| pnmscale ";
299 if ($this->MaintainAspectRatio
300 && isset($this->ScaledXSize) && isset($this->ScaledYSize))
306 if (isset($this->ScaledXSize)) { $Command .=
"-xsize ".$this->ScaledXSize.
" "; }
307 if (isset($this->ScaledYSize)) { $Command .=
"-ysize ".$this->ScaledYSize.
" "; }
311 # build command (convert to final form)
312 switch ($NewImageType)
315 $Command .=
"| ppmquant 256 | ppmtobmp -windows ";
319 $Command .=
"| ppmquant 256 | ppmtogif ";
323 $Command .=
"| ppmquant 256 | pnmtopng ";
328 $Command .=
"| cjpeg -quality ".$this->JpegSaveQuality.
" ";
332 # build command (send output to new image file)
333 $Command .=
"> ".$FileName;
337 $CommandResult = system($Command);
339 # set error status if command failed
340 if ($CommandResult === FALSE)
343 $this->FailedCommand = $Command;
348 # report success or failure to caller
352 # return the X (horizontal) image size in pixels
359 # return the Y (vertical) image size in pixels
366 # specify the size to scale the image to for the next SaveAs()
369 # save size for scaling
375 # specify the size to crop the image to for the next SaveAs()
378 # save origin and size for cropping
385 # return the image type
386 function Type($FileName = NULL)
389 if (preg_match(
"/.*\\.jp[e]{0,1}g$/i", $FileName)) {
return IMGTYPE_JPEG; }
390 elseif (preg_match(
"/.*\\.gif$/i", $FileName)) {
return IMGTYPE_GIF; }
391 elseif (preg_match(
"/.*\\.bmp$/i", $FileName)) {
return IMGTYPE_BMP; }
392 elseif (preg_match(
"/.*\\.png$/i", $FileName)) {
return IMGTYPE_PNG; }
396 # return the file name extension for the image
401 return Image::$AxisImageFileExtensions[$this->
Type()];
405 if (isset(Image::$AxisImageFileExtensions[$Type]))
407 return Image::$AxisImageFileExtensions[$Type];
416 # set/get the quality (0-100) for JPEG images created with SaveAs()
419 if ($NewSetting != NULL) { $this->JpegSaveQuality = $NewSetting; }
423 # check availability of external executables and return list of any that are not found
426 # start with empty list of missing executables
427 $MissingExecutables = array();
429 # for each required executable
432 # if executable did not appear to be available
435 # add executable to list of missing
436 $MissingExecutables[] = $Executable;
440 # return list of missing executables to caller
441 return $MissingExecutables;
444 # return list of all required external executables
447 # start with the assumption that no executables are required
448 $RequiredExecutables = array();
450 # if no image types specified assume all image types
451 if ($ImageTypes == NULL)
456 # add format-specific executables that may or may not be needed
458 && (!function_exists(
"imagetypes") || !(imagetypes() & IMG_JPG)))
460 $RequiredExecutables[] =
"djpeg";
461 $RequiredExecutables[] =
"cjpeg";
464 && (!function_exists(
"imagetypes") || !(imagetypes() & IMG_GIF)))
466 $RequiredExecutables[] =
"giftopnm";
467 $RequiredExecutables[] =
"ppmtogif";
470 && (!function_exists(
"imagetypes") || !(imagetypes() & IMG_PNG)))
472 $RequiredExecutables[] =
"pngtopnm";
473 $RequiredExecutables[] =
"pnmtopng";
477 $RequiredExecutables[] =
"bmptoppm";
478 $RequiredExecutables[] =
"ppmtobmp";
481 # if any format-specific executables needed
482 if (count($RequiredExecutables) != 0)
484 # add basic manipulation executables
485 $RequiredExecutables[] =
"pnmcut";
486 $RequiredExecutables[] =
"pnmscale";
487 $RequiredExecutables[] =
"ppmquant";
488 $RequiredExecutables[] =
"pnmfile";
491 # return list of required executables to caller
492 return $RequiredExecutables;
495 # return supported image formats
498 # start out assuming no formats are supported
501 # if JPEG is supported by PHP or needed external executables are available
502 if ((function_exists(
"imagetypes") && defined(
"IMG_JPG")
503 && (imagetypes() & IMG_JPG))
507 # add JPEG to list of supported formats
511 # if GIF is supported by PHP or needed external executables are available
512 if ((function_exists(
"imagetypes") && defined(
"IMG_GIF")
513 && (imagetypes() & IMG_GIF))
517 # add GIF to list of supported formats
521 # if PNG is supported by PHP or needed external executables are available
522 if ((function_exists(
"imagetypes") && defined(
"IMG_PNG")
523 && (imagetypes() & IMG_PNG))
527 # add PNG to list of supported formats
531 # if needed external executables are available for BMP
532 # needed executables being present is not sufficient for BMP support in PHP
533 # test is being shortcutted to false to reflect no PHP support for BMPs
537 # add BMP to list of supported formats
541 # report to caller what formats are supported
545 # return names (upper-case extensions) of supported image formats
548 # assume that no formats are supported
549 $FormatNames = array();
551 # retrieve supported formats
554 # for each possible supported format
555 foreach (Image::$AxisImageFileExtensions as $ImageType => $ImageExtension)
557 # if format is supported
558 if ($ImageType & $SupportedFormats)
560 # add format extension to list of supported image format names
561 $FormatNames[] = strtoupper($ImageExtension);
565 # return supported image format names to caller
569 # return the error status set by the constructor or the last call to SaveAs()
575 # return string containing external command that failed
582 # ---- PRIVATE INTERFACE -------------------------------------------------
602 # image file extensions
603 private static $AxisImageFileExtensions = array(
612 # if we do not already have image info
613 if (!isset($this->ImageXSize))
615 # if we are using internal image functions
618 # read size information from image object
619 $this->ImageXSize = imagesx($this->ImageObj);
620 $this->ImageYSize = imagesy($this->ImageObj);
624 # retrieve image info string
625 $Command = $this->DecodeCommand.
"| pnmfile ";
626 $Result = exec(
"$Command");
628 # parse image info string
629 $Pieces = preg_split(
"/\s+/", $Result);
630 $this->ImageXSize = $Pieces[3];
631 $this->ImageYSize = $Pieces[5];
638 if ($Format == NULL) { $Format = $this->
Type(); }
640 if (!function_exists(
"imagetypes")) {
return FALSE; }
645 return (imagetypes() & IMG_JPG) ? TRUE : FALSE;
649 return (imagetypes() & IMG_GIF) ? TRUE : FALSE;
657 return (imagetypes() & IMG_PNG) ? TRUE : FALSE;
666 # check whether external executable is available and report result back to caller
669 static $ExecutableAvailable;
671 if (!isset($ExecutableAvailable[$ExecutableName]))
673 $Result = exec(
"which ".$ExecutableName.
" 2>&1");
674 $ExecutableAvailable[$ExecutableName] =
675 (basename($Result) == $ExecutableName) ? TRUE : FALSE;
677 return $ExecutableAvailable[$ExecutableName];
681 # image type definitions (these are purposefully different from those defined by PHP GD lib)
682 define(
"IMGTYPE_UNKNOWN", 0);
683 define(
"IMGTYPE_JPEG", 1);
684 define(
"IMGTYPE_GIF", 2);
685 define(
"IMGTYPE_BMP", 4);
686 define(
"IMGTYPE_PNG", 8);
688 # error status definitions
689 define(
"AI_OKAY", 0);
690 define(
"AI_FILEUNREADABLE", 1);
691 define(
"AI_IMGOBJCREATEFAILED", 2);
692 define(
"AI_PPMCMDFAILED", 4);
693 define(
"AI_INTERNALERROR", 8);
694 define(
"AI_UNKNOWNTYPE", 16);
695 define(
"AI_UNSUPPORTEDFORMAT", 32);
696 define(
"AI_DESTINATIONUNWRITABLE", 64);
698 # supply imagetypes() function if not defined
699 if (!function_exists(
"imagetypes"))
701 # (returning 0 indicates no image types supported)
702 function imagetypes() {
return 0; }