Skip to content

Commit db41297

Browse files
authored
Re-activate shapefile image test (#27)
* Test again the image difference test for shapefile * Migrate phpunit configuration to new schema
1 parent 7e7feea commit db41297

3 files changed

Lines changed: 223 additions & 56 deletions

File tree

phpunit.xml.dist

Lines changed: 20 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit bootstrap="vendor/autoload.php"
3-
colors="true"
4-
convertErrorsToExceptions="true"
5-
convertNoticesToExceptions="true"
6-
convertWarningsToExceptions="true"
7-
processIsolation="false"
8-
stopOnFailure="true"
9-
>
10-
<testsuites>
11-
<testsuite name="Integration">
12-
<directory suffix="Test.php">./tests/Integration</directory>
13-
</testsuite>
14-
<testsuite name="Unit">
15-
<directory suffix="Test.php">./tests/Unit</directory>
16-
</testsuite>
17-
</testsuites>
18-
<php>
19-
<env name="GEOSERVER_URL" value=""/>
20-
<env name="GEOSERVER_USER" value=""/>
21-
<env name="GEOSERVER_PASSWORD" value=""/>
22-
<env name="GEOSERVER_WORKSPACE" value="test"/>
23-
</php>
24-
<filter>
25-
<!-- <blacklist>
26-
<directory>vendor</directory>
27-
<directory>test</directory>
28-
</blacklist> -->
29-
<whitelist>
30-
<directory>src</directory>
31-
</whitelist>
32-
</filter>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" colors="true" convertErrorsToExceptions="true" convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false" stopOnFailure="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
3+
<coverage>
4+
<include>
5+
<directory>src</directory>
6+
</include>
7+
</coverage>
8+
<testsuites>
9+
<testsuite name="Integration">
10+
<directory suffix="Test.php">./tests/Integration</directory>
11+
</testsuite>
12+
<testsuite name="Unit">
13+
<directory suffix="Test.php">./tests/Unit</directory>
14+
</testsuite>
15+
</testsuites>
16+
<php>
17+
<env name="GEOSERVER_URL" value=""/>
18+
<env name="GEOSERVER_USER" value=""/>
19+
<env name="GEOSERVER_PASSWORD" value=""/>
20+
<env name="GEOSERVER_WORKSPACE" value="test"/>
21+
</php>
3322
</phpunit>

tests/Integration/GeoServerWmsTest.php

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
use OneOffTech\GeoServer\Support\ImageResponse;
3333
use OneOffTech\GeoServer\Exception\InvalidDataException;
3434
use OneOffTech\GeoServer\Exception\ErrorResponseException;
35+
use Tests\Support\ImageDifference;
3536

3637
class GeoServerWmsTest extends TestCase
3738
{
@@ -76,39 +77,37 @@ public function test_wms_url_is_generated_for_geotiff()
7677
}
7778

7879

79-
// public function test_shapefile_thumbnail()
80-
// {
81-
// $datastoreName = 'shapefile_test';
82-
// $file = GeoFile::from(__DIR__ . '/../fixtures/shapefile.shp')->name($datastoreName);
83-
84-
// $resource = $this->geoserver->upload($file);
85-
86-
// $thumbnail = $this->geoserver->thumbnail($resource);
87-
88-
// $this->assertInstanceOf(ImageResponse::class, $thumbnail);
89-
// $this->assertEquals('image/png', $thumbnail->mimeType());
80+
public function test_shapefile_thumbnail()
81+
{
82+
$datastoreName = 'shapefile_test';
83+
$file = GeoFile::from(__DIR__ . '/../fixtures/shapefile.shp')->name($datastoreName);
9084

91-
// $imageAsString = $thumbnail->asString();
85+
$resource = $this->geoserver->upload($file);
9286

93-
// list($width, $height) = getimagesizefromstring($imageAsString);
87+
$thumbnail = $this->geoserver->thumbnail($resource);
9488

95-
// $this->assertEquals(300, $width);
96-
// $this->assertEquals(300, $height);
89+
$this->assertInstanceOf(ImageResponse::class, $thumbnail);
90+
$this->assertEquals('image/png', $thumbnail->mimeType());
9791

98-
// // compare the image difference against a reference thumbnail
92+
$imageAsString = $thumbnail->asString();
9993

100-
// $image1 = new Image(__DIR__ . '/../fixtures/shapefile_thumbnail.png');
94+
list($width, $height) = getimagesizefromstring($imageAsString);
10195

102-
// file_put_contents(__DIR__ . '/../fixtures/shapefile_thumbnail_from_geoserver.png', $thumbnail->asString());
96+
$this->assertEquals(300, $width);
97+
$this->assertEquals(300, $height);
10398

104-
// $image2 = new Image(__DIR__ . '/../fixtures/shapefile_thumbnail_from_geoserver.png');
99+
// compare the image difference against a reference thumbnail
105100

106-
// $difference = $image1->difference($image2, new EuclideanDistance());
101+
file_put_contents(__DIR__ . '/../fixtures/shapefile_thumbnail_from_geoserver.png', $thumbnail->asString());
102+
103+
$differencePercentage = ImageDifference::calculate(
104+
__DIR__ . '/../fixtures/shapefile_thumbnail.png',
105+
__DIR__ . '/../fixtures/shapefile_thumbnail_from_geoserver.png');
107106

108-
// unlink(__DIR__ . '/../fixtures/shapefile_thumbnail_from_geoserver.png');
109-
// $deleteResult = $this->geoserver->remove($file);
107+
unlink(__DIR__ . '/../fixtures/shapefile_thumbnail_from_geoserver.png');
108+
$deleteResult = $this->geoserver->remove($file);
110109

111-
// // considering a 20% difference as acceptable
112-
// $this->assertTrue($difference->percentage() < 20);
113-
// }
110+
// considering a 20% difference as acceptable
111+
$this->assertTrue($differencePercentage < 20);
112+
}
114113
}

