| Current Path : /proc/1908984/root/proc/2603263/cwd/ |
| Current File : //proc/1908984/root/proc/2603263/cwd/FastImageSize.tar |
FastImageSize.php 0000644 00000016426 15241433320 0007756 0 ustar 00 <?php
/**
* fast-image-size base class
*
* @package fast-image-size
* @copyright (c) Marc Alexander <admin@m-a-styles.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nextend\Framework\FastImageSize;
use Nextend\Framework\Pattern\SingletonTrait;
use Nextend\Framework\ResourceTranslator\ResourceTranslator;
class FastImageSize {
use SingletonTrait;
private static $cache = array();
/**
* @param string $image
* @param array $attributes
*/
public static function initAttributes($image, &$attributes) {
$size = self::getSize($image);
if ($size) {
$attributes['width'] = $size['width'];
$attributes['height'] = $size['height'];
}
}
public static function getWidth($image) {
$size = self::getSize($image);
if ($size) {
return $size['width'];
}
return 0;
}
public static function getSize($image) {
$imagePath = ResourceTranslator::toPath($image);
if (!isset(self::$cache[$imagePath])) {
if (empty($imagePath)) {
self::$cache[$imagePath] = false;
} else {
self::$cache[$imagePath] = self::getInstance()
->getImageSize($imagePath);
}
}
return self::$cache[$imagePath];
}
/** @var array Size info that is returned */
protected $size = array();
/** @var string Data retrieved from remote */
protected $data = '';
/** @var array List of supported image types and associated image types */
protected $supportedTypes = array(
'png' => array('png'),
'gif' => array('gif'),
'jpeg' => array(
'jpeg',
'jpg'
),
'webp' => array(
'webp',
),
'svg' => array(
'svg',
)
);
/** @var array Class map that links image extensions/mime types to class */
protected $classMap;
/** @var array An array containing the classes of supported image types */
protected $type;
/**
* Get image dimensions of supplied image
*
* @param string $file Path to image that should be checked
* @param string $type Mimetype of image
*
* @return array|bool Array with image dimensions if successful, false if not
*/
public function getImageSize($file, $type = '') {
// Reset values
$this->resetValues();
// Treat image type as unknown if extension or mime type is unknown
if (!preg_match('/\.([a-z0-9]+)$/i', $file, $match) && empty($type)) {
$this->getImagesizeUnknownType($file);
} else {
$extension = (empty($type) && isset($match[1])) ? $match[1] : preg_replace('/.+\/([a-z0-9-.]+)$/i', '$1', $type);
$this->getImageSizeByExtension($file, $extension);
}
return sizeof($this->size) > 1 ? $this->size : false;
}
/**
* Get dimensions of image if type is unknown
*
* @param string $filename Path to file
*/
protected function getImagesizeUnknownType($filename) {
// Grab the maximum amount of bytes we might need
$data = $this->getImage($filename, 0, Type\TypeJpeg::JPEG_MAX_HEADER_SIZE, false);
if ($data !== false) {
$this->loadAllTypes();
foreach ($this->type as $imageType) {
$imageType->getSize($filename);
if (sizeof($this->size) > 1) {
break;
}
}
}
}
/**
* Get image size by file extension
*
* @param string $file Path to image that should be checked
* @param string $extension Extension/type of image
*/
protected function getImageSizeByExtension($file, $extension) {
$extension = strtolower($extension);
$this->loadExtension($extension);
if (isset($this->classMap[$extension])) {
$this->classMap[$extension]->getSize($file);
}
}
/**
* Reset values to default
*/
protected function resetValues() {
$this->size = array();
$this->data = '';
}
/**
* Set mime type based on supplied image
*
* @param int $type Type of image
*/
public function setImageType($type) {
$this->size['type'] = $type;
}
/**
* Set size info
*
* @param array $size Array containing size info for image
*/
public function setSize($size) {
$this->size = $size;
}
/**
* Get image from specified path/source
*
* @param string $filename Path to image
* @param int $offset Offset at which reading of the image should start
* @param int $length Maximum length that should be read
* @param bool $forceLength True if the length needs to be the specified
* length, false if not. Default: true
*
* @return false|string Image data or false if result was empty
*/
public function getImage($filename, $offset, $length, $forceLength = true) {
if (empty($this->data)) {
$this->data = @file_get_contents($filename, false, null, $offset, $length);
}
// Force length to expected one. Return false if data length
// is smaller than expected length
if ($forceLength === true) {
return (strlen($this->data) < $length) ? false : substr($this->data, $offset, $length);
}
return empty($this->data) ? false : $this->data;
}
/**
* Get return data
*
* @return array|bool Size array if dimensions could be found, false if not
*/
protected function getReturnData() {
return sizeof($this->size) > 1 ? $this->size : false;
}
/**
* Load all supported types
*/
protected function loadAllTypes() {
foreach ($this->supportedTypes as $imageType => $extension) {
$this->loadType($imageType);
}
}
/**
* Load an image type by extension
*
* @param string $extension Extension of image
*/
protected function loadExtension($extension) {
if (isset($this->classMap[$extension])) {
return;
}
foreach ($this->supportedTypes as $imageType => $extensions) {
if (in_array($extension, $extensions, true)) {
$this->loadType($imageType);
}
}
}
/**
* Load an image type
*
* @param string $imageType Mimetype
*/
protected function loadType($imageType) {
if (isset($this->type[$imageType])) {
return;
}
$className = '\\' . __NAMESPACE__ . '\Type\Type' . ucfirst($imageType);
$this->type[$imageType] = new $className($this);
// Create class map
foreach ($this->supportedTypes[$imageType] as $ext) {
/** @var Type\TypeInterface */
$this->classMap[$ext] = $this->type[$imageType];
}
}
}
Type/TypeBase.php 0000644 00000001346 15241433321 0007714 0 ustar 00 <?php
/**
* fast-image-size image type base
*
* @package fast-image-size
* @copyright (c) Marc Alexander <admin@m-a-styles.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nextend\Framework\FastImageSize\Type;
use Nextend\Framework\FastImageSize\FastImageSize;
abstract class TypeBase implements TypeInterface {
/** @var FastImageSize */
protected $fastImageSize;
/**
* Base constructor for image types
*
* @param FastImageSize $fastImageSize
*/
public function __construct(FastImageSize $fastImageSize) {
$this->fastImageSize = $fastImageSize;
}
}
Type/TypeGif.php 0000644 00000002467 15241433321 0007554 0 ustar 00 <?php
/**
* fast-image-size image type gif
*
* @package fast-image-size
* @copyright (c) Marc Alexander <admin@m-a-styles.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nextend\Framework\FastImageSize\Type;
class TypeGif extends TypeBase {
/** @var string GIF87a header */
const GIF87A_HEADER = "\x47\x49\x46\x38\x37\x61";
/** @var string GIF89a header */
const GIF89A_HEADER = "\x47\x49\x46\x38\x39\x61";
/** @var int GIF header size */
const GIF_HEADER_SIZE = 6;
/**
* {@inheritdoc}
*/
public function getSize($filename) {
// Get data needed for reading image dimensions as outlined by GIF87a
// and GIF89a specifications
$data = $this->fastImageSize->getImage($filename, 0, self::GIF_HEADER_SIZE + self::SHORT_SIZE * 2);
$type = substr($data, 0, self::GIF_HEADER_SIZE);
if ($type !== self::GIF87A_HEADER && $type !== self::GIF89A_HEADER) {
return;
}
$size = unpack('vwidth/vheight', substr($data, self::GIF_HEADER_SIZE, self::SHORT_SIZE * 2));
$this->fastImageSize->setSize($size);
$this->fastImageSize->setImageType(IMAGETYPE_GIF);
}
}
Type/TypeInterface.php 0000644 00000001261 15241433324 0010741 0 ustar 00 <?php
/**
* fast-image-size image type interface
*
* @package fast-image-size
* @copyright (c) Marc Alexander <admin@m-a-styles.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nextend\Framework\FastImageSize\Type;
interface TypeInterface {
/** @var int 4-byte long size */
const LONG_SIZE = 4;
/** @var int 2-byte short size */
const SHORT_SIZE = 2;
/**
* Get size of supplied image
*
* @param string $filename File name of image
*
* @return null
*/
public function getSize($filename);
}
Type/TypeJpeg.php 0000644 00000012123 15241433327 0007730 0 ustar 00 <?php
/**
* fast-image-size image type jpeg
*
* @package fast-image-size
* @copyright (c) Marc Alexander <admin@m-a-styles.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nextend\Framework\FastImageSize\Type;
class TypeJpeg extends TypeBase {
/** @var int JPEG max header size. Headers can be bigger, but we'll abort
* going through the header after this */
const JPEG_MAX_HEADER_SIZE = 786432; // = 768 kiB
/** @var string JPEG header */
const JPEG_HEADER = "\xFF\xD8";
/** @var string Start of frame marker */
const SOF_START_MARKER = "\xFF";
/** @var string End of image (EOI) marker */
const JPEG_EOI_MARKER = "\xD9";
/** @var array JPEG SOF markers */
protected $sofMarkers = array(
"\xC0",
"\xC1",
"\xC2",
"\xC3",
"\xC5",
"\xC6",
"\xC7",
"\xC9",
"\xCA",
"\xCB",
"\xCD",
"\xCE",
"\xCF"
);
/** @var string|bool JPEG data stream */
protected $data = '';
/** @var int Data length */
protected $dataLength = 0;
/**
* {@inheritdoc}
*/
public function getSize($filename) {
// Do not force the data length
$this->data = $this->fastImageSize->getImage($filename, 0, self::JPEG_MAX_HEADER_SIZE, false);
// Check if file is jpeg
if ($this->data === false || substr($this->data, 0, self::SHORT_SIZE) !== self::JPEG_HEADER) {
return;
}
// Look through file for SOF marker
$size = $this->getSizeInfo();
$this->fastImageSize->setSize($size);
$this->fastImageSize->setImageType(IMAGETYPE_JPEG);
}
/**
* Get size info from image data
*
* @return array An array with the image's size info or an empty array if
* size info couldn't be found
*/
protected function getSizeInfo() {
$size = array();
// since we check $i + 1 we need to stop one step earlier
$this->dataLength = strlen($this->data) - 1;
$sofStartRead = true;
// Look through file for SOF marker
for ($i = 2; $i < $this->dataLength; $i++) {
$marker = $this->getNextMarker($i, $sofStartRead);
if (in_array($marker, $this->sofMarkers)) {
// Extract size info from SOF marker
return $this->extractSizeInfo($i);
} else {
// Extract length only
$markerLength = $this->extractMarkerLength($i);
if ($markerLength < 2) {
return $size;
}
$i += $markerLength - 1;
continue;
}
}
return $size;
}
/**
* Extract marker length from data
*
* @param int $i Current index
*
* @return int Length of current marker
*/
protected function extractMarkerLength($i) {
// Extract length only
list(, $unpacked) = unpack("H*", substr($this->data, $i, self::LONG_SIZE));
// Get width and height from unpacked size info
$markerLength = hexdec(substr($unpacked, 0, 4));
return $markerLength;
}
/**
* Extract size info from data
*
* @param int $i Current index
*
* @return array Size info of current marker
*/
protected function extractSizeInfo($i) {
// Extract size info from SOF marker
list(, $unpacked) = unpack("H*", substr($this->data, $i - 1 + self::LONG_SIZE, self::LONG_SIZE));
// Get width and height from unpacked size info
$size = array(
'width' => hexdec(substr($unpacked, 4, 4)),
'height' => hexdec(substr($unpacked, 0, 4)),
);
return $size;
}
/**
* Get next JPEG marker in file
*
* @param int $i Current index
* @param bool $sofStartRead Flag whether SOF start padding was already read
*
* @return string Next JPEG marker in file
*/
protected function getNextMarker(&$i, &$sofStartRead) {
$this->skipStartPadding($i, $sofStartRead);
do {
if ($i >= $this->dataLength) {
return self::JPEG_EOI_MARKER;
}
$marker = $this->data[$i];
$i++;
} while ($marker == self::SOF_START_MARKER);
return $marker;
}
/**
* Skip over any possible padding until we reach a byte without SOF start
* marker. Extraneous bytes might need to require proper treating.
*
* @param int $i Current index
* @param bool $sofStartRead Flag whether SOF start padding was already read
*/
protected function skipStartPadding(&$i, &$sofStartRead) {
if (!$sofStartRead) {
while ($this->data[$i] !== self::SOF_START_MARKER) {
$i++;
}
}
}
}
Type/TypePng.php 0000644 00000002537 15241433327 0007577 0 ustar 00 <?php
/**
* fast-image-size image type png
*
* @package fast-image-size
* @copyright (c) Marc Alexander <admin@m-a-styles.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nextend\Framework\FastImageSize\Type;
class TypePng extends TypeBase {
/** @var string PNG header */
const PNG_HEADER = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
/** @var int PNG IHDR offset */
const PNG_IHDR_OFFSET = 12;
/**
* {@inheritdoc}
*/
public function getSize($filename) {
// Retrieve image data including the header, the IHDR tag, and the
// following 2 chunks for the image width and height
$data = $this->fastImageSize->getImage($filename, 0, self::PNG_IHDR_OFFSET + 3 * self::LONG_SIZE);
// Check if header fits expected format specified by RFC 2083
if (substr($data, 0, self::PNG_IHDR_OFFSET - self::LONG_SIZE) !== self::PNG_HEADER || substr($data, self::PNG_IHDR_OFFSET, self::LONG_SIZE) !== 'IHDR') {
return;
}
$size = unpack('Nwidth/Nheight', substr($data, self::PNG_IHDR_OFFSET + self::LONG_SIZE, self::LONG_SIZE * 2));
$this->fastImageSize->setSize($size);
$this->fastImageSize->setImageType(IMAGETYPE_PNG);
}
}
Type/TypeSvg.php 0000644 00000002014 15241433331 0007573 0 ustar 00 <?php
namespace Nextend\Framework\FastImageSize\Type;
class TypeSvg extends TypeBase {
/**
* {@inheritdoc}
*/
public function getSize($filename) {
$data = $this->fastImageSize->getImage($filename, 0, 100);
preg_match('/width="([0-9]+)"/', $data, $matches);
if ($matches && $matches[1] > 0) {
$size = array();
$size['width'] = $matches[1];
preg_match('/height="([0-9]+)"/', $data, $matches);
if ($matches && $matches[1] > 0) {
$size['height'] = $matches[1];
$this->fastImageSize->setSize($size);
return;
}
}
preg_match('/viewBox=["\']([0-9]+) ([0-9]+) ([0-9]+) ([0-9]+)["\']/i', $data, $matches);
if ($matches) {
$this->fastImageSize->setSize(array(
'width' => $matches[3] - $matches[1],
'height' => $matches[4] - $matches[2],
));
}
}
}
Type/TypeWebp.php 0000644 00000010423 15241433331 0007734 0 ustar 00 <?php
/**
* fast-image-size image type webp
*
* @package fast-image-size
* @copyright (c) Marc Alexander <admin@m-a-styles.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Nextend\Framework\FastImageSize\Type;
use Nextend\Framework\FastImageSize\FastImageSize;
class TypeWebp extends TypeBase {
/** @var string RIFF header */
const WEBP_RIFF_HEADER = "RIFF";
/** @var string Webp header */
const WEBP_HEADER = "WEBP";
/** @var string VP8 chunk header */
const VP8_HEADER = "VP8";
/** @var string Simple(lossy) webp format */
const WEBP_FORMAT_SIMPLE = ' ';
/** @var string Lossless webp format */
const WEBP_FORMAT_LOSSLESS = 'L';
/** @var string Extended webp format */
const WEBP_FORMAT_EXTENDED = 'X';
/** @var int WEBP header size needed for retrieving image size */
const WEBP_HEADER_SIZE = 30;
/** @var array Size info array */
protected $size;
/**
* Constructor for webp image type. Adds missing constant if necessary.
*
* @param FastImageSize $fastImageSize
*/
public function __construct(FastImageSize $fastImageSize) {
parent::__construct($fastImageSize);
if (!defined('IMAGETYPE_WEBP')) {
define('IMAGETYPE_WEBP', 18);
}
}
/**
* {@inheritdoc}
*/
public function getSize($filename) {
// Do not force length of header
$data = $this->fastImageSize->getImage($filename, 0, self::WEBP_HEADER_SIZE);
$this->size = array();
$webpFormat = substr($data, 15, 1);
if (!$this->hasWebpHeader($data) || !$this->isValidFormat($webpFormat)) {
return;
}
$data = substr($data, 16, 14);
$this->getWebpSize($data, $webpFormat);
$this->fastImageSize->setSize($this->size);
$this->fastImageSize->setImageType(IMAGETYPE_WEBP);
}
/**
* Check if $data has valid WebP header
*
* @param string $data Image data
*
* @return bool True if $data has valid WebP header, false if not
*/
protected function hasWebpHeader($data) {
$riffSignature = substr($data, 0, self::LONG_SIZE);
$webpSignature = substr($data, 8, self::LONG_SIZE);
$vp8Signature = substr($data, 12, self::SHORT_SIZE + 1);
return !empty($data) && $riffSignature === self::WEBP_RIFF_HEADER && $webpSignature === self::WEBP_HEADER && $vp8Signature === self::VP8_HEADER;
}
/**
* Check if $format is a valid WebP format
*
* @param string $format Format string
*
* @return bool True if format is valid WebP format, false if not
*/
protected function isValidFormat($format) {
return in_array($format, array(
self::WEBP_FORMAT_SIMPLE,
self::WEBP_FORMAT_LOSSLESS,
self::WEBP_FORMAT_EXTENDED
));
}
/**
* Get webp size info depending on format type and set size array values
*
* @param string $data Data string
* @param string $format Format string
*/
protected function getWebpSize($data, $format) {
switch ($format) {
case self::WEBP_FORMAT_SIMPLE:
$this->size = unpack('vwidth/vheight', substr($data, 10, 4));
break;
case self::WEBP_FORMAT_LOSSLESS:
// Lossless uses 14-bit values so we'll have to use bitwise shifting
$this->size = array(
'width' => ord($data[5]) + ((ord($data[6]) & 0x3F) << 8) + 1,
'height' => (ord($data[6]) >> 6) + (ord($data[7]) << 2) + ((ord($data[8]) & 0xF) << 10) + 1,
);
break;
case self::WEBP_FORMAT_EXTENDED:
// Extended uses 24-bit values cause 14-bit for lossless wasn't weird enough
$this->size = array(
'width' => ord($data[8]) + (ord($data[9]) << 8) + (ord($data[10]) << 16) + 1,
'height' => ord($data[11]) + (ord($data[12]) << 8) + (ord($data[13]) << 16) + 1,
);
break;
}
}
}