v2.0.0.0
Publisium
- <?php
-
- declare(strict_types=1);
-
- final class Webp
- {
- private const QUALITY = 82;
-
- public static function supported(): bool
- {
- return function_exists('imagewebp') && function_exists('imagecreatefromjpeg') && function_exists('imagecreatefrompng');
- }
-
- public static function convert(string $path, string $mimeType): ?string
- {
- if (!self::supported() || !in_array($mimeType, ['image/jpeg', 'image/png'], true)) {
- return null;
- }
-
- $size = @getimagesize($path);
- if ($size === false || !self::fitsInMemory((int) $size[0], (int) $size[1])) {
- return null;
- }
-
- $orientation = 1;
- if ($mimeType === 'image/jpeg') {
- if (!function_exists('exif_read_data')) {
- return null;
- }
- $exif = @exif_read_data($path);
- $orientation = is_array($exif) ? (int) ($exif['Orientation'] ?? 1) : 1;
- }
-
- $image = $mimeType === 'image/jpeg' ? @imagecreatefromjpeg($path) : @imagecreatefrompng($path);
- if ($image === false) {
- return null;
- }
-
- if ($mimeType === 'image/png') {
- imagepalettetotruecolor($image);
- imagealphablending($image, false);
- imagesavealpha($image, true);
- }
-
- $image = self::applyOrientation($image, $orientation);
-
- $target = (string) preg_replace('/\.[A-Za-z0-9]+$/', '', $path) . '.webp';
- $saved = @imagewebp($image, $target, self::QUALITY);
- imagedestroy($image);
-
- clearstatcache(true, $target);
- if (!$saved || !is_file($target) || filesize($target) === 0 || filesize($target) >= filesize($path)) {
- @unlink($target);
- return null;
- }
-
- return $target;
- }
-
- private static function applyOrientation(GdImage $image, int $orientation): GdImage
- {
- if (in_array($orientation, [4, 5, 7], true)) {
- imageflip($image, IMG_FLIP_VERTICAL);
- } elseif ($orientation === 2) {
- imageflip($image, IMG_FLIP_HORIZONTAL);
- }
-
- $angle = match ($orientation) {
- 3 => 180,
- 5, 6 => -90,
- 7, 8 => 90,
- default => 0,
- };
-
- if ($angle === 0) {
- return $image;
- }
-
- $rotated = imagerotate($image, $angle, 0);
- if ($rotated === false) {
- return $image;
- }
- imagedestroy($image);
-
- return $rotated;
- }
-
- private static function fitsInMemory(int $width, int $height): bool
- {
- if ($width <= 0 || $height <= 0) {
- return false;
- }
-
- $limit = self::memoryLimitBytes();
- if ($limit <= 0) {
- return true;
- }
-
- return memory_get_usage() + $width * $height * 10 < $limit;
- }
-
- private static function memoryLimitBytes(): int
- {
- $value = trim((string) ini_get('memory_limit'));
- if ($value === '' || $value === '-1') {
- return -1;
- }
-
- $number = (int) $value;
-
- return match (strtolower(substr($value, -1))) {
- 'g' => $number * 1024 * 1024 * 1024,
- 'm' => $number * 1024 * 1024,
- 'k' => $number * 1024,
- default => $number,
- };
- }
- }
-