180, 6=>90, 8=>-90, ]; public function software() { return $this->belongsTo(Software::class); } public function getIDLinkAttribute() { return $this->HTMLLinkAttribute($this->id,url('p/info').'/'); } /** * Date the photo was taken */ public function date_taken(): string { return $this->date_created ? ($this->date_created->format('Y-m-d H:i:s').($this->subsectime ? '.'.$this->subsectime : '')) : 'UNKNOWN'; } /** * Determine the new name for the image * @todo Implement in Parent */ public function file_path($short=FALSE,$new=FALSE) { $file = $this->filename; if ($new) $file = sprintf('%s.%s',((is_null($this->date_created) OR ! $this->date_created) ? sprintf('UNKNOWN/%07s',$this->file_path_id()) : sprintf('%s_%03s',$this->date_created->format('Y/m/d-His'),$this->subsectime). ($this->subsectime ? '' : sprintf('-%05s',$this->id))),$this->type()); return (($short OR preg_match('/^\//',$file)) ? '' : config('photo.dir').DIRECTORY_SEPARATOR).$file; } public function getHtmlImageURL(): string { return sprintf('',url('p/thumbnail',$this->id)); } /** * Return the image, rotated, minus exif data */ public function image() { if (is_null($imo = $this->o())) return NULL; if (array_key_exists('exif',$imo->getImageProfiles())) $imo->removeImageProfile('exif'); return $this->rotate($imo); } /** * Calculate the GPS coordinates */ public static function latlon(array $coordinate,$hemisphere) { if (! $coordinate OR ! $hemisphere) return NULL; for ($i=0; $i<3; $i++) { $part = explode('/', $coordinate[$i]); if (count($part) == 1) $coordinate[$i] = $part[0]; elseif (count($part) == 2) $coordinate[$i] = floatval($part[0])/floatval($part[1]); else $coordinate[$i] = 0; } list($degrees,$minutes,$seconds) = $coordinate; $sign = ($hemisphere == 'W' || $hemisphere == 'S') ? -1 : 1; return round($sign*($degrees+$minutes/60+$seconds/3600),($degrees>100 ? 3 : 4)); } /** * Return an Imagick object or attribute */ protected function o($attr=NULL) { if (! file_exists($this->file_path()) OR ! is_readable($this->file_path())) return NULL; if (is_null($this->_o)) $this->_o = new \Imagick($this->file_path()); return is_null($attr) ? $this->_o : $this->_o->getImageProperty($attr); } /** * Display the orientation of a photo */ public function orientation() { switch ($this->orientation) { case 1: return 'None!'; case 3: return 'Upside Down'; case 6: return 'Rotate Right'; case 8: return 'Rotate Left'; default: return 'unknown?'; } } /** * Rotate the image */ private function rotate(\Imagick $imo) { if (array_key_exists($this->orientation,$this->_rotate)) $imo->rotateImage(new \ImagickPixel('none'),$this->_rotate[$this->orientation]); return $imo->getImageBlob(); } public function property(string $property) { if (! $this->o()) return NULL; switch ($property) { case 'creationdate': if ($this->property('exif:DateTimeOriginal') == '0000:00:00 00:00:00' && $this->property('exif:DateTimeOriginal') == '0000:00:00 00:00:00') return NULL; return strtotime( $this->property('exif:DateTimeOriginal') && $this->property('exif:DateTimeOriginal') != '0000:00:00 00:00:00' ? $this->property('exif:DateTimeOriginal') : $this->property('exif:DateTime')); break; case 'height': return $this->_o->getImageHeight(); case 'orientation': return $this->_o->getImageOrientation(); case 'signature': return $this->_o->getImageSignature(); case 'width': return $this->_o->getImageWidth(); default: return $this->_o->getImageProperty($property); } } public function properties() { return $this->o() ? $this->_o->getImageProperties() : []; } public function setDateCreated() { $this->date_created = $this->property('creationdate'); } public function setLocation() { $this->gps_lat = static::latlon(preg_split('/,\s?/',$this->property('exif:GPSLatitude')),$this->property('exif:GPSLatitudeRef')); $this->gps_lon = static::latlon(preg_split('/,\s?/',$this->property('exif:GPSLongitude')),$this->property('exif:GPSLongitudeRef')); } // @todo Now set software_id public function setMakeModel() { $this->make = $this->property('exif:Make') ? $this->property('exif:Make') : NULL; $this->model = $this->property('exif:Model') ? $this->property('exif:Model') : NULL; $this->software = $this->property('exif:Software') ? $this->property('exif:Software') : NULL; } public function setSignature() { $this->signature = $this->property('signature'); $this->file_signature = md5_file($this->file_path()); } public function setSubSecTime() { $this->subsectime = $this->property('exif:SubSecTimeOriginal'); // In case of an error. if ($this->subsectime > 32767) $this->subsectime = 32767; } public function setThumbnail() { try { $this->thumbnail = exif_thumbnail($this->file_path()); } catch (\Exception $e) { // @todo Couldnt get the thumbnail, so we should create one. Log::info(sprintf('Unable to create thumbnail for %s (%s)',$this->id,$e->getMessage())); } if ($this->thumbnail === FALSE) $this->thumbnail = NULL; } /** * Return the image's thumbnail */ public function thumbnail($rotate=TRUE) { if (! $this->thumbnail) { return $this->o()->thumbnailimage(200,200,true,true) ? $this->_o->getImageBlob() : NULL; } if (! $rotate OR ! array_key_exists($this->orientation,$this->_rotate) OR ! extension_loaded('imagick')) return $this->thumbnail; $imo = new \Imagick(); $imo->readImageBlob($this->thumbnail); return $this->rotate($imo); } /** * Return the extension of the image * @todo mime-by-ext? */ public function type($mime=FALSE) { return strtolower($mime ? 'image/jpeg' : pathinfo($this->filename,PATHINFO_EXTENSION)); } }