Skip to content

Commit 29f4837

Browse files
committed
Fix wonky gravity
1 parent fb19e35 commit 29f4837

3 files changed

Lines changed: 63 additions & 23 deletions

File tree

src/imagetransforms/ImageTransform.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class ImageTransform extends \craft\models\ImageTransform
7070
public ?float $gamma = null;
7171

7272
/**
73-
* @var 'auto'|'face'|'left'|'right'|'top'|'bottom'|array{x?: float, y?: float, mode?: 'remainder'|'box-center'}|null
73+
* @var 'auto'|'face'|'left'|'right'|'top'|'bottom'|array{x?: float, y?: float}|null
7474
*/
7575
public string|array|null $gravity = null;
7676

src/imagetransforms/ImageTransformer.php

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,48 @@ protected function applyAssetFocalPointGravity(Asset $asset, ImageTransform $ima
7070
return;
7171
}
7272

73+
$sourceWidth = $asset->getWidth();
74+
$sourceHeight = $asset->getHeight();
75+
$targetWidth = $imageTransform->width;
76+
$targetHeight = $imageTransform->height;
77+
78+
if (!$sourceWidth || !$sourceHeight || !$targetWidth || !$targetHeight) {
79+
$imageTransform->gravity = $asset->getFocalPoint();
80+
return;
81+
}
82+
7383
$focalPoint = $asset->getFocalPoint();
84+
$factor = min($sourceWidth / $targetWidth, $sourceHeight / $targetHeight);
85+
$newWidth = round($sourceWidth / $factor);
86+
$newHeight = round($sourceHeight / $factor);
87+
88+
$centerX = $newWidth * $focalPoint['x'];
89+
$centerY = $newHeight * $focalPoint['y'];
90+
$x1 = $centerX - $targetWidth / 2;
91+
$y1 = $centerY - $targetHeight / 2;
92+
$x2 = $x1 + $targetWidth;
93+
$y2 = $y1 + $targetHeight;
94+
95+
if ($x1 < 0) {
96+
$x2 -= $x1;
97+
$x1 = 0;
98+
}
99+
if ($y1 < 0) {
100+
$y2 -= $y1;
101+
$y1 = 0;
102+
}
103+
if ($x2 > $newWidth) {
104+
$x1 -= ($x2 - $newWidth);
105+
$x2 = $newWidth;
106+
}
107+
if ($y2 > $newHeight) {
108+
$y1 -= ($y2 - $newHeight);
109+
$y2 = $newHeight;
110+
}
111+
74112
$imageTransform->gravity = [
75-
'x' => $focalPoint['x'],
76-
'y' => $focalPoint['y'],
77-
'mode' => 'box-center',
113+
'x' => $newWidth > $targetWidth ? $x1 / ($newWidth - $targetWidth) : $focalPoint['x'],
114+
'y' => $newHeight > $targetHeight ? $y1 / ($newHeight - $targetHeight) : $focalPoint['y'],
78115
];
79116
}
80117

tests/unit/ImageTransformTest.php

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class ImageTransformTest extends Unit
1414
*/
1515
protected $tester;
1616

17-
public function testCropModeWithExplicitGravityModePreservesItInOptions(): void
17+
public function testCropModeWithExplicitGravityPreservesItInOptions(): void
1818
{
1919
$transform = new ImageTransform([
2020
'mode' => 'crop',
@@ -23,7 +23,6 @@ public function testCropModeWithExplicitGravityModePreservesItInOptions(): void
2323
'gravity' => [
2424
'x' => 0.57,
2525
'y' => 0.7707,
26-
'mode' => 'box-center',
2726
],
2827
]);
2928

@@ -32,7 +31,6 @@ public function testCropModeWithExplicitGravityModePreservesItInOptions(): void
3231
'gravity' => [
3332
'x' => 0.57,
3433
'y' => 0.7707,
35-
'mode' => 'box-center',
3634
],
3735
'height' => 750,
3836
'width' => 1200,
@@ -59,53 +57,58 @@ public function testCropModeWithoutGravityUsesPositionMapping(): void
5957
], $transform->toOptions());
6058
}
6159

62-
public function testFocalPointCropUsesBoxCenteredGravity(): void
60+
public function testCropModeMapsFocalPointToClampedCropOriginGravity(): void
6361
{
64-
$asset = $this->makeAssetStub(true, ['x' => 0.57, 'y' => 0.7707]);
62+
$asset = $this->makeAssetStub(3402, 4253, ['x' => 0.474, 'y' => 0.3064]);
6563
$transform = new ImageTransform([
6664
'mode' => 'crop',
65+
'position' => 'top-center',
6766
'width' => 1200,
6867
'height' => 750,
69-
'position' => 'top-center',
7068
]);
7169

7270
(new TestImageTransformer())->applyFocalPointGravity($asset, $transform);
7371

74-
$this->assertSame([
75-
'x' => 0.57,
76-
'y' => 0.7707,
77-
'mode' => 'box-center',
78-
], $transform->gravity);
72+
$this->assertEqualsWithDelta([
73+
'x' => 0.474,
74+
'y' => 0.1128,
75+
], $transform->gravity, 0.0001);
7976
}
8077

81-
private function makeAssetStub(bool $hasFocalPoint, array $focalPoint): Asset
78+
private function makeAssetStub(int $width, int $height, array $focalPoint): Asset
8279
{
83-
return new class($hasFocalPoint, $focalPoint) extends Asset {
84-
public function __construct(private bool $hasFocalPoint, private array $focalPoint)
80+
return new class($width, $height, $focalPoint) extends Asset {
81+
public function __construct(private int $widthValue, private int $heightValue, private array $focalPointValue)
8582
{
8683
parent::__construct();
8784
}
8885

8986
public function getHasFocalPoint(): bool
9087
{
91-
return $this->hasFocalPoint;
88+
return true;
9289
}
9390

9491
public function getFocalPoint(bool $asCss = false): array|string|null
9592
{
9693
if ($asCss) {
97-
return ($this->focalPoint['x'] * 100) . '% ' . ($this->focalPoint['y'] * 100) . '%';
94+
return ($this->focalPointValue['x'] * 100) . '% ' . ($this->focalPointValue['y'] * 100) . '%';
9895
}
9996

100-
return $this->focalPoint;
97+
return $this->focalPointValue;
10198
}
10299

103-
public function getMimeType(mixed $transform = null): ?string
100+
public function getWidth(array|string|\craft\models\ImageTransform $transform = null): ?int
104101
{
105-
return 'image/jpeg';
102+
return $this->widthValue;
103+
}
104+
105+
public function getHeight(mixed $transform = null): ?int
106+
{
107+
return $this->heightValue;
106108
}
107109
};
108110
}
111+
109112
}
110113

111114
class TestImageTransformer extends ImageTransformer

0 commit comments

Comments
 (0)