Skip to content

Commit

Permalink
Fix Image::fromString to support PNG and WebP files
Browse files Browse the repository at this point in the history
- Add missing fromString methods to PNG and WebP classes
- Update Image::fromString to read image size and MIME type with getimagesizefromstring
- Update and refactor related tests
  • Loading branch information
klaari committed Nov 12, 2024
1 parent 6e287e9 commit 88e45ed
Show file tree
Hide file tree
Showing 7 changed files with 407 additions and 131 deletions.
10 changes: 10 additions & 0 deletions src/Format/PNG.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ public static function fromFile($filename)
return new self(file_get_contents($filename));
}

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

/**
* @param string $contents
*
Expand Down
11 changes: 10 additions & 1 deletion src/Format/WebP.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,19 @@ public function getIptc()
*/
public static function fromFile($filename)
{
// var_dump($filename);
return new self(file_get_contents($filename));
}

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

/**
* @param string $contents
*
Expand Down
36 changes: 19 additions & 17 deletions src/Image.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,29 +210,31 @@ 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);
}
}
$width = $imageInfo[0];
$height = $imageInfo[1];
$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);
$image->width = $width;
$image->height = $height;
return $image;
}

return false;
Expand Down
59 changes: 32 additions & 27 deletions tests/Format/JPEGTest.php
Original file line number Diff line number Diff line change
@@ -1,53 +1,58 @@
<?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');

$xmp = $jpeg->getXmp();
$filePath = __DIR__ . '/../Fixtures/' . $filename;

$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');
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");
}

$xmp = $jpeg->getXmp();

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

Loading

0 comments on commit 88e45ed

Please sign in to comment.