%PDF- %PDF-
| Direktori : /www/varak.net/nextcloud.varak.net/apps_old/apps/passwords/lib/Helper/Image/ |
| Current File : /www/varak.net/nextcloud.varak.net/apps_old/apps/passwords/lib/Helper/Image/ImaginaryHelper.php |
<?php
/*
* @copyright 2023 Passwords App
*
* @author Marius David Wieschollek
* @license AGPL-3.0
*
* This file is part of the Passwords App
* created by Marius David Wieschollek.
*/
namespace OCA\Passwords\Helper\Image;
use Exception;
use OCA\Passwords\Exception\Image\ImageConversionException;
use OCA\Passwords\Exception\Image\Imaginary\ImaginaryCommunicationException;
use OCA\Passwords\Exception\Image\Imaginary\NotConfiguredException;
use OCA\Passwords\Helper\Image\Imaginary\ImaginaryImage;
use OCA\Passwords\Services\ConfigurationService;
use OCP\Http\Client\IClientService;
class ImaginaryHelper extends AbstractImageHelper {
public function __construct(
protected ConfigurationService $config,
protected ImagickHelper $imagickHelper,
protected IClientService $httpClientService
) {
parent::__construct($config);
}
/**
* @param ImaginaryImage $image
* @param int $minWidth
* @param int $minHeight
* @param int $maxWidth
* @param int $maxHeight
*
* @return ImaginaryImage
* @throws Exception
*/
public function advancedResizeImage($image, int $minWidth, int $minHeight, int $maxWidth, int $maxHeight): ImaginaryImage {
$info = $this->sendRequest($image, 'info');
$size = $this->getBestImageFit($info['width'], $info['height'], $minWidth, $minHeight, $maxWidth, $maxHeight);
$this->sendRequest($image, 'resize', ['type' => 'png', 'quality' => 9, 'width' => $size['width'], 'height' => $size['height']]);
if($size['cropNeeded']) {
$this->sendRequest(
$image,
'extract',
[
'type' => 'png',
'quality' => 9,
'width' => $size['cropWidth'],
'height' => $size['cropHeight'],
'areawidth' => $size['cropWidth'],
'areaheight' => $size['cropHeight'],
'top' => $size['cropX'],
'left' => $size['cropY']
]
);
}
return $image;
}
/**
* @param ImaginaryImage $image
* @param int $size
*
* @return ImaginaryImage
* @throws Exception
*/
public function simpleResizeImage($image, int $size) {
return $this->sendRequest($image, 'resize', ['type' => 'png', 'quality' => 9, 'width' => $size, 'height' => $size]);
}
/**
* @param ImaginaryImage $image
*
* @return ImaginaryImage
* @throws Exception
*/
public function cropImageRectangular($image): ImaginaryImage {
$info = $this->sendRequest($image, 'info');
if($info['width'] === $info['height'] || $info['width'] < $info['height']) {
$size = $info['width'];
} else {
$size = $info['height'];
}
return $this->sendRequest($image, 'smartcrop', ['width' => $size, 'type' => 'png', 'quality' => 9, 'aspectratio' => '1:1']);
}
/**
* @param string $imageBlob
*
* @return ImaginaryImage
* @throws ImageConversionException
*/
public function getImageFromBlob($imageBlob) {
$tempFile = $this->config->getTempDir().uniqid();
if($this->imagickHelper->isAvailable()) {
$size = getimagesizefromstring($imageBlob);
if($size && in_array($size['mime'], ['image/icon', 'image/vnd.microsoft.icon'])) {
$imageBlob = $this->convertIcoToPng($imageBlob);
}
}
return new ImaginaryImage($imageBlob, $tempFile);
}
/**
* @param ImaginaryImage $image
*
* @return bool
*/
public function destroyImage($image): bool {
$image->destroy();
return true;
}
/**
* @param $image
*
* @return mixed
* @throws Exception
*/
public function exportJpeg($image): string {
$image = $this->sendRequest($image, 'convert', ['type' => 'jpeg', 'quality' => 90]);
return $image->getData();
}
/**
* @param $image
*
* @return string
* @throws Exception
*/
public function exportPng($image): string {
$image = $this->sendRequest($image, 'convert', ['type' => 'png', 'compression' => 9]);
return $image->getData();
}
/**
* @param string $format
*
* @return bool
*/
public function supportsFormat(string $format): bool {
$format = strtolower($format);
$supportedFormats = ['bmp', 'x-bitmap', 'png', 'jpeg', 'gif', 'heic', 'heif', 'svg+xml', 'tiff', 'webp'];
if($this->imagickHelper->isAvailable()) {
$supportedFormats[] = 'icon';
$supportedFormats[] = 'vnd.microsoft.icon';
}
return in_array($format, $supportedFormats);
}
/**
* @param string $data
*
* @return string
* @throws ImageConversionException
*/
public function convertIcoToPng($data): string {
if($this->imagickHelper->isAvailable()) {
return $this->imagickHelper->convertIcoToPng($data);
}
return $data;
}
/**
* @return bool
*/
public function isAvailable(): bool {
$imaginaryUrl = $this->config->getSystemValue('preview_imaginary_url', 'invalid');
return $imaginaryUrl !== 'invalid';
}
/**
* @param ImaginaryImage $image
* @param string $operation
* @param array $params
*
* @return ImaginaryImage|array
* @throws ImaginaryCommunicationException|NotConfiguredException
*/
protected function sendRequest(ImaginaryImage $image, string $operation, array $params = []): ImaginaryImage|array {
$imaginaryEndpointUrl = $this->getImaginaryUrl($operation);
$httpClient = $this->httpClientService->newClient();
if($operation !== 'info') {
$params['stripmeta'] = 'true';
$params['norotation'] = 'true';
}
try {
$response = $httpClient->post(
$imaginaryEndpointUrl, [
'query' => $params,
'stream' => true,
'body' => $image->getResource(),
'nextcloud' => ['allow_local_address' => true],
'timeout' => 30,
'connect_timeout' => 3,
]);
} catch(\Exception $e) {
throw new ImaginaryCommunicationException('Imaginary request failed', $e);
}
if($response->getStatusCode() !== 200) {
throw new ImaginaryCommunicationException('Imaginary request failed: '.json_decode($response->getBody())['message']);
}
$body = stream_get_contents($response->getBody());
if($operation === 'info') {
return json_decode($body, true);
}
$image->update($body);
return $image;
}
/**
* @param string $operation
*
* @return string
* @throws NotConfiguredException
*/
protected function getImaginaryUrl(string $operation): string {
$imaginaryUrl = $this->config->getSystemValue('preview_imaginary_url', 'invalid');
if($imaginaryUrl === 'invalid' || !is_string($imaginaryUrl)) {
throw new NotConfiguredException();
}
$imaginaryUrl = rtrim($imaginaryUrl, '/');
return $imaginaryUrl.'/'.$operation;
}
}