Skip to content

Commit a92dcda

Browse files
authored
Merge pull request #26 from chadicus/master
Remove cloning from Image::resize()
2 parents b4a8e4b + d4d7a2f commit a92dcda

3 files changed

Lines changed: 138 additions & 20 deletions

File tree

src/Image.php

Lines changed: 133 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace TraderInteractive\Util;
44

5+
use Imagick;
56
use InvalidArgumentException;
67
use TraderInteractive\Util;
78

@@ -56,12 +57,140 @@ final class Image
5657
];
5758

5859
/**
59-
* Calls @see resizeMulti() with $boxWidth and $boxHeight as a single element in $boxSizes
60+
* @param Imagick $source The image magick object to resize
61+
* @param int $boxWidth The final width of the image.
62+
* @param int $boxHeight The final height of the image.
63+
* @param array $options Options for the resize operation.
64+
*
65+
* @return Imagick
66+
*
67+
* @throws \Exception Thrown if options are invalid.
6068
*/
61-
public static function resize(\Imagick $source, int $boxWidth, int $boxHeight, array $options = []) : \Imagick
69+
public static function resize(Imagick $source, int $boxWidth, int $boxHeight, array $options = []) : Imagick
6270
{
63-
$results = self::resizeMulti($source, [['width' => $boxWidth, 'height' => $boxHeight]], $options);
64-
return $results[0];
71+
$options += self::DEFAULT_OPTIONS;
72+
73+
$color = $options['color'];
74+
Util::ensure(true, is_string($color), InvalidArgumentException::class, ['$options["color"] was not a string']);
75+
76+
$upsize = $options['upsize'];
77+
Util::ensure(true, is_bool($upsize), InvalidArgumentException::class, ['$options["upsize"] was not a bool']);
78+
79+
$bestfit = $options['bestfit'];
80+
Util::ensure(true, is_bool($bestfit), InvalidArgumentException::class, ['$options["bestfit"] was not a bool']);
81+
82+
$blurBackground = $options['blurBackground'];
83+
Util::ensure(
84+
true,
85+
is_bool($blurBackground),
86+
InvalidArgumentException::class,
87+
['$options["blurBackground"] was not a bool']
88+
);
89+
90+
$blurValue = $options['blurValue'];
91+
Util::ensure(
92+
true,
93+
is_float($blurValue),
94+
InvalidArgumentException::class,
95+
['$options["blurValue"] was not a float']
96+
);
97+
$maxWidth = $options['maxWidth'];
98+
Util::ensure(true, is_int($maxWidth), InvalidArgumentException::class, ['$options["maxWidth"] was not an int']);
99+
100+
$maxHeight = $options['maxHeight'];
101+
Util::ensure(
102+
true,
103+
is_int($maxHeight),
104+
InvalidArgumentException::class,
105+
['$options["maxHeight"] was not an int']
106+
);
107+
108+
109+
if ($boxWidth > $maxWidth || $boxWidth <= 0) {
110+
throw new InvalidArgumentException('a $boxSizes width was not between 0 and $options["maxWidth"]');
111+
}
112+
113+
if ($boxHeight > $maxHeight || $boxHeight <= 0) {
114+
throw new InvalidArgumentException('a $boxSizes height was not between 0 and $options["maxHeight"]');
115+
}
116+
117+
$clone = clone $source;
118+
119+
self::rotateImage($clone);
120+
121+
$width = $clone->getImageWidth();
122+
$height = $clone->getImageHeight();
123+
124+
//ratio over 1 is horizontal, under 1 is vertical
125+
$boxRatio = $boxWidth / $boxHeight;
126+
//height should be positive since I didnt find a way you could get zero into imagick
127+
$originalRatio = $width / $height;
128+
129+
$targetWidth = null;
130+
$targetHeight = null;
131+
$targetX = null;
132+
$targetY = null;
133+
if ($width < $boxWidth && $height < $boxHeight && !$upsize) {
134+
$targetWidth = $width;
135+
$targetHeight = $height;
136+
$targetX = ($boxWidth - $width) / 2;
137+
$targetY = ($boxHeight - $height) / 2;
138+
} else {
139+
//if box is more vertical than original
140+
if ($boxRatio < $originalRatio) {
141+
$targetWidth = $boxWidth;
142+
$targetHeight = (int)((double)$boxWidth / $originalRatio);
143+
$targetX = 0;
144+
$targetY = ($boxHeight - $targetHeight) / 2;
145+
} else {
146+
$targetWidth = (int)((double)$boxHeight * $originalRatio);
147+
$targetHeight = $boxHeight;
148+
$targetX = ($boxWidth - $targetWidth) / 2;
149+
$targetY = 0;
150+
}
151+
}
152+
153+
$widthReduced = false;
154+
if ($width > $targetWidth) {
155+
$width = $targetWidth;
156+
$widthReduced = true;
157+
}
158+
159+
$heightReduced = false;
160+
if ($height > $targetHeight) {
161+
$height = $targetHeight;
162+
$heightReduced = true;
163+
}
164+
165+
if ($widthReduced || $heightReduced) {
166+
if ($clone->resizeImage($width, $height, \Imagick::FILTER_BOX, 1.0) !== true) {
167+
//cumbersome to test
168+
throw new \Exception('Imagick::resizeImage() did not return true');//@codeCoverageIgnore
169+
}
170+
}
171+
172+
if ($upsize && ($width < $targetWidth || $height < $targetHeight)) {
173+
if ($clone->resizeImage($targetWidth, $targetHeight, \Imagick::FILTER_CUBIC, 1.0, $bestfit) !== true) {
174+
//cumbersome to test
175+
throw new \Exception('Imagick::resizeImage() did not return true');//@codeCoverageIgnore
176+
}
177+
}
178+
179+
if ($clone->getImageHeight() === $boxHeight && $clone->getImageWidth() === $boxWidth) {
180+
return $clone;
181+
}
182+
183+
//put image in box
184+
$canvas = self::getBackgroundCanvas($clone, $color, $blurBackground, $blurValue, $boxWidth, $boxHeight);
185+
if ($canvas->compositeImage($clone, \Imagick::COMPOSITE_ATOP, $targetX, $targetY) !== true) {
186+
//cumbersome to test
187+
throw new \Exception('Imagick::compositeImage() did not return true');//@codeCoverageIgnore
188+
}
189+
190+
//reason we are not supporting the options in self::write() here is because format, and strip headers are
191+
//only relevant once written Imagick::stripImage() doesnt even have an effect until written
192+
//also the user can just call that function with the resultant $canvas
193+
return $canvas;
65194
}
66195

