available = $available; } /** * Budget from the current PHP settings and usage. */ public static function from_runtime(): self { $limit = self::to_bytes( (string) ini_get( 'memory_limit' ) ); return new self( null === $limit ? null : $limit - memory_get_usage( true ) ); } /** * Whether decoding a $width × $height image and producing a $max_side output fits. * * @param int $width Source width. * @param int $height Source height. * @param int $max_side Longest side of the output. */ public function fits( int $width, int $height, int $max_side ): bool { if ( null === $this->available ) { return true; } // Source bitmap + resized copy + flattened canvas of the output size. $needed = $width * $height * self::BYTES_PER_PIXEL + 2 * $max_side * $max_side * self::BYTES_PER_PIXEL; return $needed <= $this->available; } /** * Converts a php.ini size ("128M", "1G", "-1") to bytes; null means unlimited. * * @param string $value Ini value. */ public static function to_bytes( string $value ): ?int { $value = trim( $value ); if ( '' === $value || '-1' === $value ) { return null; } $number = (int) $value; $unit = strtolower( substr( $value, -1 ) ); $factor = array( 'k' => 1024, 'm' => 1024 ** 2, 'g' => 1024 ** 3, ); return $number * ( $factor[ $unit ] ?? 1 ); } }