fix: static
This commit is contained in:
@@ -9,6 +9,9 @@ use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class PhotoOcrPreparer
|
||||
{
|
||||
/** @var array<string, ?string> */
|
||||
private static array $bins = [];
|
||||
|
||||
public function __construct(private readonly PhotoPreview $preview) {}
|
||||
|
||||
/**
|
||||
@@ -21,30 +24,49 @@ class PhotoOcrPreparer
|
||||
return null;
|
||||
}
|
||||
|
||||
$payload = $this->preview->payload($abs, (string) ($photo->device?->device_id ?: $photo->device_id), (string) $photo->sha256);
|
||||
$bytes = (string) ($payload['bytes'] ?? '');
|
||||
if ($bytes === '') {
|
||||
$jpeg = $this->tempJpeg();
|
||||
if ($jpeg === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'ocr_');
|
||||
if ($tmp === false) {
|
||||
$head = (string) @file_get_contents($abs, false, null, 0, 64);
|
||||
if ($this->preview->headLooksHeic($head) || $this->looksHeicPath($abs)) {
|
||||
$payload = $this->preview->payload(
|
||||
$abs,
|
||||
(string) ($photo->device?->device_id ?: $photo->device_id),
|
||||
(string) $photo->sha256,
|
||||
);
|
||||
$bytes = (string) ($payload['bytes'] ?? '');
|
||||
if ($bytes === '' || ! $this->isJpeg($bytes)) {
|
||||
@unlink($jpeg);
|
||||
|
||||
return null;
|
||||
}
|
||||
file_put_contents($jpeg, $bytes);
|
||||
} elseif (! @copy($abs, $jpeg)) {
|
||||
@unlink($jpeg);
|
||||
|
||||
return null;
|
||||
}
|
||||
$jpeg = $tmp.'.jpg';
|
||||
@unlink($tmp);
|
||||
file_put_contents($jpeg, $bytes);
|
||||
|
||||
$this->resize($jpeg);
|
||||
|
||||
return $jpeg;
|
||||
return is_file($jpeg) ? $jpeg : null;
|
||||
}
|
||||
|
||||
private function resize(string $path): void
|
||||
{
|
||||
$max = (int) config('coruna.ocr.max_edge', 1800);
|
||||
$max = (int) config('coruna.ocr.max_edge', 1280);
|
||||
if ($max < 400) {
|
||||
return;
|
||||
}
|
||||
$info = @getimagesize($path);
|
||||
if (is_array($info) && (int) ($info[0] ?? 0) <= $max && (int) ($info[1] ?? 0) <= $max) {
|
||||
return;
|
||||
}
|
||||
if ($this->resizeWithGd($path, $max)) {
|
||||
return;
|
||||
}
|
||||
$magick = $this->which('magick') ?? $this->which('convert');
|
||||
if ($magick !== null) {
|
||||
Process::timeout(30)->run([$magick, $path, '-resize', $max.'x'.$max.'>', $path]);
|
||||
@@ -56,11 +78,77 @@ class PhotoOcrPreparer
|
||||
}
|
||||
}
|
||||
|
||||
private function resizeWithGd(string $path, int $max): bool
|
||||
{
|
||||
if (! function_exists('imagecreatefromstring') || ! function_exists('imagejpeg')) {
|
||||
return false;
|
||||
}
|
||||
$bytes = @file_get_contents($path);
|
||||
if (! is_string($bytes) || $bytes === '') {
|
||||
return false;
|
||||
}
|
||||
$src = @imagecreatefromstring($bytes);
|
||||
if ($src === false) {
|
||||
return false;
|
||||
}
|
||||
$width = imagesx($src);
|
||||
$height = imagesy($src);
|
||||
$edge = max($width, $height);
|
||||
if ($edge <= $max) {
|
||||
imagedestroy($src);
|
||||
|
||||
return true;
|
||||
}
|
||||
$scale = $max / $edge;
|
||||
$newW = max(1, (int) round($width * $scale));
|
||||
$newH = max(1, (int) round($height * $scale));
|
||||
$dst = imagecreatetruecolor($newW, $newH);
|
||||
if ($dst === false) {
|
||||
imagedestroy($src);
|
||||
|
||||
return false;
|
||||
}
|
||||
imagecopyresampled($dst, $src, 0, 0, 0, 0, $newW, $newH, $width, $height);
|
||||
imagedestroy($src);
|
||||
$ok = imagejpeg($dst, $path, 85);
|
||||
imagedestroy($dst);
|
||||
|
||||
return $ok;
|
||||
}
|
||||
|
||||
private function tempJpeg(): ?string
|
||||
{
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'ocr_');
|
||||
if ($tmp === false) {
|
||||
return null;
|
||||
}
|
||||
$jpeg = $tmp.'.jpg';
|
||||
@unlink($tmp);
|
||||
|
||||
return $jpeg;
|
||||
}
|
||||
|
||||
private function looksHeicPath(string $path): bool
|
||||
{
|
||||
$ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));
|
||||
|
||||
return in_array($ext, ['heic', 'heif'], true);
|
||||
}
|
||||
|
||||
private function isJpeg(string $bytes): bool
|
||||
{
|
||||
return strlen($bytes) >= 3 && substr($bytes, 0, 2) === "\xFF\xD8";
|
||||
}
|
||||
|
||||
private function which(string $bin): ?string
|
||||
{
|
||||
if (array_key_exists($bin, self::$bins)) {
|
||||
return self::$bins[$bin];
|
||||
}
|
||||
$result = Process::timeout(3)->run(['which', $bin]);
|
||||
$path = trim($result->output());
|
||||
self::$bins[$bin] = $result->successful() && $path !== '' ? $path : null;
|
||||
|
||||
return $result->successful() && $path !== '' ? $path : null;
|
||||
return self::$bins[$bin];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,13 +14,15 @@ class TesseractOcrDriver implements OcrDriver
|
||||
}
|
||||
|
||||
$bin = (string) config('coruna.ocr.tesseract', 'tesseract');
|
||||
$langs = (string) config('coruna.ocr.langs', 'eng+chi_sim');
|
||||
$oem = max(0, (int) config('coruna.ocr.oem', 1));
|
||||
$psm = max(0, (int) config('coruna.ocr.psm', 6));
|
||||
$result = Process::timeout(90)->run([
|
||||
$bin,
|
||||
$imagePath,
|
||||
'stdout',
|
||||
'-l', $langs,
|
||||
'--psm', '6',
|
||||
'-l', 'eng',
|
||||
'--oem', (string) $oem,
|
||||
'--psm', (string) $psm,
|
||||
]);
|
||||
|
||||
if (! $result->successful()) {
|
||||
|
||||
Reference in New Issue
Block a user