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

CI - test images handling that use GD path #46

Merged
merged 11 commits into from
Jun 25, 2021
2 changes: 2 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:

- name: Print some details about PHP
run: |
php -v
php -m
php -i | grep -A25 -i "gd support"

- name: Get composer cache directory
Expand Down
32 changes: 13 additions & 19 deletions classes/utils/Image.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,15 @@ abstract class Image

/**
* Create an instance of Image for given raw image data
*
* @param string $raw
*/
abstract public function __construct($raw);
abstract public function __construct(string $raw);

/**
* Create an instance of Image from given URL (file will be fetched via HTTP)
*
* @param string $url
* @return Image
* @throws Nano\Http\ResponseException
*/
public static function newFromUrl($url)
public static function newFromUrl(string $url): Image
{
$raw = Http::get($url);

Expand All @@ -41,11 +37,8 @@ public static function newFromUrl($url)

/**
* Create an instance of Image from given file
*
* @param string $file
* @return Image
*/
public static function newFromFile($file)
public static function newFromFile(string $file): Image
{
$raw = file_get_contents($file);

Expand All @@ -55,11 +48,9 @@ public static function newFromFile($file)
/**
* Create an instance of Image from raw image data
*
* @param string $raw
* @return Image
* @throws RuntimeException
*/
public static function newFromRaw($raw)
public static function newFromRaw(string $raw): Image
{
return self::getInstance($raw);
}
Expand All @@ -69,14 +60,17 @@ public static function newFromRaw($raw)
*
* Auto-detects which library to use: Imagick or GD
*
* @param string $raw
* @return Image
* @throws RuntimeException
*/
private static function getInstance($raw)
private static function getInstance(string $raw): Image
{
/**
* @see ImageGDTest::setUp
*/
global $NANO_FORCE_GD;

// Image Magick
if (class_exists('Imagick')) {
if (class_exists('Imagick') && empty($NANO_FORCE_GD)) {
$driverName = ImageImagick::class;
}
// fallback to GD
Expand All @@ -102,12 +96,12 @@ abstract public function crop($width, $height);
/**
* Return image raw data
*/
abstract public function render($type, $quality = false);
abstract public function render($type, int $quality = 75);

/**
* Save image raw data to a given file
*/
public function save($filename, $type, $quality = false)
public function save($filename, $type, int $quality = 75)
{
$raw = $this->render($type, $quality);

Expand Down
11 changes: 7 additions & 4 deletions classes/utils/ImageGD.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ class ImageGD extends Image

/**
* Create an instance of Image for given raw image data
*
* @throws Exception
*/
public function __construct($raw)
public function __construct(string $raw)
{
$this->img = imagecreatefromstring($raw);

Expand Down Expand Up @@ -149,14 +151,14 @@ public function crop($width, $height)
/**
* Return image raw data
*/
public function render($type, $quality = false)
public function render($type, int $quality = 75)
{
ob_start();

switch ($type) {
case 'jpeg':
$type = IMAGETYPE_JPEG;
imagejpeg($this->img, null, $quality ? $quality : 75);
imagejpeg($this->img, null, $quality);
break;

case 'gif':
Expand All @@ -166,10 +168,11 @@ public function render($type, $quality = false)

case 'png':
$type = IMAGETYPE_PNG;
imagepng($this->img, null, $quality ? $quality : 9);
imagepng($this->img, null, $quality);
break;

default:
ob_end_clean();
return false;
}

Expand Down
21 changes: 16 additions & 5 deletions classes/utils/ImageImagick.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ class ImageImagick extends Image

/**
* Create an instance of Image for given raw image data
* @throws Exception
*/
public function __construct($raw)
public function __construct(string $raw)
{
if (!class_exists('Imagick')) {
throw new Exception('imagick extension is not installed');
}

$this->img = new Imagick();
$res = $this->img->readImageBlob($raw);

Expand All @@ -27,8 +32,10 @@ public function __construct($raw)

/**
* Scale an image to fit given box and keeping proportions
*
* @throws ImagickException
*/
public function scale($width, $height)
public function scale($width, $height): bool
{
// calculate new dimension
// @see http://www.php.net/manual/en/imagick.scaleimage.php#93667
Expand All @@ -54,8 +61,10 @@ public function scale($width, $height)

/**
* Crop an image to fit given box
*
* @throws ImagickException
*/
public function crop($width, $height)
public function crop($width, $height): bool
{
// calculate scale-down ratio
$ratio = max($width / $this->width, $height / $this->height);
Expand Down Expand Up @@ -97,14 +106,16 @@ public function crop($width, $height)

/**
* Return image raw data
*
* @throws ImagickException
*/
public function render($type, $quality = false)
public function render($type, int $quality = 75)
{
switch ($type) {
case 'jpeg':
$type = IMAGETYPE_JPEG;
$this->img->setImageFormat('jpeg');
$this->img->setImageCompressionQuality($quality ? $quality : 75);
$this->img->setImageCompressionQuality($quality);
break;

case 'gif':
Expand Down
7 changes: 5 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
"Nano\\AppTests\\": "tests/app/tests"
}
},
"autoload-dev": {
"classmap": [ "tests/" ]
},
"scripts": {
"test": [
"phpunit"
"phpunit --verbose"
],
"coverage": [
"XDEBUG_MODE=coverage phpunit --coverage-html=.coverage --coverage-clover=.coverage.xml --coverage-text"
"XDEBUG_MODE=coverage phpunit --coverage-html=.coverage --coverage-clover=.coverage.xml --coverage-text --verbose"
],
"lint": [
"php-cs-fixer fix --config=.php-cs-fixer.php --dry-run --verbose",
Expand Down
29 changes: 29 additions & 0 deletions tests/ImageGDTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/**
* Set of unit tests for Image class (for GD)
*
* @covers ImageGD
*/
class ImageGDTest extends ImageTestBase
{
public function tearDown(): void
{
unset($GLOBALS['NANO_FORCE_GD']);
}

public function setUp(): void
{
/**
* @see Image::getInstance
*/
global $NANO_FORCE_GD;
$NANO_FORCE_GD = true;

if (!function_exists('gd_info')) {
$this->markTestSkipped('gd extension not installed');
}

parent::setUp();
}
}
18 changes: 18 additions & 0 deletions tests/ImageImagickTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

/**
* Set of unit tests for Image class (for Imagick)
*
* @covers ImageImagick
*/
class ImageImagickTest extends ImageTestBase
{
public function setUp(): void
{
if (!class_exists('Imagick')) {
$this->markTestSkipped('imagick extension not installed');
}

parent::setUp();
}
}
14 changes: 7 additions & 7 deletions tests/ImageTest.php → tests/ImageTestBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Set of unit tests for Image class
*/

class ImageTest extends \Nano\NanoBaseTest
abstract class ImageTestBase extends \Nano\NanoBaseTest
{

/* @var string $file */
Expand All @@ -15,14 +15,14 @@ class ImageTest extends \Nano\NanoBaseTest
public function setUp(): void
{
// 578x406
$this->file = dirname(__FILE__) . '/app/statics/php-logo.jpg';
$this->file = __DIR__ . '/app/statics/php-logo.jpg';
}

public function testNewFromFile()
{
$img = Image::newFromFile($this->file);

$this->assertInstanceOf('Image', $img);
$this->assertInstanceOf(Image::class, $img);
$this->assertEquals(578, $img->getWidth());
$this->assertEquals(406, $img->getHeight());
}
Expand All @@ -31,7 +31,7 @@ public function testScale()
{
$img = Image::newFromFile($this->file);

$this->assertInstanceOf('Image', $img);
$this->assertInstanceOf(Image::class, $img);

if (self::DEBUG) {
$img->save('img.jpg', 'jpeg');
Expand Down Expand Up @@ -62,7 +62,7 @@ public function testScale()
$this->assertTrue($img->scale(300, 410));

$this->assertEquals(300, $img->getWidth());
$this->assertEqualsWithDelta(211, $img->getHeight(), 2);
$this->assertEqualsWithDelta(211, $img->getHeight(), 2, 'This image should be 211 px high');

if (self::DEBUG) {
$img->save('img-scaled-bounding.jpg', 'jpeg');
Expand All @@ -73,7 +73,7 @@ public function testCrop()
{
$img = Image::newFromFile($this->file);

$this->assertInstanceOf('Image', $img);
$this->assertInstanceOf(Image::class, $img);

// scaling up no permitted
$this->assertFalse($img->crop(600, 500));
Expand Down Expand Up @@ -101,7 +101,7 @@ public function testCropAndResize()
{
$img = Image::newFromFile($this->file);

$this->assertInstanceOf('Image', $img);
$this->assertInstanceOf(Image::class, $img);

// crop
$this->assertTrue($img->crop(300, 100));
Expand Down