diff --git a/docs/2.0/api/trim.md b/docs/2.0/api/trim.md new file mode 100644 index 00000000..7e8d03c1 --- /dev/null +++ b/docs/2.0/api/trim.md @@ -0,0 +1,52 @@ +--- +layout: default +title: Trim +--- + +# Trim + +## Trim `trim=top-left` + +Trims away image space in color at given position. + +~~~ html + +~~~ + +### Trim Base + +Sets the the point from where the trimming color is picked. + +### Accepts: + +- `top-left`: Default. +- `buttom-right` +- `transparent` + +~~~ html + +~~~ + +### Trim Away + +Sets which borders should be trimmed away. Defined by the first letter of each side; `t`, `b`, `l`, `r` (top, bottom, left, light). Default is all sides. + +~~~ html + +~~~ + +### Trim Tolerance + +Sets tolerance level in percent to trim similar colors. Default is `0`. + +~~~ html + +~~~ + +### Trim Feather + +Sets the border around the object, in pixels. Can be a positive value, to expand the border, or negative, to contract the border. Default is `0`. + +~~~ html + +~~~ \ No newline at end of file diff --git a/src/Manipulators/Trim.php b/src/Manipulators/Trim.php new file mode 100644 index 00000000..7d392249 --- /dev/null +++ b/src/Manipulators/Trim.php @@ -0,0 +1,139 @@ +getTrim()) { + list($base, $away, $tolerance, $feather) = $trim; + return $image->trim($base, $away, $tolerance, $feather); + } + + return $image; + } + + /** + * Resolve trim. + * + * @return array|null The resolved trim. + */ + public function getTrim() + { + if (!$this->trim) { + return; + } + + $values = explode(',', $this->trim); + + $base = $this->getBase(isset($values[0]) ? $values[0] : null); + $away = $this->getAway(isset($values[1]) ? $values[1] : null); + $tolerance = $this->getTolerance(isset($values[2]) ? $values[2] : null); + $feather = $this->getFeather(isset($values[3]) ? $values[3] : null); + + return [$base, $away, $tolerance, $feather]; + } + + /** + * Resolve the base. + * + * @param string $base The raw base. + * + * @return string The resolved base. + */ + public function getBase($base) + { + if (!in_array($base, ['top-left', 'bottom-right', 'transparent'], true)) { + return 'top-left'; + } + + return $base; + } + + /** + * Resolve the away. + * + * @param string $away The raw away. + * + * @return array|null The resolved away array. + */ + public function getAway($away) + { + if (null === $away || preg_match('/[^tblr]/', $away)) { + return; + } + + $aways = []; + + if (strpos($away, 't') !== false) { + $aways[] = 'top'; + } + + if (strpos($away, 'b') !== false) { + $aways[] = 'bottom'; + } + + if (strpos($away, 'l') !== false) { + $aways[] = 'left'; + } + + if (strpos($away, 'r') !== false) { + $aways[] = 'right'; + } + + if (empty($aways)) { + return; + } + + return $aways; + } + + /** + * Resolve the tolerance. + * + * @param string $tolerance The raw tolerance. + * + * @return int|null The resolved tolerance. + */ + public function getTolerance($tolerance) + { + if (!is_numeric($tolerance)) { + return; + } + + if ($tolerance < 0 or $tolerance > 100) { + return; + } + + return (int) $tolerance; + } + + /** + * Resolve the feather. + * + * @param string $feather The raw feather. + * + * @return int|null The resolved feather. + */ + public function getFeather($feather) + { + if (!is_numeric($feather)) { + return; + } + + return (int) $feather; + } +} diff --git a/src/ServerFactory.php b/src/ServerFactory.php index 3dbf987c..55c8ec35 100644 --- a/src/ServerFactory.php +++ b/src/ServerFactory.php @@ -22,6 +22,7 @@ use League\Glide\Manipulators\Pixelate; use League\Glide\Manipulators\Sharpen; use League\Glide\Manipulators\Size; +use League\Glide\Manipulators\Trim; use League\Glide\Manipulators\Watermark; use League\Glide\Responses\ResponseFactoryInterface; @@ -269,6 +270,7 @@ public function getManipulators() new Filter(), new Flip(), new Blur(), + new Trim(), new Pixelate(), new Watermark($this->getWatermarks(), $this->getWatermarksPathPrefix() ?: ''), new Background(), diff --git a/tests/Manipulators/TrimTest.php b/tests/Manipulators/TrimTest.php new file mode 100644 index 00000000..7743c6db --- /dev/null +++ b/tests/Manipulators/TrimTest.php @@ -0,0 +1,109 @@ +manipulator = new Trim(); + } + + public function tearDown(): void + { + Mockery::close(); + } + + public function testCreateInstance() + { + $this->assertInstanceOf('League\Glide\Manipulators\Trim', new Trim()); + } + + public function testRun() + { + $image = Mockery::mock('Intervention\Image\Image', function ($mock) { + $mock->shouldReceive('trim')->andReturn($mock)->with('top-left', ['top', 'bottom', 'left', 'right'], 20, 10)->once(); + $mock->shouldReceive('trim')->andReturn($mock)->with('top-left', null, null, null)->once(); + }); + + $this->assertInstanceOf( + 'Intervention\Image\Image', + $this->manipulator->setParams(['trim' => 'top-left,trbl,20,10'])->run($image) + ); + + $this->assertInstanceOf( + 'Intervention\Image\Image', + $this->manipulator->setParams(['trim' => 'invalid,invalid,150,invalid'])->run($image) + ); + } + + public function testGetTrim() + { + $this->assertSame( + ['top-left', ['top', 'bottom', 'left', 'right'], 20, 10], + $this->manipulator->setParams(['trim' => 'top-left,trbl,20,10'])->getTrim() + ); + + $this->assertSame( + ['top-left', null, null, null], + $this->manipulator->setParams(['trim' => 'invalid,invalid,150,invalid'])->getTrim() + ); + + $this->assertSame( + ['top-left', null, 0, 0], + $this->manipulator->setParams(['trim' => 'top-left,,0,0'])->getTrim() + ); + } + + public function testGetBase() + { + $this->assertSame('top-left', $this->manipulator->getBase('top-left')); + $this->assertSame('bottom-right', $this->manipulator->getBase('bottom-right')); + $this->assertSame('transparent', $this->manipulator->getBase('transparent')); + $this->assertSame('top-left', $this->manipulator->getBase(null)); + $this->assertSame('top-left', $this->manipulator->getBase(123)); + } + + public function testGetAway() + { + $this->assertSame(['top', 'bottom', 'left', 'right'], $this->manipulator->getAway('tblr')); + $this->assertSame(['top', 'bottom', 'left'], $this->manipulator->getAway('tbl')); + $this->assertSame(['top', 'bottom'], $this->manipulator->getAway('tb')); + $this->assertSame(['top'], $this->manipulator->getAway('t')); + $this->assertSame(['bottom', 'left'], $this->manipulator->getAway('bl')); + $this->assertSame(['top', 'right'], $this->manipulator->getAway('tr')); + $this->assertSame(['top', 'bottom', 'left', 'right'], $this->manipulator->getAway('rlbt')); + $this->assertSame(['top', 'bottom', 'left', 'right'], $this->manipulator->getAway('rrllbbtt')); + $this->assertSame(null, $this->manipulator->getAway('invalid')); + $this->assertSame(null, $this->manipulator->getAway(null)); + $this->assertSame(null, $this->manipulator->getAway(123)); + } + + public function testTolerance() + { + $this->assertSame(20, $this->manipulator->getTolerance(20)); + $this->assertSame(20, $this->manipulator->getTolerance('20')); + $this->assertSame(0, $this->manipulator->getTolerance('0')); + $this->assertSame(100, $this->manipulator->getTolerance('100')); + $this->assertSame(null, $this->manipulator->getTolerance('150')); + $this->assertSame(null, $this->manipulator->getTolerance('-150')); + $this->assertSame(null, $this->manipulator->getTolerance('invalid')); + } + + public function testFeather() + { + $this->assertSame(20, $this->manipulator->getFeather(20)); + $this->assertSame(-20, $this->manipulator->getFeather(-20)); + $this->assertSame(20, $this->manipulator->getFeather('20')); + $this->assertSame(0, $this->manipulator->getFeather('0')); + $this->assertSame(100, $this->manipulator->getFeather('100')); + $this->assertSame(150, $this->manipulator->getFeather('150')); + $this->assertSame(-150, $this->manipulator->getFeather('-150')); + $this->assertSame(null, $this->manipulator->getFeather('invalid')); + } +}