'test_gif.gif', 'jpg' => 'test_jpg.jpg', 'png8' => 'test_png8.png', 'png32' => 'test_png32.png' ); public function setUp() { parent::setUp(); GDBackend::flush(); } public function tearDown() { GDBackend::flush(); parent::tearDown(); } /** * Loads all images into an associative array of GD objects. * Optionally applies an operation to each GD * * @param callable $callback Action to perform on each GD * @return array List of GD */ protected function applyToEachImage($callback = null) { $gds = array(); foreach (self::$filenames as $type => $file) { $fullPath = realpath(__DIR__ . '/GDTest/images/' . $file); $gd = new GDBackend(); $gd->loadFrom($fullPath); if ($callback) { $gd = $callback($gd); } $gds[$type] = $gd; } return $gds; } /** * Takes samples from the given GD at 5 pixel increments * * @param GDBackend $gd The source image * @param integer $horizontal Number of samples to take horizontally * @param integer $vertical Number of samples to take vertically * @return array List of colours for each sample, each given as an associative * array with red, blue, green, and alpha components */ protected function sampleAreas(GDBackend $gd, $horizontal = 4, $vertical = 4) { $samples = array(); for ($y = 0; $y < $vertical; $y++) { for ($x = 0; $x < $horizontal; $x++) { $colour = imagecolorat($gd->getImageResource(), $x * 5, $y * 5); $samples[] = imagecolorsforindex($gd->getImageResource(), $colour); } } return $samples; } /** * Asserts that two colour channels are equivalent within a given tolerance range * * @param integer $expected * @param integer $actual * @param integer $tolerance */ protected function assertColourEquals($expected, $actual, $tolerance = 0) { $match = ($expected + $tolerance >= $actual) && ($expected - $tolerance <= $actual); $this->assertTrue($match); } /** * Asserts that all samples given correctly correspond to a greyscale version * of the test image pattern * * @param array $samples List of 16 colour samples representing each of the 8 x 8 squares on the image pattern * 8 x 8 squares on the image pattern * @param int $alphaBits Depth of alpha channel in bits * @param int $tolerance Reasonable tolerance level for colour comparison */ protected function assertGreyscale($samples, $alphaBits = 0, $tolerance = 0) { // Check that all colour samples match foreach ($samples as $sample) { $matches = ($sample['red'] === $sample['green']) && ($sample['blue'] === $sample['green']); $this->assertTrue($matches, 'Assert colour is greyscale'); if (!$matches) { return; } } // check various sample points $this->assertColourEquals(76, $samples[0]['red'], $tolerance); $this->assertColourEquals(149, $samples[2]['red'], $tolerance); $this->assertColourEquals(0, $samples[8]['red'], $tolerance); $this->assertColourEquals(127, $samples[9]['red'], $tolerance); // check alpha of various points switch ($alphaBits) { case 0: $this->assertColourEquals(0, $samples[2]['alpha'], $tolerance); $this->assertColourEquals(0, $samples[12]['alpha'], $tolerance); break; case 1: $this->assertColourEquals(0, $samples[2]['alpha'], $tolerance); $this->assertColourEquals(127, $samples[12]['alpha'], $tolerance); break; default: $this->assertColourEquals(63, $samples[2]['alpha'], $tolerance); $this->assertColourEquals(127, $samples[12]['alpha'], $tolerance); break; } } /** * Tests that images are correctly transformed to greyscale */ function testGreyscale() { // Apply greyscaling to each image $images = $this->applyToEachImage( function (GDBackend $gd) { return $gd->greyscale(); } ); // Test GIF (256 colour, transparency) $samplesGIF = $this->sampleAreas($images['gif']); $this->assertGreyscale($samplesGIF, 1); // Test JPG $samplesJPG = $this->sampleAreas($images['jpg']); $this->assertGreyscale($samplesJPG, 0, 4); // Test PNG 8 (indexed with alpha transparency) $samplesPNG8 = $this->sampleAreas($images['png8']); $this->assertGreyscale($samplesPNG8, 8, 4); // Test PNG 32 (full alpha transparency) $samplesPNG32 = $this->sampleAreas($images['png32']); $this->assertGreyscale($samplesPNG32, 8); } /** * Tests that GD doesn't attempt to load images when they're deemed unavailable * * @return void */ public function testImageSkippedWhenUnavailable() { $fullPath = realpath(__DIR__ . '/GDTest/images/test_jpg.jpg'); $gd = new GDTest\ImageUnavailable(); $gd->loadFrom($fullPath); /* Ensure no image resource is created if the image is unavailable */ $this->assertNull($gd->getImageResource()); } /** * Tests the integrity of the manipulation cache when an error occurs */ public function testCacheIntegrity() { $fullPath = realpath(__DIR__ . '/GDTest/images/nonimagedata.jpg'); // Load invalid file $gd = new GDBackend(); $gd->loadFrom($fullPath); // Cache should refer to this file $cache = Injector::inst()->get(CacheInterface::class . '.GDBackend_Manipulations'); $key = sha1(implode('|', array($fullPath, filemtime($fullPath)))); $data = $cache->get($key); $this->assertEquals('1', $data); } /** * Test that GD::failedResample() returns true for the current image * manipulation only if it previously failed * * @return void */ public function testFailedResample() { $fullPath = realpath(__DIR__ . '/GDTest/images/nonimagedata.jpg'); $fullPath2 = realpath(__DIR__ . '/GDTest/images/test_gif.gif'); // Load invalid file $gd = new GDBackend(); $gd->loadFrom($fullPath); // Cache should refre to this file $this->assertTrue($gd->failedResample($fullPath, filemtime($fullPath))); $this->assertFalse($gd->failedResample($fullPath2, filemtime($fullPath2))); } }