forked from leftypol/leftypol
CmdMagickMediaHandler.php: add WIP partial implementation
This commit is contained in:
parent
262728cea9
commit
7d55f2ad5c
1 changed files with 143 additions and 0 deletions
143
inc/Service/Media/CmdMagickMediaHandler.php
Normal file
143
inc/Service/Media/CmdMagickMediaHandler.php
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
namespace Vichan\Service\Media;
|
||||
|
||||
use Vichan\Functions\{Fs, Metadata};
|
||||
use Vichan\Data\{Exif, MediaInstallResult, ThumbGenerationResult};
|
||||
|
||||
class CmdMagickMediaHandler implements MediaHandler {
|
||||
use MediaHandlerTrait;
|
||||
|
||||
public const CMD_IMAGE_MAGICK = 'magick';
|
||||
public const CMD_GRAPHICS_MAGICK = 'gm';
|
||||
public const THUMB_KEEP_FRAMES_NO = 0;
|
||||
public const THUMB_KEEP_FRAMES_ALL = -1;
|
||||
|
||||
private string $prefix;
|
||||
private bool $strip_metadata;
|
||||
private int $max_image_width;
|
||||
private int $max_image_height;
|
||||
|
||||
|
||||
private static function parseOrientation(string $str): ?int {
|
||||
switch ($str) {
|
||||
case 'Undefined':
|
||||
return Exif::EXIF_ORIENTATION_UNDEFINED;
|
||||
case 'TopLeft':
|
||||
return Exif::EXIF_ORIENTATION_0_UPRIGHT;
|
||||
case 'TopRight':
|
||||
return Exif::EXIF_ORIENTATION_0_FLIPPED;
|
||||
case 'BottomRight':
|
||||
return Exif::EXIF_ORIENTATION_180_UPRIGHT;
|
||||
case 'BottomLeft':
|
||||
return Exif::EXIF_ORIENTATION_180_FLIPPED;
|
||||
case 'LeftTop':
|
||||
return Exif::EXIF_ORIENTATION_90_UPRIGHT;
|
||||
case 'RightTop':
|
||||
return Exif::EXIF_ORIENTATION_90_FLIPPED;
|
||||
case 'RightBottom':
|
||||
return Exif::EXIF_ORIENTATION_270_UPRIGHT;
|
||||
case 'LeftBottom':
|
||||
return Exif::EXIF_ORIENTATION_270_FLIPPED;
|
||||
case 'Unrecognized':
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getMetadata(string $file_path, bool $only_first_frame): array {
|
||||
$arg = \escapeshellarg($only_first_frame ? "{$file_path}[0]" : $file_path);
|
||||
$ret_exec = shell_exec_error("{$this->prefix} identify -format '%w %h %m %[orientation] %n' $arg");
|
||||
|
||||
if (!\is_string($ret_exec)) {
|
||||
throw new MediaException('Error while executing identify', MediaException::ERR_COMPUTE_ERR);
|
||||
}
|
||||
$ret_match = \preg_match('/^(\d+) (\d+) ([\w\d]+) ([\w]+) (\d+)$/', $ret_exec, $m);
|
||||
if ($ret_match !== 1) {
|
||||
throw new MediaException('Could not parse identify output', MediaException::ERR_COMPUTE_ERR);
|
||||
}
|
||||
$width = \intval($m[1]);
|
||||
$height = \intval($m[2]);
|
||||
$ext = $m[3];
|
||||
$orientation_str = $m[4];
|
||||
$frame_count = \intval($m[5]);
|
||||
|
||||
$mime = Metadata\ext_to_mime($ext) ?? 'application/octet-stream';
|
||||
$exif_orientation = self::parseOrientation($orientation_str);
|
||||
return [ $width, $height, $mime, $exif_orientation, $frame_count ];
|
||||
}
|
||||
|
||||
private function __construct(string $cmd, bool $strip_metadata, int $max_image_width, int $max_image_height) {
|
||||
$this->prefix = $cmd;
|
||||
$this->strip_metadata = $strip_metadata;
|
||||
$this->max_image_width = $max_image_width;
|
||||
$this->max_image_height = $max_image_height;
|
||||
}
|
||||
|
||||
public function supportsMime(string $mime): bool {
|
||||
// Could not find a good way to query the commands. Also it would be really slow.
|
||||
return \in_array($mime, Metadata\SUPPORTED_IMAGE_MIME_TYPES)
|
||||
|| \in_array($mime, Metadata\SUPPORTED_THUMB_MIME_TYPES);
|
||||
}
|
||||
|
||||
public function openHandle(string $file_path, string $file_mime, int $file_kind): mixed {
|
||||
$is_pdf = $file_mime === 'application/pdf';
|
||||
list($width, $height, $mime, $exif_orientation) = self::getMetadata($file_path, $is_pdf);
|
||||
|
||||
if ($mime !== $file_mime) {
|
||||
throw new MediaException("Mime type mismatch, expected $file_mime, got $mime", MediaException::ERR_COMPUTE_ERR);
|
||||
}
|
||||
if ($width > $this->max_image_width || $height > $this->max_image_height) {
|
||||
throw new MediaException("Image too big", MediaException::ERR_IMAGE_TOO_LARGE);
|
||||
}
|
||||
|
||||
return [ $file_path, $file_mime, $file_kind, $width, $height, $exif_orientation ];
|
||||
}
|
||||
|
||||
public function closeHandle(mixed $handle) {
|
||||
// No-op.
|
||||
}
|
||||
|
||||
public function installMediaAndGenerateThumb(
|
||||
mixed $handle,
|
||||
string $media_preferred_out_file_basepath,
|
||||
string $thumb_preferred_out_file_basepath,
|
||||
int $thumb_max_width,
|
||||
int $thumb_max_height
|
||||
): MediaInstallResult {
|
||||
list($source_file_path, $source_file_mime, $source_file_kind, $width, $height, $exif_orientation) = $handle;
|
||||
|
||||
if (!$this->strip_metadata) {
|
||||
$media_out_path = $media_preferred_out_file_basepath . Metadata\mime_to_ext($source_file_mime);
|
||||
$this->move_or_link_or_copy($source_file_kind, $source_file_path, $media_out_path);
|
||||
|
||||
if ($width <= $thumb_max_width && $height <= $thumb_max_height) {
|
||||
$thumb_out_path = $thumb_preferred_out_file_basepath . Metadata\mime_to_ext($source_file_mime);
|
||||
if (!Fs\link_or_copy($media_out_path, $thumb_out_path)) {
|
||||
throw new MediaException("Could not link or copy '$media_out_path' to '$thumb_out_path'", MediaException::ERR_IO_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function installMedia(mixed $handle, string $preferred_out_file_basepath): string {
|
||||
list($source_file_path, $source_file_mime, $source_file_kind, $width, $height, $exif_orientation) = $handle;
|
||||
|
||||
if (!$this->strip_metadata) {
|
||||
$out_path = $preferred_out_file_basepath . Metadata\mime_to_ext($source_file_mime);
|
||||
$this->move_or_link_or_copy($source_file_kind, $source_file_path, $out_path);
|
||||
return $out_path;
|
||||
}
|
||||
}
|
||||
|
||||
public function generateThumb(mixed $handle, string $preferred_out_file_basepath, int $max_width, int $max_height): ThumbGenerationResult {
|
||||
list($source_file_path, $source_file_mime, $source_file_kind, $width, $height, $exif_orientation) = $handle;
|
||||
|
||||
if (!$this->strip_metadata && $width <= $max_width && $height <= $max_height) {
|
||||
$out_path = $preferred_out_file_basepath . Metadata\mime_to_ext($source_file_mime);
|
||||
$this->move_or_link_or_copy($source_file_kind, $source_file_path, $out_path);
|
||||
return new ThumbGenerationResult($out_path, $source_file_mime, $width, $height);
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue