CWIS Developer Documentation
Image.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # Axis--Image.php
4 # A PHP Object to Support Image File Manipulation
5 #
6 # Copyright 1999-2013 Axis Data
7 # This code is free software that can be used or redistributed under the
8 # terms of Version 2 of the GNU General Public License, as published by the
9 # Free Software Foundation (http://www.fsf.org).
10 #
11 # Part of the AxisPHP library v1.2.5
12 # For more information see http://www.axisdata.com/AxisPHP/
13 #
14 
15 class Image {
16 
17  # ---- PUBLIC INTERFACE --------------------------------------------------
18 
19  # image type definitions
20  # (these are purposefully different from those defined by PHP GD lib)
21  const IMGTYPE_UNKNOWN = 0;
22  const IMGTYPE_JPEG = 1;
23  const IMGTYPE_GIF = 2;
24  const IMGTYPE_BMP = 4;
25  const IMGTYPE_PNG = 8;
26 
28  {
29  # set debug level
30  $this->DebugLevel = $DebugLevel;
31 
32  # save source file name
33  $this->SourceFileName = $SourceFileName;
34 
35  # set default values
36  $this->JpegSaveQuality = 80;
37  $this->ErrorStatus = AI_OKAY;
38  $this->FailedCommand = "";
39 
40  # get GD library version
41  if (extension_loaded("gd"))
42  {
43  if (in_array("imagecreatetruecolor", get_extension_funcs("gd")))
44  {
45  $this->GDVersion = 2;
46  }
47  else
48  {
49  $this->GDVersion = 1;
50  }
51  }
52  else
53  {
54  $this->GDVersion = 0;
55  }
56 
57  # if source file is readable
58  if (is_readable(realpath($SourceFileName)))
59  {
60  # if support is available for this image type
61  if ($this->ImageFormatSupportedByPhp())
62  {
63  # create PHP image object
64  switch ($this->Type())
65  {
66  case self::IMGTYPE_JPEG:
67  if ($this->DebugLevel > 1) { print("AI: file format is JPEG<br>\n"); }
68  $this->ImageObj = imagecreatefromjpeg($this->SourceFileName);
69  break;
70 
71  case self::IMGTYPE_GIF:
72  if ($this->DebugLevel > 1) { print("AI: file format is GIF<br>\n"); }
73  $this->ImageObj = imagecreatefromgif($this->SourceFileName);
74  break;
75 
76  case self::IMGTYPE_BMP:
77  if ($this->DebugLevel > 1) { print("AI: file format is BMP<br>\n"); }
78  $this->ImageObj = imagecreatefrombmp($this->SourceFileName);
79  break;
80 
81  case self::IMGTYPE_PNG:
82  if ($this->DebugLevel > 1) { print("AI: file format is PNG<br>\n"); }
83  $this->ImageObj = imagecreatefrompng($this->SourceFileName);
84  break;
85 
86  default:
87  $this->ErrorStatus = AI_INTERNALERROR;
88  break;
89  }
90 
91  # if PHP image object creation failed
92  if (FALSE === $this->ImageObj)
93  {
94  # set error status
95  $this->ErrorStatus = AI_IMGOBJCREATEFAILED;
96  }
97  }
98  else
99  {
100  # set error status to indicate unsupported image format
101  $this->ErrorStatus = AI_UNSUPPORTEDFORMAT;
102  }
103  }
104  else
105  {
106  # set error status
107  $this->ErrorStatus = AI_FILEUNREADABLE;
108  }
109  }
110 
111  # save image with a new name and (optionally) a new type
112  function SaveAs($FileName, $NewImageType = NULL)
113  {
114  # assume we will succeed
115  $this->ErrorStatus = AI_OKAY;
116 
117  # if destination file exists and is not writable
118  if (file_exists($FileName) && (is_writable($FileName) != TRUE))
119  {
120  # set error code
121  $this->ErrorStatus = AI_DESTINATIONUNWRITABLE;
122  }
123  # else if destination directory is not writable
124  elseif (is_writable(dirname($FileName)) != TRUE)
125  {
126  # set error code
127  $this->ErrorStatus = AI_DESTINATIONUNWRITABLE;
128  }
129  else
130  {
131  # if no image type specified try to determine based on file name or use source file type
132  if ($NewImageType == NULL)
133  {
134  if ($this->Type($FileName) != self::IMGTYPE_UNKNOWN)
135  { $NewImageType = $this->Type($FileName); }
136  else
137  { $NewImageType = $this->Type(); }
138  }
139 
140  # if input and output types both supported
141  if ($this->ImageFormatSupportedByPhp() && $this->ImageFormatSupportedByPhp($NewImageType))
142  {
143  # if image cropping or scaling was requested
144  if (isset($this->CroppedXSize)
145  || isset($this->ScaledXSize)
146  || isset($this->ScaledYSize))
147  {
148  # determine destination image size
149  if (isset($this->ScaledXSize) && isset($this->ScaledYSize)
150  && ($this->MaintainAspectRatio != TRUE))
151  {
152  $DstXSize = $this->ScaledXSize;
153  $DstYSize = $this->ScaledYSize;
154  }
155  elseif (isset($this->ScaledXSize)
156  || ($this->ScaledXSize > $this->ScaledYSize))
157  {
158  $DstXSize = $this->ScaledXSize;
159  $DstYSize = ($this->ScaledXSize * $this->YSize())
160  / $this->XSize();
161  }
162  elseif (isset($this->ScaledYSize))
163  {
164  $DstXSize = ($this->ScaledYSize * $this->XSize())
165  / $this->YSize();
166  $DstYSize = $this->ScaledYSize;
167  }
168  elseif (isset($this->CroppedXSize))
169  {
170  $DstXSize = $this->CroppedXSize;
171  $DstYSize = $this->CroppedYSize;
172  }
173  else
174  {
175  $DstXSize = $this->XSize();
176  $DstYSize = $this->YSize();
177  }
178 
179  # create destination image object
180  if (($NewImageType == self::IMGTYPE_GIF) || ($this->GDVersion < 2))
181  {
182  $DstImage = imagecreate($DstXSize, $DstYSize);
183  }
184  else
185  {
186  $DstImage = imagecreatetruecolor($DstXSize, $DstYSize);
187  imagealphablending($DstImage, FALSE);
188  imagesavealpha($DstImage, TRUE);
189  }
190 
191  # determine area of source image to use
192  if (isset($this->CroppedXSize))
193  {
194  $SrcXSize = $this->CroppedXSize;
195  $SrcYSize = $this->CroppedYSize;
196  }
197  else
198  {
199  $SrcXSize = $this->XSize();
200  $SrcYSize = $this->YSize();
201  }
202 
203  # copy/scale portion of original image to destination image
204  if ($this->GDVersion >= 2)
205  {
206  imagecopyresampled($DstImage, $this->ImageObj,
207  0, 0,
208  $this->CroppedXOrigin, $this->CroppedYOrigin,
209  $DstXSize, $DstYSize,
210  $SrcXSize, $SrcYSize);
211  }
212  else
213  {
214  imagecopyresized($DstImage, $this->ImageObj,
215  0, 0,
216  $this->CroppedXOrigin, $this->CroppedYOrigin,
217  $DstXSize, $DstYSize,
218  $SrcXSize, $SrcYSize);
219  }
220  }
221  else
222  {
223  $DstImage =& $this->ImageObj;
224  }
225 
226  # save image to new file
227  switch ($NewImageType)
228  {
229  case self::IMGTYPE_GIF:
230  imagegif($DstImage, $FileName);
231  break;
232 
233  case self::IMGTYPE_JPEG:
234  imagejpeg($DstImage, $FileName, $this->JpegSaveQuality);
235  break;
236 
237  case self::IMGTYPE_PNG:
238  imagepng($DstImage, $FileName, 9);
239  break;
240 
241  case self::IMGTYPE_BMP:
242  imagebmp($DstImage, $FileName);
243  break;
244 
245  default:
246  $this->ErrorStatus = AI_INTERNALERROR;
247  break;
248  }
249  }
250  else
251  {
252  # set error status to indicate unsupported image format
253  $this->ErrorStatus = AI_UNSUPPORTEDFORMAT;
254  }
255  }
256 
257  # report success or failure to caller
258  return $this->ErrorStatus;
259  }
260 
261  # return the X (horizontal) image size in pixels
262  function XSize()
263  {
264  $this->ReadSize();
265  return $this->ImageXSize;
266  }
267 
268  # return the Y (vertical) image size in pixels
269  function YSize()
270  {
271  $this->ReadSize();
272  return $this->ImageYSize;
273  }
274 
275  # specify the size to scale the image to for the next SaveAs()
277  {
278  # save size for scaling
279  $this->ScaledXSize = $ScaledXSize;
280  $this->ScaledYSize = $ScaledYSize;
281  $this->MaintainAspectRatio = $MaintainAspectRatio;
282  }
283 
284  # specify the size to crop the image to for the next SaveAs()
286  {
287  # save origin and size for cropping
288  $this->CroppedXSize = $CroppedXSize;
289  $this->CroppedYSize = $CroppedYSize;
290  $this->CroppedXOrigin = $CroppedXOrigin;
291  $this->CroppedYOrigin = $CroppedYOrigin;
292  }
293 
301  function Type($FileName = NULL)
302  {
303  if ($FileName == NULL) { $FileName = $this->SourceFileName; }
304  if (is_readable($FileName))
305  {
306  switch (exif_imagetype($FileName))
307  {
308  case IMAGETYPE_GIF: return self::IMGTYPE_GIF;
309  case IMAGETYPE_JPEG: return self::IMGTYPE_JPEG;
310  case IMAGETYPE_PNG: return self::IMGTYPE_PNG;
311  case IMAGETYPE_BMP: return self::IMGTYPE_BMP;
312  }
313  }
314  if (preg_match("/.*\\.jp[e]{0,1}g$/i", $FileName))
315  { return self::IMGTYPE_JPEG; }
316  elseif (preg_match("/.*\\.gif$/i", $FileName))
317  { return self::IMGTYPE_GIF; }
318  elseif (preg_match("/.*\\.bmp$/i", $FileName))
319  { return self::IMGTYPE_BMP; }
320  elseif (preg_match("/.*\\.png$/i", $FileName))
321  { return self::IMGTYPE_PNG; }
322  return self::IMGTYPE_UNKNOWN;
323  }
324 
330  public function Mimetype()
331  {
332  $MimeTypes = [
333  self::IMGTYPE_JPEG => "image/jpeg",
334  self::IMGTYPE_PNG => "image/png",
335  self::IMGTYPE_GIF => "image/gif",
336  self::IMGTYPE_BMP => "image/bmp",
337  ];
338 
339  if (isset($MimeTypes[$this->Type()]))
340  {
341  return $MimeTypes[$this->Type()];
342  }
343 
344  $Mimetype = FALSE;
345  $FilePath = $this->SourceFileName;
346 
347  if (strlen(trim($FilePath)))
348  {
349  if (function_exists("mime_content_type"))
350  {
351  $MimeType = mime_content_type($FilePath);
352  }
353  elseif (function_exists("finfo_open"))
354  {
355  $FInfoHandle = finfo_open(FILEINFO_MIME);
356  if ($FInfoHandle)
357  {
358  $Mimetype = finfo_file($FInfoHandle, $FilePath);
359  finfo_close($FInfoHandle);
360  }
361  }
362  }
363 
364  return $Mimetype;
365  }
366 
367  # return the file name extension for the image
368  function Extension()
369  {
370  return Image::$AxisImageFileExtensions[$this->Type()];
371  }
372 
379  static function ExtensionForType($Type)
380  {
381  if (isset(Image::$AxisImageFileExtensions[$Type]))
382  {
383  return Image::$AxisImageFileExtensions[$Type];
384  }
385  else
386  {
387  return NULL;
388  }
389  }
390 
391  # set/get the quality (0-100) for JPEG images created with SaveAs()
392  function JpegQuality($NewSetting = NULL)
393  {
394  if ($NewSetting != NULL) { $this->JpegSaveQuality = $NewSetting; }
395  return $this->JpegSaveQuality;
396  }
397 
398  # return supported image formats
399  static function SupportedFormats()
400  {
401  # start out assuming no formats are supported
402  $Supported = 0;
403 
404  # if JPEG is supported by PHP
405  if (defined("IMG_JPG") && (imagetypes() & IMG_JPG))
406  {
407  # add JPEG to list of supported formats
408  $Supported |= self::IMGTYPE_JPEG;
409  }
410 
411  # if GIF is supported by PHP
412  if (defined("IMG_GIF") && (imagetypes() & IMG_GIF))
413  {
414  # add GIF to list of supported formats
415  $Supported |= self::IMGTYPE_GIF;
416  }
417 
418  # if PNG is supported by PHP
419  if (defined("IMG_PNG") && (imagetypes() & IMG_PNG))
420  {
421  # add PNG to list of supported formats
422  $Supported |= self::IMGTYPE_PNG;
423  }
424 
425  # if BMP is supported by PHP
426  if (defined("IMG_BMP") && (imagetypes() & IMG_BMP))
427  {
428  # add BMP to list of supported formats
429  $Supported |= self::IMGTYPE_BMP;
430  }
431 
432  # report to caller what formats are supported
433  return $Supported;
434  }
435 
436  # return names (upper-case extensions) of supported image formats
437  static function SupportedFormatNames()
438  {
439  # assume that no formats are supported
440  $FormatNames = array();
441 
442  # retrieve supported formats
443  $SupportedFormats = Image::SupportedFormats();
444 
445  # for each possible supported format
446  foreach (Image::$AxisImageFileExtensions as $ImageType => $ImageExtension)
447  {
448  # if format is supported
449  if ($ImageType & $SupportedFormats)
450  {
451  # add format extension to list of supported image format names
452  $FormatNames[] = strtoupper($ImageExtension);
453  }
454  }
455 
456  # return supported image format names to caller
457  return $FormatNames;
458  }
459 
460  # return the error status set by the constructor or the last call to SaveAs()
461  function Status()
462  {
463  return $this->ErrorStatus;
464  }
465 
466  # return string containing external command that failed
468  {
469  return $this->FailedCommand;
470  }
471 
472 
473  # ---- PRIVATE INTERFACE -------------------------------------------------
474 
492 
493  # image file extensions
494  private static $AxisImageFileExtensions = array(
495  self::IMGTYPE_JPEG => "jpg",
496  self::IMGTYPE_GIF => "gif",
497  self::IMGTYPE_BMP => "bmp",
498  self::IMGTYPE_PNG => "png",
499  );
500 
501  function ReadSize()
502  {
503  # if we do not already have image info
504  if (!isset($this->ImageXSize))
505  {
506  # read size information from image object
507  $this->ImageXSize = imagesx($this->ImageObj);
508  $this->ImageYSize = imagesy($this->ImageObj);
509  }
510  }
511 
512  function ImageFormatSupportedByPhp($Format = NULL)
513  {
514  if ($Format == NULL) { $Format = $this->Type(); }
515 
516  if (!function_exists("imagetypes")) { return FALSE; }
517 
518  switch ($Format)
519  {
520  case self::IMGTYPE_JPEG:
521  return (imagetypes() & IMG_JPG) ? TRUE : FALSE;
522  break;
523 
524  case self::IMGTYPE_GIF:
525  return (imagetypes() & IMG_GIF) ? TRUE : FALSE;
526  break;
527 
528  case self::IMGTYPE_BMP:
529  if (defined("IMG_BMP"))
530  {
531  return (imagetypes() & IMG_BMP) ? TRUE : FALSE;
532  }
533  else
534  {
535  return FALSE;
536  }
537  break;
538 
539  case self::IMGTYPE_PNG:
540  return (imagetypes() & IMG_PNG) ? TRUE : FALSE;
541  break;
542 
543  default:
544  return FALSE;
545  break;
546  }
547  }
548 }
549 
550 # error status definitions
551 define("AI_OKAY", 0);
552 define("AI_FILEUNREADABLE", 1);
553 define("AI_IMGOBJCREATEFAILED", 2);
554 define("AI_PPMCMDFAILED", 4);
555 define("AI_INTERNALERROR", 8);
556 define("AI_UNKNOWNTYPE", 16);
557 define("AI_UNSUPPORTEDFORMAT", 32);
558 define("AI_DESTINATIONUNWRITABLE", 64);
559 
560 # supply imagetypes() function if not defined
561 if (!function_exists("imagetypes"))
562 {
563  # (returning 0 indicates no image types supported)
564  function imagetypes() { return 0; }
565 }
566 
static SupportedFormatNames()
Definition: Image.php:437
SaveAs($FileName, $NewImageType=NULL)
Definition: Image.php:112
$ImageObj
Definition: Image.php:476
ScaleTo($ScaledXSize, $ScaledYSize, $MaintainAspectRatio=FALSE)
Definition: Image.php:276
CropTo($CroppedXSize, $CroppedYSize, $CroppedXOrigin=0, $CroppedYOrigin=0)
Definition: Image.php:285
$GDVersion
Definition: Image.php:475
ReadSize()
Definition: Image.php:501
const AI_OKAY
Definition: Image.php:551
YSize()
Definition: Image.php:269
XSize()
Definition: Image.php:262
$CroppedYOrigin
Definition: Image.php:486
$DecodeCommand
Definition: Image.php:488
const IMGTYPE_GIF
Definition: Image.php:23
Extension()
Definition: Image.php:368
$CroppedXOrigin
Definition: Image.php:485
const AI_DESTINATIONUNWRITABLE
Definition: Image.php:558
$JpegSaveQuality
Definition: Image.php:487
$ScaledXSize
Definition: Image.php:480
JpegQuality($NewSetting=NULL)
Definition: Image.php:392
$ImageXSize
Definition: Image.php:478
static ExtensionForType($Type)
return the file name extension for the image, given a type.
Definition: Image.php:379
$ErrorStatus
Definition: Image.php:489
ImageFormatSupportedByPhp($Format=NULL)
Definition: Image.php:512
const IMGTYPE_UNKNOWN
Definition: Image.php:21
$MaintainAspectRatio
Definition: Image.php:482
$ScaledYSize
Definition: Image.php:481
$CroppedXSize
Definition: Image.php:483
const AI_FILEUNREADABLE
Definition: Image.php:552
const AI_IMGOBJCREATEFAILED
Definition: Image.php:553
const IMGTYPE_PNG
Definition: Image.php:25
Status()
Definition: Image.php:461
Mimetype()
Get the MIME type for the image.
Definition: Image.php:330
const IMGTYPE_JPEG
Definition: Image.php:22
Definition: Image.php:15
Type($FileName=NULL)
Get the image type.
Definition: Image.php:301
$DebugLevel
Definition: Image.php:491
__construct($SourceFileName, $DebugLevel=0)
Definition: Image.php:27
const IMGTYPE_BMP
Definition: Image.php:24
$ImageYSize
Definition: Image.php:479
static SupportedFormats()
Definition: Image.php:399
FailedExternalCommand()
Definition: Image.php:467
const AI_INTERNALERROR
Definition: Image.php:555
$FailedCommand
Definition: Image.php:490
$CroppedYSize
Definition: Image.php:484
$SourceFileName
Definition: Image.php:477
const AI_UNSUPPORTEDFORMAT
Definition: Image.php:557