Skip to content
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

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

Merged
Merged
Show file tree
Hide file tree
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
Expand Up @@ -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;
}

/**
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
}

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

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

$this->setSizeFromString($contents);
}

/**
Expand Down Expand Up @@ -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);
}

/**
Expand Down
9 changes: 8 additions & 1 deletion src/Format/PSD.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

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

/**
* Load PSD from string.
*
* @todo calculate and set image size
*/
public static function fromString($string)
{
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
}

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

$this->setSizeFromString($contents);
}

/**
Expand Down Expand Up @@ -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);
}

/**
Expand Down
53 changes: 32 additions & 21 deletions src/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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 <[email protected]>
*
* @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
Loading