Skip to content

Fix Image::fromString to support PNG and WebP files #31

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/Format/JPEG.php
Original file line number Diff line number Diff line change
@@ -85,7 +85,10 @@ public static function fromString($string)
fwrite($stream, $string);
rewind($stream);

return self::fromStream($stream);
$jpeg = self::fromStream($stream);
$jpeg->setSizeFromString($string);

return $jpeg;
}

/**
@@ -108,6 +111,8 @@ public static function fromImagick(\Imagick $imagick)
*
* @return self
* @throws \Exception
*
* @todo calculate and set image size
*/
public static function fromStream($fileHandle)
{
@@ -189,12 +194,14 @@ public static function fromStream($fileHandle)
public static function fromFile($filename)
{
$fileHandle = @fopen($filename, 'rb');

if (!$fileHandle) {
throw new \Exception(sprintf('Could not open file %s', $filename));
}

return self::fromStream($fileHandle);
$jpeg = self::fromStream($fileHandle);
$jpeg->setSizeFromFile($filename);

return $jpeg;
}

/**
19 changes: 18 additions & 1 deletion src/Format/PNG.php
Original file line number Diff line number Diff line change
@@ -40,6 +40,8 @@ public function __construct($contents)
}

$this->chunks = $this->getChunksFromContents($contents);

$this->setSizeFromString($contents);
}

/**
@@ -101,7 +103,22 @@ public function getIptc()
*/
public static function fromFile($filename)
{
return new self(file_get_contents($filename));
$contents = file_get_contents($filename);
if ($contents === false) {
throw new \Exception(sprintf('Could not open file %s', $filename));
}

return new self($contents);
}

/**
* @param $string
*
* @return PNG
*/
public static function fromString($string)
{
return new self($string);
}

/**
9 changes: 8 additions & 1 deletion src/Format/PSD.php
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

use CSD\Image\Metadata\Exif;
use CSD\Image\Metadata\Iptc;
use CSD\Image\Metadata\UnsupportedException;
use CSD\Image\Metadata\Xmp;
use CSD\Image\Image;

@@ -70,6 +71,8 @@ public static function fromResource($gd)

/**
* Load PSD from string.
*
* @todo calculate and set image size
*/
public static function fromString($string)
{
@@ -96,6 +99,8 @@ public static function fromImagick(\Imagick $imagick)
*
* @return self
* @throws \Exception
*
* @todo calculate and set image size
*/
public static function fromStream($fileHandle)
{
@@ -194,7 +199,9 @@ public static function fromFile($filename)
throw new \Exception(sprintf('Could not open file %s', $filename));
}

return self::fromStream($fileHandle);
$psd = self::fromStream($fileHandle);
$psd->setSizeFromFile($filename);
return $psd;
}

/**
21 changes: 19 additions & 2 deletions src/Format/WebP.php
Original file line number Diff line number Diff line change
@@ -47,6 +47,8 @@ public function __construct($contents)
if (!$this->isExtendedFormat()) {
// throw new \Exception('Only extended WebP format is supported');
}

$this->setSizeFromString($contents);
}

/**
@@ -144,8 +146,23 @@ public function getIptc()
*/
public static function fromFile($filename)
{
// var_dump($filename);
return new self(file_get_contents($filename));
$contents = file_get_contents($filename);
if ($contents === false) {
throw new \Exception(sprintf('Could not open file %s', $filename));
}

return new self($contents);
}


/**
* @param $string
*
* @return PNG
*/
public static function fromString($string)
{
return new self($string);
}

/**
53 changes: 32 additions & 21 deletions src/Image.php
Original file line number Diff line number Diff line change
@@ -198,10 +198,6 @@ public static function fromFile($fileName)
if (!$result) {
throw new \Exception('Unrecognised file name');
}

$size = getimagesize($fileName);
$result->width = $size[0];
$result->height = $size[1];
return $result;
}

@@ -210,31 +206,46 @@ public static function fromFile($fileName)
*
* @return JPEG|WebP|PNG|false
*/

public static function fromString($string)
{
$len = strlen($string);
$imageInfo = getimagesizefromstring($string);

// try JPEG
if ($len >= 2) {
if (JPEG::SOI === substr($string, 0, 2)) {
return JPEG::fromString($string);
}
if (!$imageInfo) {
return false;
}

// try WebP
if ($len >= 4) {
if ('RIFF' === substr($string, 0, 4) && 'WEBP' === substr($string, 8, 4)) {
return WebP::fromString($string);
}
}
$mime = $imageInfo['mime'];

// try PNG
if ($len >= 8) {
if (PNG::SIGNATURE === substr($string, 0, 8)) {
return PNG::fromString($string);
}
$mimeToClass = [
'image/jpeg' => JPEG::class,
'image/png' => PNG::class,
'image/webp' => WebP::class,
];

if (isset($mimeToClass[$mime])) {
$class = $mimeToClass[$mime];
$image = $class::fromString($string);
return $image;
}

return false;
}

protected function setSizeFromFile($fileName)
{
$imageSize = getimagesize($fileName);
if ($imageSize === false) {
throw new \Exception(sprintf('Could not get image size for %s', $fileName));
}
$this->width = $imageSize[0];
$this->height = $imageSize[1];
}

protected function setSizeFromString($string)
{
$size = getimagesizefromstring($string);
$this->width = $size[0];
$this->height = $size[1];
}
}
61 changes: 35 additions & 26 deletions tests/Format/JPEGTest.php
Original file line number Diff line number Diff line change
@@ -1,53 +1,62 @@
<?php

namespace CSD\Image\Tests\Format;

use CSD\Image\Format\JPEG;
use CSD\Image\Metadata\Xmp;

/**
* @author Daniel Chesterton <daniel@chestertondevelopment.com>
*
* @coversDefaultClass \CSD\Image\Format\JPEG
*/
class JPEGTest extends \PHPUnit\Framework\TestCase
{
/**
* Test that JPEG can read XMP embedded with Photo Mechanic.
* Data provider for testGetXmp method.
*
* @return array
*/
public function testGetXmpPhotoMechanic()
public function providerTestGetXmp()
{
$jpeg = JPEG::fromFile(__DIR__ . '/../Fixtures/metapm.jpg');

$xmp = $jpeg->getXmp();

$this->assertInstanceOf(Xmp::class, $xmp);
$this->assertSame('Headline', $xmp->getHeadline());
return [
// [method, filename, expectedHeadline]
['fromFile', 'metapm.jpg', 'Headline'],
['fromString', 'metapm.jpg', 'Headline'],
['fromFile', 'metaphotoshop.jpg', 'Headline'],
['fromString', 'metaphotoshop.jpg', 'Headline'],
['fromFile', 'nometa.jpg', null],
['fromString', 'nometa.jpg', null],
];
}

/**
* Test that JPEG can read XMP embedded with Photoshop.
* Test that JPEG can read XMP data using both fromFile and fromString methods.
*
* @dataProvider providerTestGetXmp
*
* @param string $method The method to use ('fromFile' or 'fromString')
* @param string $filename The filename of the test image
* @param string|null $expectedHeadline The expected headline in the XMP data
*/
public function testGetXmpPhotoshop()
public function testGetXmp($method, $filename, $expectedHeadline)
{
$jpeg = JPEG::fromFile(__DIR__ . '/../Fixtures/metaphotoshop.jpg');
$filePath = __DIR__ . '/../Fixtures/' . $filename;

$xmp = $jpeg->getXmp();
if ($method === 'fromFile') {
$jpeg = JPEG::fromFile($filePath);
} elseif ($method === 'fromString') {
$string = file_get_contents($filePath);
$jpeg = JPEG::fromString($string);
} else {
throw new \InvalidArgumentException("Invalid method: $method");
}

$this->assertInstanceOf(Xmp::class, $xmp);
$this->assertSame('Headline', $xmp->getHeadline());
}

/**
* Test that JPEG class returns an empty XMP object when there is no XMP data.
*/
public function testGetXmpNoMeta()
{
$jpeg = JPEG::fromFile(__DIR__ . '/../Fixtures/nometa.jpg');
$this->assertInstanceOf(JPEG::class, $jpeg);
$this->assertGreaterThan(0, $jpeg->getSize()["width"]);
$this->assertGreaterThan(0, $jpeg->getSize()["height"]);

$xmp = $jpeg->getXmp();

$this->assertInstanceOf(Xmp::class, $xmp);
$this->assertNull($xmp->getHeadline());
$this->assertSame($expectedHeadline, $xmp->getHeadline());
}
}

Loading
Oops, something went wrong.
Loading
Oops, something went wrong.