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'));
+ }
+}