* @copyright Copyright (c) 2018-2020 Matias De lellis * * @author Branko Kokanovic * * @license GNU AGPL version 3 or any later version * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . * */ namespace OCA\FaceRecognition\Helper; use OCP\Image; use OCP\ITempManager; use OCA\FaceRecognition\Helper\Imaginary; class TempImage extends Image { /** @var Imaginary */ private $imaginary; /** @var string */ private $imagePath; /** @var string */ private $tempPath; /** @var string */ private $preferredMimeType; /** @var int */ private $maxImageArea; /** @var ITempManager */ private $tempManager; /** @var int */ private $minImageSide; /** @var float */ private $ratio = -1.0; /** @var bool */ private $skipped = false; public function __construct(string $imagePath, string $preferredMimeType, int $maxImageArea, int $minImageSide) { parent::__construct(); $this->imagePath = $imagePath; $this->preferredMimeType = $preferredMimeType; $this->maxImageArea = $maxImageArea; $this->minImageSide = $minImageSide; $this->tempManager = \OC::$server->getTempManager(); $this->imaginary = new Imaginary(); $this->prepareImage(); } /** * Get the path of temporary image * * @return string */ public function getTempPath(): string { return $this->tempPath; } /** * Obtain the ratio of the temporary image against the original * * @return float */ public function getRatio(): float { return $this->ratio; } /** Return if image was skipped * * @return bool */ public function getSkipped(): bool { return $this->skipped; } /** * Clean temporary files */ public function clean() { $this->tempManager->clean(); } /** * Obtain a temporary image according to the imposed restrictions. * */ private function prepareImage() { if ($this->imaginary->isEnabled()) { $fileInfo = $this->imaginary->getInfo($this->imagePath); $widthOrig = $fileInfo['width']; $heightOrig = $fileInfo['height']; if (($widthOrig < $this->minImageSide) || ($heightOrig < $this->minImageSide)) { $this->skipped = true; return; } $scaleFactor = $this->getResizeRatio($widthOrig, $heightOrig); $newWidth = intval(round($widthOrig * $scaleFactor)); $newHeight = intval(round($heightOrig * $scaleFactor)); $resizedResource = $this->imaginary->getResized($this->imagePath, $newWidth, $newHeight, $fileInfo['autorotate'], $this->preferredMimeType); $this->loadFromData($resizedResource); if (!$this->valid()) { throw new \RuntimeException("Imaginary image response is not valid."); } $this->ratio = 1 / $scaleFactor; } else { $this->loadFromFile($this->imagePath); $this->fixOrientation(); if (!$this->valid()) { throw new \RuntimeException("Local image is not valid, probably cannot be loaded"); } if ((imagesx($this->resource()) < $this->minImageSide) || (imagesy($this->resource()) < $this->minImageSide)) { $this->skipped = true; return; } $this->ratio = $this->resizeOCImage(); } $this->tempPath = $this->tempManager->getTemporaryFile(); $this->save($this->tempPath, $this->preferredMimeType); } /** * Resizes the image to reach max image area, but preserving ratio. * * @return float Ratio of resize. 1 if there was no resize */ private function resizeOCImage(): float { $widthOrig = imagesx($this->resource()); $heightOrig = imagesy($this->resource()); if (($widthOrig <= 0) || ($heightOrig <= 0)) { $message = "Image is having non-positive width or height, cannot continue"; throw new \RuntimeException($message); } $scaleFactor = $this->getResizeRatio($widthOrig, $heightOrig); $newWidth = intval(round($widthOrig * $scaleFactor)); $newHeight = intval(round($heightOrig * $scaleFactor)); $success = $this->preciseResize($newWidth, $newHeight); if ($success === false) { throw new \RuntimeException("Error during image resize"); } return 1 / $scaleFactor; } /** * Resizes the image to reach max image area, but preserving ratio. * * @return float Ratio of resize. 1 if there was no resize */ private function getResizeRatio($widthOrig, $heightOrig): float { $areaRatio = $this->maxImageArea / ($widthOrig * $heightOrig); return sqrt($areaRatio); } }