CWIS Developer Documentation
SPTImage.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: SPTImage.php
4 #
5 # Part of the Collection Workflow Integration System (CWIS)
6 # Copyright 2002-2013 Edward Almasy and Internet Scout Research Group
7 # http://scout.wisc.edu/cwis/
8 #
9 
13 class SPTImage {
14 
15  # ---- PUBLIC INTERFACE --------------------------------------------------
16 
18  const IMAGE_PATH = "ImageStorage/";
20  const PREVIEW_PATH = "ImageStorage/Previews/";
22  const THUMBNAIL_PATH = "ImageStorage/Thumbnails/";
23 
36  function SPTImage($ImageIdOrFileNameOrImageObj,
37  $MaxWidth = NULL, $MaxHeight = NULL,
38  $MaxPreviewWidth = NULL, $MaxPreviewHeight = NULL,
39  $MaxThumbnailWidth = NULL, $MaxThumbnailHeight = NULL)
40  {
41  # clear error status (0 = AI_OKAY)
42  $this->ErrorStatus = 0;
43 
44  # trigger the Image class file to be autoloaded since some parts of this
45  # class (SPTImage) use constants defined in it but don't construct Image
46  # objects
47  new Image(NULL);
48 
49  # create and save a database handle for our use
50  $this->DB = new Database();
51 
52  # if image object was passed in
53  if (is_object($ImageIdOrFileNameOrImageObj)
54  && method_exists($ImageIdOrFileNameOrImageObj, "SPTImage"))
55  {
56  # create copy of image passed in
57  $this->CreateCopyOfImage($ImageIdOrFileNameOrImageObj);
58  }
59  # else if image ID was passed in
60  elseif (($ImageIdOrFileNameOrImageObj > 0)
61  && preg_match("/[0-9]+/", $ImageIdOrFileNameOrImageObj))
62  {
63  # load info on existing image
64  $this->LoadImageInfo($ImageIdOrFileNameOrImageObj);
65  }
66  # else assume that value passed in is file name
67  else
68  {
69  # create new image from named file
70  $this->CreateNewImage($ImageIdOrFileNameOrImageObj,
71  $MaxWidth, $MaxHeight,
72  $MaxPreviewWidth, $MaxPreviewHeight,
73  $MaxThumbnailWidth, $MaxThumbnailHeight);
74  }
75  }
76 
81  function Id() { return $this->Id; }
82 
87  function Url() { return $this->FileName; }
88 
93  function PreviewUrl() { return $this->PreviewFileName; }
94 
99  function ThumbnailUrl() { return $this->ThumbnailFileName; }
100 
106  function Format() { return $this->Format; }
107 
112  public function Mimetype()
113  {
114  $Image = new Image($this->FileName);
115  return $Image->Mimetype();
116  }
117 
122  function Height() { return $this->Height; }
123 
128  function Width() { return $this->Width; }
129 
134  function PreviewHeight() { return $this->PreviewHeight; }
135 
140  function PreviewWidth() { return $this->PreviewWidth; }
141 
146  function ThumbnailHeight() { return $this->ThumbnailHeight; }
147 
152  function ThumbnailWidth() { return $this->ThumbnailWidth; }
153 
158  static function ImageStorageDirectory()
159  {
160  # for each possible storage location
161  foreach (self::$ImageStorageLocations as $Dir)
162  {
163  # if location exists
164  if (is_dir($Dir))
165  {
166  # return location to caller
167  return $Dir;
168  }
169  }
170 
171  # return default (most preferred) location to caller
172  return self::$ImageStorageLocations[0];
173  }
174 
179  static function PreviewStorageDirectory()
180  {
181  # for each possible storage location
182  foreach (self::$PreviewStorageLocations as $Dir)
183  {
184  # if location exists
185  if (is_dir($Dir))
186  {
187  # return location to caller
188  return $Dir;
189  }
190  }
191 
192  # return default (most preferred) location to caller
193  return self::$PreviewStorageLocations[0];
194  }
195 
200  static function ThumbnailStorageDirectory()
201  {
202  # for each possible storage location
203  foreach (self::$ThumbnailStorageLocations as $Dir)
204  {
205  # if location exists
206  if (is_dir($Dir))
207  {
208  # return location to caller
209  return $Dir;
210  }
211  }
212 
213  # return default (most preferred) location to caller
214  return self::$ThumbnailStorageLocations[0];
215  }
216 
221  function GetLink() { return $this->FileName; }
222 
229  function AltText($NewValue = NULL)
230  {
231  # if new value supplied and new value differs from existing value
232  if (($NewValue !== NULL) && ($NewValue != $this->AltText))
233  {
234  # save new value to database
235  $this->DB->Query("UPDATE Images SET"
236  ." AltText = '".addslashes($NewValue)."'"
237  ." WHERE ImageId = ".$this->Id);
238 
239  # save new value locally
240  $this->AltText = $NewValue;
241  }
242 
243  # return attribute value to caller
244  return $this->AltText;
245  }
246 
251  function Delete()
252  {
253  # delete base image file
254  if (file_exists($this->FileName)) { unlink($this->FileName); }
255 
256  # delete preview image file
257  if (file_exists($this->PreviewFileName)) { unlink($this->PreviewFileName); }
258 
259  # delete thumbnail image file
260  if (file_exists($this->ThumbnailFileName)) { unlink($this->ThumbnailFileName); }
261 
262  # delete image info record in database
263  $this->DB->Query("DELETE FROM Images WHERE ImageId = ".$this->Id);
264  }
265 
270  function Status()
271  {
272  return $this->ErrorStatus;
273  }
274 
280  static function CheckDirectories()
281  {
282  # determine paths
283  $ImagePath = self::ImageStorageDirectory();
284  $PreviewPath = self::PreviewStorageDirectory();
285  $ThumbnailPath = self::ThumbnailStorageDirectory();
286 
287  # assume everything will be okay
288  $ErrorsFound = NULL;
289 
290  # check base image directory
291  if (!is_dir($ImagePath) || !is_writable($ImagePath))
292  {
293  if (!is_dir($ImagePath))
294  {
295  @mkdir($ImagePath, 0755);
296  }
297  else
298  {
299  @chmod($ImagePath, 0755);
300  }
301  if (!is_dir($ImagePath))
302  {
303  $ErrorsFound[] = "Image Storage Directory Not Found";
304  }
305  elseif (!is_writable($ImagePath))
306  {
307  $ErrorsFound[] = "Image Storage Directory Not Writable";
308  }
309  }
310 
311  # check preview directory
312  if (!is_dir($PreviewPath) || !is_writable($PreviewPath))
313  {
314  if (!is_dir($PreviewPath))
315  {
316  @mkdir($PreviewPath, 0755);
317  }
318  else
319  {
320  @chmod($PreviewPath, 0755);
321  }
322  if (!is_dir($PreviewPath))
323  {
324  $ErrorsFound[] = "Preview Storage Directory Not Found";
325  }
326  elseif (!is_writable($PreviewPath))
327  {
328  $ErrorsFound[] = "Preview Storage Directory Not Writable";
329  }
330  }
331 
332  # check thumbnail directory
333  if (!is_dir($ThumbnailPath) || !is_writable($ThumbnailPath))
334  {
335  if (!is_dir($ThumbnailPath))
336  {
337  @mkdir($ThumbnailPath, 0755);
338  }
339  else
340  {
341  @chmod($ThumbnailPath, 0755);
342  }
343  if (!is_dir($ThumbnailPath))
344  {
345  $ErrorsFound[] = "Thumbnail Storage Directory Not Found";
346  }
347  elseif (!is_writable($ThumbnailPath))
348  {
349  $ErrorsFound[] = "Thumbnail Storage Directory Not Writable";
350  }
351  }
352 
353  # return any errors found to caller
354  return $ErrorsFound;
355  }
356 
367  public function Resize($MaxWidth, $MaxHeight,
368  $MaxPreviewWidth, $MaxPreviewHeight,
369  $MaxThumbnailWidth, $MaxThumbnailHeight)
370  {
371  $SrcImage = new Image($this->FileName);
372 
373  # scale the original image if necessary
374  $MaxWidth = min($MaxWidth, $SrcImage->XSize());
375  $MaxHeight = min($MaxHeight, $SrcImage->YSize());
376  $SrcImage->ScaleTo($MaxWidth, $MaxHeight, TRUE);
377 
378  # save and reload image info
379  $SrcImage->SaveAs($this->FileName);
380  $SrcImage = new Image($this->FileName);
381 
382  # retrieve image width and height
383  $this->Height = $SrcImage->YSize();
384  $this->Width = $SrcImage->XSize();
385 
386  # generate preview image and calculate width and height
387  $MaxPreviewWidth = min($MaxPreviewWidth, $this->Width);
388  $MaxPreviewHeight = min($MaxPreviewHeight, $this->Height);
389  $SrcImage->ScaleTo($MaxPreviewWidth, $MaxPreviewHeight, TRUE);
390  $SrcImage->SaveAs($this->PreviewFileName, IMGTYPE_JPEG);
391  if (($this->Width * $MaxPreviewHeight)
392  > ($this->Height * $MaxPreviewWidth))
393  {
394  $this->PreviewWidth = $MaxPreviewWidth;
395  $this->PreviewHeight =
396  ($MaxPreviewWidth * $SrcImage->YSize()) / $SrcImage->XSize();
397  }
398  else
399  {
400  $this->PreviewWidth =
401  ($MaxPreviewHeight * $SrcImage->XSize()) / $SrcImage->YSize();
402  $this->PreviewHeight = $MaxPreviewHeight;
403  }
404 
405  # generate thumbnail image and calculate width and height
406  $MaxThumbnailWidth = min($MaxThumbnailWidth, $this->Width);
407  $MaxThumbnailHeight = min($MaxThumbnailHeight, $this->Height);
408  $SrcImage->ScaleTo($MaxThumbnailWidth, $MaxThumbnailHeight, TRUE);
409  $SrcImage->SaveAs($this->ThumbnailFileName, IMGTYPE_JPEG);
410  if (($this->Width * $MaxThumbnailHeight)
411  > ($this->Height * $MaxThumbnailWidth))
412  {
413  $this->ThumbnailWidth = $MaxThumbnailWidth;
414  $this->ThumbnailHeight =
415  ($MaxThumbnailWidth * $SrcImage->YSize()) / $SrcImage->XSize();
416  }
417  else
418  {
419  $this->ThumbnailWidth = ($MaxThumbnailHeight * $SrcImage->XSize()) / $SrcImage->YSize();
420  $this->ThumbnailHeight = $MaxThumbnailHeight;
421  }
422 
423  # save image attributes to database
424  $this->SaveImageInfo();
425  }
426 
427  # ---- PRIVATE INTERFACE -------------------------------------------------
428 
429  private $Id;
430  private $FileName;
431  private $PreviewFileName;
432  private $ThumbnailFileName;
433  private $Format;
434  private $AltText;
435  private $Url;
436  private $PreviewUrl;
437  private $ThumbnailUrl;
438  private $Height;
439  private $Width;
440  private $PreviewHeight;
441  private $PreviewWidth;
442  private $ThumbnailHeight;
443  private $ThumbnailWidth;
444  private $DB;
445  private $ErrorStatus;
446 
448  static private $ImageStorageLocations = array(
449  "local/data/images",
450  "ImageStorage",
451  );
452  static private $PreviewStorageLocations = array(
453  "local/data/images/previews",
454  "ImageStorage/Previews",
455  );
456  static private $ThumbnailStorageLocations = array(
457  "local/data/images/thumbnails",
458  "ImageStorage/Thumbnails",
459  );
460 
472  private function CreateNewImage($FileName, $MaxWidth, $MaxHeight,
473  $MaxPreviewWidth, $MaxPreviewHeight, $MaxThumbnailWidth, $MaxThumbnailHeight)
474  {
475  # if file does not exist or is not readable
476  if (!is_readable($FileName))
477  {
478  # set error status
479  $this->ErrorStatus = AI_FILEUNREADABLE;
480  }
481  else
482  {
483  # if image is invalid or unsupported type
484  $SrcImage = new Image($FileName);
485  if ($SrcImage->Status() != AI_OKAY)
486  {
487  # set error status
488  $this->ErrorStatus = $SrcImage->Status();
489  }
490  else
491  {
492  # retrieve image type
493  $this->Format = $SrcImage->Type();
494 
495  # generate new image ID
496  $this->Id = $this->GenerateNewImageId();
497 
498  # generate and set file names
499  $this->SetFileNames();
500 
501  # if our image file name differs from file name passed in
502  if (realpath($this->FileName) != realpath($FileName))
503  {
504  # create image file
505  $SrcImage->SaveAs($this->FileName);
506 
507  # if create failed set error status and bail out
508  if ($SrcImage->Status() != AI_OKAY)
509  {
510  $this->DB->Query("DELETE FROM Images WHERE ImageId = "
511  .intval($this->Id));
512  $this->ErrorStatus = $SrcImage->Status();
513  return;
514  }
515  }
516 
517  # scale the original image if necessary
518  $MaxWidth = min($MaxWidth, $SrcImage->XSize());
519  $MaxHeight = min($MaxHeight, $SrcImage->YSize());
520 
521  # change the minimum width if the height is the limiting factor
522  if ($SrcImage->YSize() * $MaxWidth / $SrcImage->XSize() > $MaxHeight)
523  {
524  $MaxWidth = round($SrcImage->XSize() * $MaxHeight / $SrcImage->YSize());
525  }
526 
527  # change the minimum height since the width is the limiting factor
528  else
529  {
530  $MaxHeight = round($SrcImage->YSize() * $MaxWidth / $SrcImage->XSize());
531  }
532 
533  # scale the image
534  $SrcImage->ScaleTo($MaxWidth, $MaxHeight, TRUE);
535 
536  # save and reload image info
537  $SrcImage->SaveAs($this->FileName);
538  $SrcImage = new Image($this->FileName);
539 
540  # retrieve image width and height
541  $this->Height = $SrcImage->YSize();
542  $this->Width = $SrcImage->XSize();
543 
544  # create the preview and thumbnail images
545  foreach (array("Preview", "Thumbnail") as $ImageType)
546  {
547  # variable name strings to use in the variable variables below
548  $MaxWidthVar = "Max".$ImageType."Width";
549  $MaxHeightVar = "Max".$ImageType."Height";
550 
551  # find the mininum values for the width and height
552  $$MaxWidthVar = min($$MaxWidthVar, $this->Width);
553  $$MaxHeightVar= min($$MaxHeightVar, $this->Height);
554 
555  # change the minimum width if the height is the limiting factor
556  if ($this->Height * $$MaxWidthVar / $this->Width > $$MaxHeightVar)
557  {
558  $$MaxWidthVar =
559  round($this->Width * $$MaxHeightVar / $this->Height);
560  }
561 
562  # change the minimum height since the width is the limiting factor
563  else
564  {
565  $$MaxHeightVar =
566  round($this->Height * $$MaxWidthVar / $this->Width);
567  }
568 
569  # scale the image and save it to a new file
570  $SrcImage->ScaleTo($$MaxWidthVar, $$MaxHeightVar, TRUE);
571  $SrcImage->SaveAs($this->{$ImageType."FileName"}, IMGTYPE_JPEG);
572 
573  # scaling/saving failed
574  if ($SrcImage->Status() != AI_OKAY)
575  {
576  $this->DB->Query("DELETE FROM Images WHERE ImageId = "
577  .intval($this->Id));
578  $this->ErrorStatus = $SrcImage->Status();
579  return;
580  }
581 
582  # save the dimensions
583  $this->{$ImageType."Width"} = $$MaxWidthVar;
584  $this->{$ImageType."Height"} = $$MaxHeightVar;
585  }
586 
587  # save image attributes to database
588  $this->SaveImageInfo();
589  }
590  }
591  }
592 
597  private function LoadImageInfo($ImageId)
598  {
599  # save image ID
600  $this->Id = $ImageId;
601 
602  # load image record from database
603  $this->DB->Query("SELECT * FROM Images WHERE ImageId = ".$ImageId);
604 
605  # if the ID is invalid
606  if (!$this->DB->NumRowsSelected())
607  {
608  $this->ErrorStatus = AI_INTERNALERROR;
609  return;
610  }
611 
612  $Record = $this->DB->FetchRow();
613 
614  # load in values from record
615  $this->Format = $Record["Format"];
616  $this->AltText = $Record["AltText"];
617  $this->Height = $Record["Height"];
618  $this->Width = $Record["Width"];
619  $this->PreviewHeight = $Record["PreviewHeight"];
620  $this->PreviewWidth = $Record["PreviewWidth"];
621  $this->ThumbnailHeight = $Record["ThumbnailHeight"];
622  $this->ThumbnailWidth = $Record["ThumbnailWidth"];
623 
624  # generate file names
625  $this->SetFileNames();
626  }
627 
632  private function CreateCopyOfImage($SrcImage)
633  {
634  $Image = new Image($SrcImage->Url());
635  if ($Image->Status() != AI_OKAY)
636  {
637  # set error status
638  $this->ErrorStatus = $Image->Status();
639  return;
640  }
641 
642  # generate new image ID
643  $this->Id = $this->GenerateNewImageId();
644 
645  # generate file names
646  $this->SetFileNames();
647 
648  # copy attributes from source image
649  $this->Format = $SrcImage->Format();
650  $this->AltText = $SrcImage->AltText();
651  $this->Width = $SrcImage->Width();
652  $this->Height = $SrcImage->Height();
653  $this->PreviewWidth = $SrcImage->PreviewWidth();
654  $this->PreviewHeight = $SrcImage->PreviewHeight();
655  $this->ThumbnailWidth = $SrcImage->ThumbnailWidth();
656  $this->ThumbnailHeight = $SrcImage->ThumbnailHeight();
657 
658  # copy source image files
659  copy($SrcImage->Url(), $this->FileName);
660  copy($SrcImage->PreviewUrl(), $this->PreviewFileName);
661  copy($SrcImage->ThumbnailUrl(), $this->ThumbnailFileName);
662 
663  # save image attributes to database
664  $this->SaveImageInfo();
665  }
666 
671  private function SetFileNames()
672  {
673  if (Image::Extension($this->Format))
674  {
675  $FileExtension = Image::Extension($this->Format);
676  }
677  else
678  {
679  $FileExtension = "";
680  }
681 
682  $this->FileName = $this->DetermineFileName(
683  self::$ImageStorageLocations, "Img--", $FileExtension);
684  $this->PreviewFileName = $this->DetermineFileName(
685  self::$PreviewStorageLocations, "Preview--", $FileExtension);
686  $this->ThumbnailFileName = $this->DetermineFileName(
687  self::$ThumbnailStorageLocations, "Thumb--", $FileExtension);
688  }
689 
699  private function DetermineFileName($Locations, $Prefix, $Extension)
700  {
701  # build base name for file
702  $BaseName = $Prefix.sprintf("%08d.", $this->Id).$Extension;
703 
704  # for each possible location
705  foreach ($Locations as $Dir)
706  {
707  # build full file name for location
708  $FileName = $Dir."/".$BaseName;
709 
710  # if file exists in location return full file name
711  if (file_exists($FileName)) { return $FileName; }
712  }
713 
714  # for each possible location
715  foreach ($Locations as $Dir)
716  {
717  # build full file name for location
718  $FileName = $Dir."/".$BaseName;
719 
720  # if location is writable return full file name
721  if (is_dir($Dir) && is_writable($Dir)) { return $FileName; }
722  }
723 
724  # return full file name for default location
725  return $Locations[0]."/".$BaseName;
726  }
727 
732  private function GenerateNewImageId()
733  {
734  # add new entry to database
735  $this->DB->Query("INSERT INTO Images (AltText) VALUES ('')");
736 
737  # return ID of inserted image
738  return $this->DB->LastInsertId();
739  }
740 
744  private function SaveImageInfo()
745  {
746  # update existing image record
747  $this->DB->Query("UPDATE Images SET"
748  ." Format = '" .$this->Format."',"
749  ." AltText = '" .addslashes($this->AltText)."',"
750  ." Height = '" .$this->Height."',"
751  ." Width = '" .$this->Width."',"
752  ." PreviewHeight = '" .$this->PreviewHeight."',"
753  ." PreviewWidth = '" .$this->PreviewWidth."',"
754  ." ThumbnailHeight = '".$this->ThumbnailHeight."',"
755  ." ThumbnailWidth = '" .$this->ThumbnailWidth."'"
756  ." WHERE ImageId = ".$this->Id);
757  }
758 
759 }
Mimetype()
Get the MIME type for the image.
Definition: SPTImage.php:112
ThumbnailWidth()
Get the width of the thumbnail image for this image.
Definition: SPTImage.php:152
const IMGTYPE_JPEG
SPTImage($ImageIdOrFileNameOrImageObj, $MaxWidth=NULL, $MaxHeight=NULL, $MaxPreviewWidth=NULL, $MaxPreviewHeight=NULL, $MaxThumbnailWidth=NULL, $MaxThumbnailHeight=NULL)
Object constructor.
Definition: SPTImage.php:36
SQL database abstraction object with smart query caching.
Delete()
Delete the image, that is, remove its record from the database and delete the associated image files ...
Definition: SPTImage.php:251
PreviewHeight()
Get the height of the preview image for this image.
Definition: SPTImage.php:134
const THUMBNAIL_PATH
path where thumbnail images are stored
Definition: SPTImage.php:22
const AI_FILEUNREADABLE
PreviewWidth()
Get the width of the preview image for this image.
Definition: SPTImage.php:140
Status()
Get the error status set by the constructor.
Definition: SPTImage.php:270
const AI_INTERNALERROR
PHP
Definition: OAIClient.php:39
static CheckDirectories()
Check that the image storage directories are available, creating them and attempting to change their ...
Definition: SPTImage.php:280
ThumbnailHeight()
Get the height of the thumbnail image for this image.
Definition: SPTImage.php:146
Width()
Get the width of the image.
Definition: SPTImage.php:128
Encapsulates a full-size, preview, and thumbnail image.
Definition: SPTImage.php:13
Url()
Get the path to the image.
Definition: SPTImage.php:87
static PreviewStorageDirectory()
Get the path to the preview image storage directory.
Definition: SPTImage.php:179
PreviewUrl()
Get the path to the preview image for this image.
Definition: SPTImage.php:93
Format()
Get the format of the image.
Definition: SPTImage.php:106
const PREVIEW_PATH
path where preview images are stored
Definition: SPTImage.php:20
GetLink()
Get the path to the full-size image.
Definition: SPTImage.php:221
Id()
Get the ID of the image in the database.
Definition: SPTImage.php:81
const AI_OKAY
Height()
Get the height of the image.
Definition: SPTImage.php:122
Resize($MaxWidth, $MaxHeight, $MaxPreviewWidth, $MaxPreviewHeight, $MaxThumbnailWidth, $MaxThumbnailHeight)
Resize the full-size, preview, and thumbnail images based on the given dimension restrictions.
Definition: SPTImage.php:367
AltText($NewValue=NULL)
Get or set the alternate text value for the image.
Definition: SPTImage.php:229
const IMAGE_PATH
base path where images are stored
Definition: SPTImage.php:18
static ThumbnailStorageDirectory()
Get the path to the thumbnail image storage directory.
Definition: SPTImage.php:200
static ImageStorageDirectory()
Get the path to the (full-size) image storage directory.
Definition: SPTImage.php:158
ThumbnailUrl()
Get the path to the thumbnail image for this image.
Definition: SPTImage.php:99
static Extension($Type=NULL)