[ATTACHMENTS][AttachmentThumbnail] Fix implementation of predictScalingValues and small fixes

This commit is contained in:
Hugo Sales 2021-08-18 17:30:54 +01:00
parent 2ccbbd53a6
commit 4cd3924cc1
Signed by: someonewithpc
GPG Key ID: 7D0C7EAFC9D835A0

View File

@ -28,9 +28,11 @@ use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\NotFoundException; use App\Util\Exception\NotFoundException;
use App\Util\Exception\NotStoredLocallyException;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
use DateTimeInterface; use DateTimeInterface;
use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Mime\MimeTypes;
@ -130,16 +132,16 @@ class AttachmentThumbnail extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
private Attachment $attachment; private ?Attachment $attachment = null;
public function setAttachment(Attachment $attachment) public function setAttachment(?Attachment $attachment)
{ {
$this->attachment = $attachment; $this->attachment = $attachment;
} }
public function getAttachment() public function getAttachment()
{ {
if (isset($this->attachment)) { if (isset($this->attachment) && !is_null($this->attachment)) {
return $this->attachment; return $this->attachment;
} else { } else {
return $this->attachment = DB::findOneBy('attachment', ['id' => $this->attachment_id]); return $this->attachment = DB::findOneBy('attachment', ['id' => $this->attachment_id]);
@ -164,8 +166,10 @@ class AttachmentThumbnail extends Entity
$predicted_height = null; $predicted_height = null;
try { try {
if (is_null($attachment->getWidth()) || is_null($attachment->getHeight())) { if (is_null($attachment->getWidth()) || is_null($attachment->getHeight())) {
// @codeCoverageIgnoreStart
// TODO: check if we can generate from an existing thumbnail // TODO: check if we can generate from an existing thumbnail
throw new ClientException(_m('Invalid dimensions requested for thumbnail.')); throw new ClientException(_m('Invalid dimensions requested for thumbnail.'));
// @codeCoverageIgnoreEnd
} }
return Cache::get('thumb-' . $attachment->getId() . "-{$width}x{$height}", return Cache::get('thumb-' . $attachment->getId() . "-{$width}x{$height}",
function () use ($crop, $attachment, $width, $height, &$predicted_width, &$predicted_height) { function () use ($crop, $attachment, $width, $height, &$predicted_width, &$predicted_height) {
@ -173,8 +177,8 @@ class AttachmentThumbnail extends Entity
return DB::findOneBy('attachment_thumbnail', ['attachment_id' => $attachment->getId(), 'width' => $predicted_width, 'height' => $predicted_height]); return DB::findOneBy('attachment_thumbnail', ['attachment_id' => $attachment->getId(), 'width' => $predicted_width, 'height' => $predicted_height]);
}); });
} catch (NotFoundException $e) { } catch (NotFoundException $e) {
if (is_null($attachment->getPath())) { if (!file_exists($attachment->getPath())) {
throw new NotFoundException('Can\'t generate a thumbnail for this attachment given the requested dimensions'); throw new NotStoredLocallyException();
} }
$thumbnail = self::create(['attachment_id' => $attachment->getId()]); $thumbnail = self::create(['attachment_id' => $attachment->getId()]);
$event_map = []; $event_map = [];
@ -189,6 +193,7 @@ class AttachmentThumbnail extends Entity
[$attachment->getPath(), &$temp, &$width, &$height, $crop, &$mimetype] [$attachment->getPath(), &$temp, &$width, &$height, $crop, &$mimetype]
) )
) { ) {
$thumbnail->setAttachment($attachment);
$thumbnail->setWidth($predicted_width); $thumbnail->setWidth($predicted_width);
$thumbnail->setHeight($predicted_height); $thumbnail->setHeight($predicted_height);
$ext = '.' . MimeTypes::getDefault()->getExtensions($temp->getMimeType())[0]; $ext = '.' . MimeTypes::getDefault()->getExtensions($temp->getMimeType())[0];
@ -200,11 +205,13 @@ class AttachmentThumbnail extends Entity
$temp->move(Common::config('thumbnail', 'dir'), $filename); $temp->move(Common::config('thumbnail', 'dir'), $filename);
return $thumbnail; return $thumbnail;
} else { } else {
// @codeCoverageIgnoreStart
Log::debug($m = ('Somehow the EncoderPlugin didn\'t handle ' . $attachment->getMimetype())); Log::debug($m = ('Somehow the EncoderPlugin didn\'t handle ' . $attachment->getMimetype()));
throw new ServerException($m); throw new ServerException(_m($m));
} }
} else { } else {
throw new ClientException(_m('Can not generate thumbnail for attachment with id={id}', ['id' => $attachment->getId()])); throw new ClientException(_m('Can not generate thumbnail for attachment with id={id}', ['id' => $attachment->getId()]));
// @codeCoverageIgnoreEnd
} }
} }
} }
@ -240,7 +247,9 @@ class AttachmentThumbnail extends Entity
$filepath = $this->getPath(); $filepath = $this->getPath();
if (file_exists($filepath)) { if (file_exists($filepath)) {
if (@unlink($filepath) === false) { if (@unlink($filepath) === false) {
// @codeCoverageIgnoreStart
Log::warning("Failed deleting file for attachment thumbnail with id={$this->attachment_id}, width={$this->width}, height={$this->height} at {$filepath}"); Log::warning("Failed deleting file for attachment thumbnail with id={$this->attachment_id}, width={$this->width}, height={$this->height} at {$filepath}");
// @codeCoverageIgnoreEnd
} }
} }
DB::remove($this); DB::remove($this);
@ -264,44 +273,25 @@ class AttachmentThumbnail extends Entity
* @return array [predicted width, predicted height] * @return array [predicted width, predicted height]
*/ */
public static function predictScalingValues( public static function predictScalingValues(
int $width, int $existing_width,
int $height, int $existing_height,
int $maxW, int $requested_width,
int $maxH, int $requested_height,
bool $crop bool $crop
): array { ): array {
// Cropping data (for original image size). Default values, 0 and null,
// imply no cropping and with preserved aspect ratio (per axis).
$cx = 0; // crop x
$cy = 0; // crop y
$cw = null; // crop area width
$ch = null; // crop area height
if ($crop) { if ($crop) {
$s_ar = $width / $height; $rw = min($existing_width, $requested_width);
$t_ar = $maxW / $maxH; $rh = min($existing_height, $requested_height);
$rw = $maxW;
$rh = $maxH;
// Source aspect ratio differs from target, recalculate crop points!
if ($s_ar > $t_ar) {
$cx = floor($width / 2 - $height * $t_ar / 2);
$cw = ceil($height * $t_ar);
} elseif ($s_ar < $t_ar) {
$cy = floor($height / 2 - $width / $t_ar / 2);
$ch = ceil($width / $t_ar);
}
} else { } else {
$rw = $maxW; if ($existing_width > $existing_height) {
$rh = ceil($height * $rw / $width); $rw = min($existing_width, $requested_width);
$rh = ceil($existing_height * $rw / $existing_width);
// Scaling caused too large height, decrease to max accepted value } else {
if ($rh > $maxH) { $rh = min($existing_height, $requested_height);
$rh = $maxH; $rw = ceil($existing_width * $rh / $existing_height);
$rw = ceil($width * $rh / $height);
} }
} }
return [(int) $rw, (int) $rh]; return [(int) $rw, (int) $rh];
} }