| Current Path : /home/megadansyp/www/components/com_eventgallery/library/common/ |
| Current File : /home/megadansyp/www/components/com_eventgallery/library/common/imageprocessor.php |
<?php
/**
* @package Sven.Bluege
* @subpackage com_eventgallery
*
* @copyright Copyright (C) 2005 - 2019 Sven Bluege All rights reserved.
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
// Check to ensure this file is included in Joomla!
use lsolesen\pel\Pel;
use lsolesen\pel\PelDataWindow;
use lsolesen\pel\PelException;
use lsolesen\pel\PelExif;
use lsolesen\pel\PelJpeg;
use lsolesen\pel\PelTag;
defined('_JEXEC') or die();
/**
* provides the ability to create thumbnails of an image file
*
* Class EventgalleryLibraryCommonImageprocessor
*/
class EventgalleryLibraryCommonImageprocessor
{
private static $jpeg_orientation_translation = Array(
0 => 0,
1 => 0,
2 => 0,
3 => 180,
4 => 0,
5 => 0,
6 => -90,
7 => 0,
8 => 90
);
/**
* @var PelJpeg
*/
private $input_jpeg;
/**
* @var PelExif
*/
private $exif;
private $im_original;
private $im_thumbnail;
private $width;
private $height;
private $orig_width;
private $orig_height;
private $orig_ratio;
/**
* loads the image data from the given image file
*
* @param $filename
*/
public function loadImage($filename) {
$ext = pathinfo($filename, PATHINFO_EXTENSION);
if (!file_exists($filename)) {
throw new Exception(JText::_("COM_EVENTGALLERY_EVENT_FILE_NOT_FOUND"), 404);
}
if (strtolower($ext) == "gif") {
if (!$im_original = imagecreatefromgif($filename)) {
throw new Exception(JText::_("COM_EVENTGALLERY_EVENT_FILE_NOT_FOUND"), 404);
}
} else if(strtolower($ext) == "jpg" || strtolower($ext) == "jpeg") {
// try to use PEL first. If things fail, use the php internal method to get the JPEG
try {
$this->input_jpeg = new PelJpeg($filename);
/* Retrieve the original Exif data in $jpeg (if any). */
$this->exif = $this->input_jpeg->getExif();
/* The input image is already loaded, so we can reuse the bytes stored
* in $input_jpeg when creating the Image resource. */
if (!$im_original = imagecreatefromstring($this->input_jpeg->getBytes())) {
throw new Exception(JText::_("COM_EVENTGALLERY_EVENT_FILE_NOT_FOUND"), 404);
}
} catch (Exception $e){
if (!$im_original = imagecreatefromjpeg($filename)) {
throw new Exception(JText::_("COM_EVENTGALLERY_EVENT_FILE_NOT_FOUND"), 404);
}
}
} else if(strtolower($ext) == "png") {
if (!$im_original = imagecreatefrompng($filename)) {
throw new Exception(JText::_("COM_EVENTGALLERY_EVENT_FILE_NOT_FOUND"), 404);
}
} else {
throw new EventgalleryLibraryExceptionUnsupportedfileextensionexception(JText::_("COM_EVENTGALLERY_EVENT_FILEEXTENSION_NOT_SUPPORTED"));
}
$this->im_original = $im_original;
$this->orig_width = imagesx($this->im_original);
$this->orig_height = imagesy($this->im_original);
$this->orig_ratio = $this->orig_width / $this->orig_height;
}
/**
* initializes the size calculation
* throws an exception if the image was not loaded before.
*
* @param int $width
* @param int $height
* @throws Exception
*/
public function setTargetImageSize($width = -1, $height = -1, $doFindMatingSize = true) {
if ($this->im_original == null) {
throw new Exception('Can\'t set the target image size. The image needs to be loaded first');
}
if ($height > $width) {
$width = $height;
}
$sizeCalc = new EventgalleryHelpersSizecalculator($this->orig_width, $this->orig_height, (int)$width, $doFindMatingSize);
$this->height = $sizeCalc->getHeight();
$this->width = $sizeCalc->getWidth();
//adjust height to not enlarge images
if ($this->width > $this->orig_width) {
$this->width = $this->orig_width;
}
if ($this->height > $this->orig_height) {
$this->height = $this->orig_height;
}
$canvasWidth = $this->width;
$canvasHeight = ceil($this->width / $this->orig_ratio);
if ($canvasHeight > $this->height) {
$canvasHeight = $this->height;
$canvasWidth = ceil($this->height * $this->orig_ratio);
}
$this->width = $canvasWidth;
$this->height = $canvasHeight;
}
/**
* Performs the image transformations
* - resizing
* - rotation
* - sharping
* - watermarking
*
* @param $doAutorotate
* @param $doWatermarking
* @param $watermark
* @param $doSharping
* @param $doSharpingForOriginalImage
* @param $sharpenMatrix
*/
public function processImage($doAutorotate, $doWatermarking, $watermark, $doSharping, $doSharpingForOriginalImage, $sharpenMatrix)
{
$this->resize();
if ($doAutorotate == true) {
$this->doAutoRotate();
}
// do sharpen the image if it's allowed and we're not dealing with an original sized image where we don't allow sharping.
if ($doSharping && !($this->isOriginalSize() && !$doSharpingForOriginalImage)) {
$this->addSharpening($sharpenMatrix);
}
if ($doWatermarking) {
$this->addWatermark($watermark);
}
}
/**
* adds a watermark to the current image
*
* @param $watermark EventgalleryLibraryWatermark
*/
private function addWatermark($watermark) {
if (null != $watermark && $watermark->isPublished()) {
$watermark->addWatermark($this->im_thumbnail);
}
}
/**
* Applies the sharpening matrix to the image
*
* @param String $sharpeningMatrix a JSON string containing the 3x3 matrix
*/
private function addSharpening($sharpeningMatrix) {
// configure the sharpening
$stringSharpenMatrix = $sharpeningMatrix;
$sharpenMatrix = json_decode($stringSharpenMatrix);
if (null == $sharpenMatrix || count($sharpenMatrix)!=3) {
$sharpenMatrix = array(
array(-1,-1,-1),
array(-1,16,-1),
array(-1,-1,-1)
);
}
$divisor = array_sum(array_map('array_sum', $sharpenMatrix));
$offset = 0;
if (function_exists('imageconvolution'))
{
imageconvolution($this->im_thumbnail, $sharpenMatrix, $divisor, $offset);
}
}
/**
* performs the auto rotation of an image based in the exif orientation data.
*
* @throws PelException
*/
private function doAutoRotate() {
if ($this->exif == null) {
return;
}
$tiff = $this->exif->getTiff();
$ifd0 = $tiff->getIfd();
$orientation = $ifd0->getEntry(PelTag::ORIENTATION);
if ($orientation != null) {
$degree = self::$jpeg_orientation_translation[$orientation->getValue()];
if ($degree !== 0) {
$this->im_thumbnail = imagerotate($this->im_thumbnail, $degree, 0);
$orientation->setValue(1);
}
}
}
/**
* performs the resizing of the original image and creates the thumbnail image.
*/
private function resize() {
if ($this->isOriginalSize()) {
$this->im_thumbnail = $this->im_original;
return;
}
$im_output = imagecreatetruecolor($this->width, $this->height);
// set background to white
$white = imagecolorallocate($im_output, 255, 255, 255);
imagefill($im_output, 0, 0, $white);
$resize_faktor = $this->orig_height / $this->height;
$new_height = $this->height;
$new_width = $this->orig_width / $resize_faktor;
if ($new_width < $this->width) {
$resize_faktor = $this->orig_width / $this->width;
$new_width = $this->width;
$new_height = $this->orig_height / $resize_faktor;
}
imagecopyresampled($im_output, $this->im_original,
(int)(($this->width/2)-($new_width/2)),
(int)(($this->height/2)-($new_height/2)),
0,0,
(int)$new_width, (int)$new_height,$this->orig_width,$this->orig_height);
$this->im_thumbnail = $im_output;
}
/**
* saves a thumbnail as JPEG file to the disk
*
* @param string $filename
* @param int $image_quality the jpeg quality setting (0-100)
*/
public function saveThumbnail($filename, $image_quality) {
$dir = dirname($filename);
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
}
$config = \Joomla\Component\Eventgallery\Site\Library\Configuration\Main::getInstance();
if ($config->getImage()->doUsePrecalculatedThumbnailsForLocalFiles()) {
EventgalleryLibraryCommonSecurity::unprotectFolder(COM_EVENTGALLERY_IMAGE_CACHE_PATH);
} else {
EventgalleryLibraryCommonSecurity::protectFolder(COM_EVENTGALLERY_IMAGE_CACHE_PATH);
}
if ($this->input_jpeg != null) {
Pel::setJPEGQuality($image_quality);
/* We want the raw JPEG data from $scaled. Luckily, one can create a
* PelJpeg object from an image resource directly: */
/** @noinspection PhpParamsInspection */
$output_jpeg = new PelJpeg($this->im_thumbnail);
/* If no Exif data was present, then $exif is null. */
if ($this->exif != null) {
$empty_image = imagecreate(1, 1);
$d = new PelDataWindow($empty_image);
$idf = $this->exif->getTiff()->getIfd();
do {
if (strlen($idf->getThumbnailData()) > 0) {
$idf->setThumbnail($d);
}
$idf = $idf->getNextIfd();
} while($idf != null);
$output_jpeg->setExif($this->exif);
unset($empty_image);
unset($d);
}
/* We can now save the scaled image. */
$writeSuccess = true;
$output_jpeg->saveFile($filename);
} else {
$writeSuccess = imagejpeg($this->im_thumbnail, $filename, $image_quality);
}
if (!$writeSuccess) {
throw new Exception(JText::_("COM_EVENTGALLERY_EVENT_CACHEFILE_NOT_FOUND"));
}
}
/**
* copys the ICC profile of the source file to the target file.
*
* @param $sourceFileName
* @param $targetFileName
*/
public function copyICCProfile($sourceFileName, $targetFileName) {
// add the ICC profile
try {
$o = new JPEG_ICC();
$o->LoadFromJPEG($sourceFileName);
$o->SaveToJPEG($targetFileName);
} catch (Exception $e) {
}
}
/**
* checks if the desired thumbnail size equals the original image size
*
* @return bool
*/
private function isOriginalSize() {
$isOriginalSize = false;
if ($this->height == $this->orig_height && $this->width == $this->orig_width) {
$isOriginalSize = true;
}
return $isOriginalSize;
}
/**
* removes possible harmful 'directory' characters like /\. in a string.
*
* @param $value
* @return String
*/
private static function cleanValue($value) {
$value = str_replace("\.\.", "", $value);
$value = str_replace("/", "", $value);
$value = str_replace("\\", "", $value);
return $value;
}
public static function calculateCacheThumbnailName($width, $doFindMatingSize, $filename, $foldername, $isMainImage) {
$file = self::cleanValue($filename);
$folder = self::cleanValue($foldername);
$width = self::cleanValue((int)$width);
$isMainImage = self::cleanValue((boolean)$isMainImage);
$sizeSet = new EventgalleryHelpersSizeset();
if ($doFindMatingSize) {
$saveAsSize = $sizeSet->getMatchingSize($width);
} else {
$saveAsSize = $width;
}
$cachebasedir = COM_EVENTGALLERY_IMAGE_CACHE_PATH;
$cachedir_thumbs = $cachebasedir . $folder;
/**
* nocrop is only for legacy reasons! Same goes for the whole path. The path without underscores is outdated.
*
*/
$image_thumb_file = $cachedir_thumbs . DIRECTORY_SEPARATOR . ($isMainImage ? 'mainimage_':'') . 'nocrop' . $saveAsSize . $file;
if (file_exists($image_thumb_file)) {
return $image_thumb_file;
}
// the new path format.
$image_thumb_file = $cachedir_thumbs . DIRECTORY_SEPARATOR . ($isMainImage ? 'mainimage_':'') . 'nocrop_' . $saveAsSize . '_' . $file;
return $image_thumb_file;
}
/**
* This method calculates the image
*
* @param $folder
* @param $file
* @param $width
* @param $doFindMatingSize defined if we try to find a size in the list of possible images sized
* @param $doWatermarking
* @param $watermark EventgalleryLibraryWatermark
* @param $doSharping
* @param $forceThumbnailCreation
*
* @return string the name of the thumbnail file.
*
*/
public static function createThumbnail($folder, $file, $width = -1, $doFindMatingSize = true, $doWatermarking = true, $watermark = null, $doSharping = true, $forceThumbnailCreation = false)
{
$config = \Joomla\Component\Eventgallery\Site\Library\Configuration\Main::getInstance();
/**
* @var EventgalleryLibraryFactoryFile $fileFactory
*/
$fileFactory = EventgalleryLibraryFactoryFile::getInstance();
$fileObject = $fileFactory->getFile($folder, $file);
$image_thumb_file = EventgalleryLibraryCommonImageprocessor::calculateCacheThumbnailName($width, $doFindMatingSize, $file, $folder, $fileObject->isMainImage());
if ($forceThumbnailCreation || !file_exists($image_thumb_file)) {
if ($watermark == null) {
$folderObject = $fileObject->getFolder();
$watermark = $folderObject->getWatermark();
if ($fileObject->isMainImage()) {
$doWatermarking = $doWatermarking && $config->getImage()->doUseWatermarkForMainImages();
}
// load default watermark
if (null == $watermark || !$watermark->isPublished()) {
/**
* @var EventgalleryLibraryFactoryWatermark $watermarkFactory
* @var EventgalleryLibraryWatermark $watermark
*/
$watermarkFactory = EventgalleryLibraryFactoryWatermark::getInstance();
$watermark = $watermarkFactory->getDefaultWatermark();
}
}
$image_file = COM_EVENTGALLERY_IMAGE_FOLDER_PATH . $folder . DIRECTORY_SEPARATOR . $file;
$imageProcessor = new EventgalleryLibraryCommonImageprocessor();
$imageProcessor->loadImage($image_file);
$imageProcessor->setTargetImageSize($width, -1, $doFindMatingSize);
$imageProcessor->processImage(
$config->getImage()->doAutoRotate(),
$doWatermarking,
$watermark,
$doSharping && $config->getImage()->doUseSharpening(),
$config->getImage()->doUseSharpeningForOriginalSizes(),
$config->getImage()->getImageSharpenMatrix()
);
$imageProcessor->saveThumbnail($image_thumb_file, $config->getImage()->getImageQuality());
$imageProcessor->copyICCProfile($image_file, $image_thumb_file);
Pel::clearExceptions();
}
gc_collect_cycles();
return $image_thumb_file;
}
/**
* This method calculates the image and delivers it to the client.
*
* @param $folder
* @param $file
* @param $width
* @param $doFindMatingSize defined if we try to find a size in the list of possible images sized
* @param $doCache
* @param $doWatermarking
* @param $watermark EventgalleryLibraryWatermark
* @param $doSharping
*
*/
public static function renderThumbnail($folder, $file, $width = -1, $doFindMatingSize = true, $doCache = true, $doWatermarking = true, $watermark = null, $doSharping = true) {
$image_thumb_file = self::createThumbnail($folder, $file, $width, $doFindMatingSize, $doWatermarking, $watermark, $doSharping);
$last_modified = gmdate('D, d M Y H:i:s T', filemtime ($image_thumb_file));
$mime = ($mime = getimagesize($image_thumb_file)) ? $mime['mime'] : $mime;
$size = filesize($image_thumb_file);
$fp = fopen($image_thumb_file, "rb");
if (!($mime && $size && $fp)) {
throw new Exception(COM_EVENTGALLERY_EVENT_CACHEFILE_NOT_FOUND);
}
header("Content-Type: " . $mime);
header("Content-Length: " . $size);
header("Last-Modified: $last_modified");
header("Cache-Control: public, max-age=86400");
fpassthru($fp);
fclose($fp);
if (!$doCache) {
unlink($image_thumb_file);
}
}
}