tests/Support/ImageDifference.php

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
<?php
2+
/*
3+
* GeoServer PHP Client
4+
*
5+
* Copyright (c) 2018 Oneoff-tech UG, Germany, www.oneofftech.xyz
6+
*
7+
* This program is Free Software: you can redistribute it and/or modify
8+
* it under the terms of the GNU Affero General Public License as
9+
* published by the Free Software Foundation, either version 3 of the
10+
* License, or (at your option) any later version.
11+
*
12+
* This program is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU Affero General Public
18+
* License along with this program. If not, see
19+
* <http://www.gnu.org/licenses/>.
20+
*/
21+
22+
namespace Tests\Support;
23+
24+
use InvalidArgumentException;
25+
26+
class ImageDifference
27+
{
28+
29+
/**
30+
* Calculate the difference between two images
31+
*
32+
* @param string $expected The path of the image ground truth
33+
* @param string $actual The actual image to compare
34+
* @return float the percentage of difference between the two images
35+
*/
36+
public static function calculate($expected, $actual)
37+
{
38+
list($expectedImage, $expectedImagewidth, $expectedImageHeight) = static::imageFromFile($expected);
39+
40+
list($actualImage) = static::imageFromFile($actual);
41+
42+
$differenceBitmap = static::calculateDifference(
43+
$expectedImage, $actualImage, $expectedImagewidth, $expectedImageHeight
44+
);
45+
46+
return static::calculateDifferencePercentage($differenceBitmap, $expectedImagewidth, $expectedImageHeight);
47+
}
48+
49+
/**
50+
* Load a bitmap array from image path.
51+
*
52+
* @param string $path
53+
*
54+
* @return array
55+
*
56+
* @throws InvalidArgumentException
57+
*/
58+
private static function imageFromFile($path)
59+
{
60+
$info = getimagesize($path);
61+
$type = $info[2];
62+
63+
$image = null;
64+
65+
if ($type == IMAGETYPE_JPEG) {
66+
$image = imagecreatefromjpeg($path);
67+
}
68+
if ($type == IMAGETYPE_GIF) {
69+
$image = imagecreatefromgif($path);
70+
}
71+
if ($type == IMAGETYPE_PNG) {
72+
$image = imagecreatefrompng($path);
73+
}
74+
75+
if (!$image) {
76+
throw new InvalidArgumentException("invalid image [{$path}]");
77+
}
78+
79+
$width = imagesx($image);
80+
$height = imagesy($image);
81+
82+
$bitmap = [];
83+
84+
for ($y = 0; $y < $height; $y++) {
85+
$bitmap[$y] = [];
86+
87+
for ($x = 0; $x < $width; $x++) {
88+
$color = imagecolorat($image, $x, $y);
89+
90+
$bitmap[$y][$x] = [
91+
"r" => ($color >> 16) & 0xFF,
92+
"g" => ($color >> 8) & 0xFF,
93+
"b" => $color & 0xFF
94+
];
95+
}
96+
}
97+
98+
return [$bitmap, $width, $height];
99+
}
100+
101+
/**
102+
* Difference between all pixels of two images.
103+
*
104+
* @param array $bitmap1
105+
* @param array $bitmap2
106+
* @param int $width
107+
* @param int $height
108+
*
109+
* @return array
110+
*/
111+
private static function calculateDifference(array $bitmap1, array $bitmap2, $width, $height)
112+
{
113+
$new = [];
114+
115+
for ($y = 0; $y < $height; $y++) {
116+
$new[$y] = [];
117+
118+
for ($x = 0; $x < $width; $x++) {
119+
$new[$y][$x] = static::euclideanDistance(
120+
$bitmap1[$y][$x],
121+
$bitmap2[$y][$x]
122+
);
123+
}
124+
}
125+
126+
return $new;
127+
}
128+
129+
/**
130+
* RGB color distance for the same pixel in two images.
131+
*
132+
* @link https://en.wikipedia.org/wiki/Euclidean_distance
133+
*
134+
* @param array $p
135+
* @param array $q
136+
*
137+
* @return float
138+
*/
139+
private static function euclideanDistance(array $p, array $q)
140+
{
141+
$r = $p["r"] - $q["r"];
142+
$r *= $r;
143+
144+
$g = $p["g"] - $q["g"];
145+
$g *= $g;
146+
147+
$b = $p["b"] - $q["b"];
148+
$b *= $b;
149+
150+
return (float) sqrt($r + $g + $b);
151+
}
152+
153+
/**
154+
* Percentage of different pixels in the bitmap.
155+
*
156+
* @param array $bitmap
157+
* @param int $width
158+
* @param int $height
159+
*
160+
* @return float
161+
*/
162+
private static function calculateDifferencePercentage(array $bitmap, $width, $height)
163+
{
164+
$total = 0;
165+
$different = 0;
166+
167+
for ($y = 0; $y < $height; $y++) {
168+
for ($x = 0; $x < $width; $x++) {
169+
$total++;
170+
171+
if ($bitmap[$y][$x] > 0) {
172+
$different++;
173+
}
174+
}
175+
}
176+
177+
return (float) (($different / $total) * 100);
178+
}
179+
}

0 commit comments

Comments
 (0)