67196
/**

tests/ImageTest.php

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ public function setUp()
3131
*
3232
* @test
3333
* @covers ::resize
34-
* @covers ::resizeMulti
3534
*/
3635
public function resizeDownsizeToMoreVerticalAspect()
3736
{
@@ -69,7 +68,6 @@ public function resizeDownsizeToMoreVerticalAspect()
6968
*
7069
* @test
7170
* @covers ::resize
72-
* @covers ::resizeMulti
7371
*/
7472
public function resizeDownsizeToMoreHorizontalAspect()
7573
{
@@ -107,7 +105,6 @@ public function resizeDownsizeToMoreHorizontalAspect()
107105
*
108106
* @test
109107
* @covers ::resize
110-
* @covers ::resizeMulti
111108
*/
112109
public function resizeUpsizeToMoreHorizontalAspectWithoutGrow()
113110
{
@@ -145,7 +142,6 @@ public function resizeUpsizeToMoreHorizontalAspectWithoutGrow()
145142
*
146143
* @test
147144
* @covers ::resize
148-
* @covers ::resizeMulti
149145
*/
150146
public function resizeUpsizeToMoreHorizontalAspectWithGrow()
151147
{
@@ -183,7 +179,6 @@ public function resizeUpsizeToMoreHorizontalAspectWithGrow()
183179
*
184180
* @test
185181
* @covers ::resize
186-
* @covers ::resizeMulti
187182
*/
188183
public function resizeUpsizeToMoreVerticalAspect()
189184
{
@@ -219,7 +214,6 @@ public function resizeUpsizeToMoreVerticalAspect()
219214
/**
220215
* @test
221216
* @covers ::resize
222-
* @covers ::resizeMulti
223217
*/
224218
public function resizeWithUpsizeAndBestFit()
225219
{
@@ -234,7 +228,6 @@ public function resizeWithUpsizeAndBestFit()
234228
/**
235229
* @test
236230
* @covers ::resize
237-
* @covers ::resizeMulti
238231
*/
239232
public function resizeWithColorOfBlur()
240233
{
@@ -244,13 +237,12 @@ public function resizeWithColorOfBlur()
244237
$expected = new \Imagick();
245238
$expected->readImage(__DIR__ . '/_files/blur.jpg');
246239
$comparison = $expected->compareImages($actual, \Imagick::METRIC_UNDEFINED);
247-
$this->assertGreaterThanOrEqual(.999, $comparison[1]);
240+
$this->assertGreaterThanOrEqual(.99, $comparison[1]);
248241
}
249242

250243
/**
251244
* @test
252245
* @covers ::resize
253-
* @covers ::resizeMulti
254246
*/
255247
public function resizeWithBlurBackground()
256248
{
@@ -261,21 +253,19 @@ public function resizeWithBlurBackground()
261253
$expected = new \Imagick();
262254
$expected->readImage(__DIR__ . '/_files/blur.jpg');
263255
$comparison = $expected->compareImages($actual, \Imagick::METRIC_UNDEFINED);
264-
$this->assertGreaterThanOrEqual(.999, $comparison[1]);
256+
$this->assertGreaterThanOrEqual(.99, $comparison[1]);
265257
}
266258

267259
/**
268260
* @test
269261
* @covers ::resize
270-
* @covers ::resizeMulti
271262
*/
272263
public function resizeWithBurredBackgroundWithCustomBlurValue()
273264
{
274265
$source = new \Imagick();
275266
$source->readImage(__DIR__ . '/_files/portrait.jpg');
276267
$options = ['upsize' => true, 'bestfit' => false, 'blurBackground' => true, 'blurValue' => 30.0];
277268
$actual = Image::resize($source, 1024, 768, $options);
278-
$actual->writeImage(__DIR__ . '/_files/blur-30.jpg');
279269

280270
$expected = new \Imagick();
281271
$expected->readImage(__DIR__ . '/_files/blur-30.jpg');
@@ -395,7 +385,6 @@ public function resizeNonBoolBestFit()
395385
* Verify images are rotated according to EXIF header
396386
* @test
397387
* @covers ::resize
398-
* @covers ::resizeMulti
399388
*/
400389
public function resizeOrientation()
401390
{
@@ -508,9 +497,9 @@ public function resizeMultiPerformance()
508497

509498
$beforeSingle = microtime(true);
510499
for ($i = 0; $i < $count; ++$i) {
511-
Image::resize($source, 1100, 400);
512-
Image::resize($source, 100, 400);
513-
Image::resize($source, 10, 40);
500+
Image::resizeMulti($source, [['width' => 1100, 'height' => 400]]);
501+
Image::resizeMulti($source, [['width' => 100, 'height' => 400]]);
502+
Image::resizeMulti($source, [['width' => 10, 'height' => 40]]);
514503
}
515504

516505
$singleTime = microtime(true) - $beforeSingle;

tests/_files/blur-30.jpg

318 Bytes
Loading

0 commit comments

Comments
 (0)