mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #1318 from tractorcow/3.1-api-image-resampling-compatible
API Better detection and prevention of image resampling
This commit is contained in:
commit
88d77db9e0
186
model/Image.php
186
model/Image.php
@ -192,30 +192,61 @@ class Image extends File {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function SetWidth($width) {
|
/**
|
||||||
return $this->getWidth() == $width ? $this : $this->getFormattedImage('SetWidth', $width);
|
* Resize the image by preserving aspect ratio, keeping the image inside the
|
||||||
}
|
* $width and $height
|
||||||
|
*
|
||||||
public function SetHeight($height) {
|
* @param integer $width The width to size within
|
||||||
return $this->getHeight() == $height ? $this : $this->getFormattedImage('SetHeight', $height);
|
* @param integer $height The height to size within
|
||||||
}
|
* @return Image
|
||||||
|
*/
|
||||||
public function SetSize($width, $height) {
|
|
||||||
return (($this->getWidth() == $width) && ($this->getHeight() == $height))
|
|
||||||
? $this
|
|
||||||
: $this->getFormattedImage('SetSize', $width, $height);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function SetRatioSize($width, $height) {
|
public function SetRatioSize($width, $height) {
|
||||||
return $this->getFormattedImage('SetRatioSize', $width, $height);
|
|
||||||
|
// Check if image is already sized to the correct dimension
|
||||||
|
$widthRatio = $width / $this->width;
|
||||||
|
$heightRatio = $height / $this->height;
|
||||||
|
if( $widthRatio < $heightRatio ) {
|
||||||
|
// Target is higher aspect ratio than image, so check width
|
||||||
|
if($this->isWidth($width)) return $this;
|
||||||
|
} else {
|
||||||
|
// Target is wider aspect ratio than image, so check height
|
||||||
|
if($this->isHeight($height)) return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Item must be regenerated
|
||||||
|
return $this->getFormattedImage('SetRatioSize', $width, $height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize the image by preserving aspect ratio, keeping the image inside the
|
||||||
|
* $width and $height
|
||||||
|
*
|
||||||
|
* @param Image_Backend $backend
|
||||||
|
* @param integer $width The width to size within
|
||||||
|
* @param integer $height The height to size within
|
||||||
|
* @return Image_Backend
|
||||||
|
*/
|
||||||
public function generateSetRatioSize(Image_Backend $backend, $width, $height) {
|
public function generateSetRatioSize(Image_Backend $backend, $width, $height) {
|
||||||
return $backend->resizeRatio($width, $height);
|
return $backend->resizeRatio($width, $height);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize this Image by width, keeping aspect ratio. Use in templates with $SetWidth.
|
* Resize this Image by width, keeping aspect ratio. Use in templates with $SetWidth.
|
||||||
|
*
|
||||||
|
* @param integer $width The width to set
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
public function SetWidth($width) {
|
||||||
|
return $this->isWidth($width)
|
||||||
|
? $this
|
||||||
|
: $this->getFormattedImage('SetWidth', $width);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize this Image by width, keeping aspect ratio. Use in templates with $SetWidth.
|
||||||
|
*
|
||||||
|
* @param Image_Backend $backend
|
||||||
|
* @param type $width The width to set
|
||||||
* @return Image_Backend
|
* @return Image_Backend
|
||||||
*/
|
*/
|
||||||
public function generateSetWidth(Image_Backend $backend, $width) {
|
public function generateSetWidth(Image_Backend $backend, $width) {
|
||||||
@ -224,6 +255,21 @@ class Image extends File {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize this Image by height, keeping aspect ratio. Use in templates with $SetHeight.
|
* Resize this Image by height, keeping aspect ratio. Use in templates with $SetHeight.
|
||||||
|
*
|
||||||
|
* @param integer $height The height to set
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
public function SetHeight($height) {
|
||||||
|
return $this->isHeight($height)
|
||||||
|
? $this
|
||||||
|
: $this->getFormattedImage('SetHeight', $height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize this Image by height, keeping aspect ratio. Use in templates with $SetHeight.
|
||||||
|
*
|
||||||
|
* @param Image_Backend $backend
|
||||||
|
* @param integer $height The height to set
|
||||||
* @return Image_Backend
|
* @return Image_Backend
|
||||||
*/
|
*/
|
||||||
public function generateSetHeight(Image_Backend $backend, $height){
|
public function generateSetHeight(Image_Backend $backend, $height){
|
||||||
@ -232,6 +278,24 @@ class Image extends File {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Resize this Image by both width and height, using padded resize. Use in templates with $SetSize.
|
* Resize this Image by both width and height, using padded resize. Use in templates with $SetSize.
|
||||||
|
* @see Image::PaddedImage()
|
||||||
|
*
|
||||||
|
* @param integer $width The width to size to
|
||||||
|
* @param integer $height The height to size to
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
public function SetSize($width, $height) {
|
||||||
|
return $this->isSize($width, $height)
|
||||||
|
? $this
|
||||||
|
: $this->getFormattedImage('SetSize', $width, $height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize this Image by both width and height, using padded resize. Use in templates with $SetSize.
|
||||||
|
*
|
||||||
|
* @param Image_Backend $backend
|
||||||
|
* @param integer $width The width to size to
|
||||||
|
* @param integer $height The height to size to
|
||||||
* @return Image_Backend
|
* @return Image_Backend
|
||||||
*/
|
*/
|
||||||
public function generateSetSize(Image_Backend $backend, $width, $height) {
|
public function generateSetSize(Image_Backend $backend, $width, $height) {
|
||||||
@ -274,10 +338,63 @@ class Image extends File {
|
|||||||
return $backend->croppedResize($this->stat('strip_thumbnail_width'),$this->stat('strip_thumbnail_height'));
|
return $backend->croppedResize($this->stat('strip_thumbnail_width'),$this->stat('strip_thumbnail_height'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize this Image by both width and height, using padded resize. Use in templates with $PaddedImage.
|
||||||
|
* @see Image::SetSize()
|
||||||
|
*
|
||||||
|
* @param integer $width The width to size to
|
||||||
|
* @param integer $height The height to size to
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
public function PaddedImage($width, $height) {
|
||||||
|
return $this->isSize($width, $height)
|
||||||
|
? $this
|
||||||
|
: $this->getFormattedImage('PaddedImage', $width, $height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resize this Image by both width and height, using padded resize. Use in templates with $PaddedImage.
|
||||||
|
*
|
||||||
|
* @param Image_Backend $backend
|
||||||
|
* @param integer $width The width to size to
|
||||||
|
* @param integer $height The height to size to
|
||||||
|
* @return Image_Backend
|
||||||
|
*/
|
||||||
public function generatePaddedImage(Image_Backend $backend, $width, $height) {
|
public function generatePaddedImage(Image_Backend $backend, $width, $height) {
|
||||||
return $backend->paddedResize($width, $height);
|
return $backend->paddedResize($width, $height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if this image is of the specified size
|
||||||
|
*
|
||||||
|
* @param integer $width Width to check
|
||||||
|
* @param integer $height Height to check
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isSize($width, $height) {
|
||||||
|
return $this->isWidth($width) && $this->isHeight($height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if this image is of the specified width
|
||||||
|
*
|
||||||
|
* @param integer $width Width to check
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isWidth($width) {
|
||||||
|
return !empty($width) && $this->getWidth() == $width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if this image is of the specified width
|
||||||
|
*
|
||||||
|
* @param integer $height Height to check
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function isHeight($height) {
|
||||||
|
return !empty($height) && $this->getHeight() == $height;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return an image object representing the image in the given format.
|
* Return an image object representing the image in the given format.
|
||||||
* This image will be generated using generateFormattedImage().
|
* This image will be generated using generateFormattedImage().
|
||||||
@ -321,6 +438,7 @@ class Image extends File {
|
|||||||
* Generate an image on the specified format. It will save the image
|
* Generate an image on the specified format. It will save the image
|
||||||
* at the location specified by cacheFilename(). The image will be generated
|
* at the location specified by cacheFilename(). The image will be generated
|
||||||
* using the specific 'generate' method for the specified format.
|
* using the specific 'generate' method for the specified format.
|
||||||
|
*
|
||||||
* @param string $format Name of the format to generate.
|
* @param string $format Name of the format to generate.
|
||||||
* @param string $arg1 Argument to pass to the generate method.
|
* @param string $arg1 Argument to pass to the generate method.
|
||||||
* @param string $arg2 A second argument to pass to the generate method.
|
* @param string $arg2 A second argument to pass to the generate method.
|
||||||
@ -350,6 +468,25 @@ class Image extends File {
|
|||||||
/**
|
/**
|
||||||
* Generate a resized copy of this image with the given width & height.
|
* Generate a resized copy of this image with the given width & height.
|
||||||
* Use in templates with $ResizedImage.
|
* Use in templates with $ResizedImage.
|
||||||
|
*
|
||||||
|
* @param integer $width Width to resize to
|
||||||
|
* @param integer $height Height to resize to
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
public function ResizedImage($width, $height) {
|
||||||
|
return $this->isSize($width, $height)
|
||||||
|
? $this
|
||||||
|
: $this->getFormattedImage('ResizedImage', $width, $height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a resized copy of this image with the given width & height.
|
||||||
|
* Use in templates with $ResizedImage.
|
||||||
|
*
|
||||||
|
* @param Image_Backend $backend
|
||||||
|
* @param integer $width Width to resize to
|
||||||
|
* @param integer $height Height to resize to
|
||||||
|
* @return Image_Backend
|
||||||
*/
|
*/
|
||||||
public function generateResizedImage(Image_Backend $backend, $width, $height) {
|
public function generateResizedImage(Image_Backend $backend, $width, $height) {
|
||||||
if(!$backend){
|
if(!$backend){
|
||||||
@ -363,6 +500,25 @@ class Image extends File {
|
|||||||
/**
|
/**
|
||||||
* Generate a resized copy of this image with the given width & height, cropping to maintain aspect ratio.
|
* Generate a resized copy of this image with the given width & height, cropping to maintain aspect ratio.
|
||||||
* Use in templates with $CroppedImage
|
* Use in templates with $CroppedImage
|
||||||
|
*
|
||||||
|
* @param integer $width Width to crop to
|
||||||
|
* @param integer $height Height to crop to
|
||||||
|
* @return Image
|
||||||
|
*/
|
||||||
|
public function CroppedImage($width, $height) {
|
||||||
|
return $this->isSize($width, $height)
|
||||||
|
? $this
|
||||||
|
: $this->getFormattedImage('CroppedImage', $width, $height);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a resized copy of this image with the given width & height, cropping to maintain aspect ratio.
|
||||||
|
* Use in templates with $CroppedImage
|
||||||
|
*
|
||||||
|
* @param Image_Backend $backend
|
||||||
|
* @param integer $width Width to crop to
|
||||||
|
* @param integer $height Height to crop to
|
||||||
|
* @return Image_Backend
|
||||||
*/
|
*/
|
||||||
public function generateCroppedImage(Image_Backend $backend, $width, $height) {
|
public function generateCroppedImage(Image_Backend $backend, $width, $height) {
|
||||||
return $backend->croppedResize($width, $height);
|
return $backend->croppedResize($width, $height);
|
||||||
|
@ -81,6 +81,9 @@ class ImageTest extends SapphireTest {
|
|||||||
$this->assertEquals($expected, $actual);
|
$this->assertEquals($expected, $actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that multiple image manipulations may be performed on a single Image
|
||||||
|
*/
|
||||||
public function testMultipleGenerateManipulationCalls() {
|
public function testMultipleGenerateManipulationCalls() {
|
||||||
$image = $this->objFromFixture('Image', 'imageWithoutTitle');
|
$image = $this->objFromFixture('Image', 'imageWithoutTitle');
|
||||||
|
|
||||||
@ -98,6 +101,78 @@ class ImageTest extends SapphireTest {
|
|||||||
$this->assertEquals($expected, $actual);
|
$this->assertEquals($expected, $actual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that image manipulations that do not affect the resulting dimensions
|
||||||
|
* of the output image do not resample the file.
|
||||||
|
*/
|
||||||
|
public function testReluctanceToResampling() {
|
||||||
|
|
||||||
|
$image = $this->objFromFixture('Image', 'imageWithoutTitle');
|
||||||
|
$this->assertTrue($image->isSize(300, 300));
|
||||||
|
|
||||||
|
// Set width to 50 pixels
|
||||||
|
$imageSetWidth = $image->SetWidth(300);
|
||||||
|
$this->assertEquals($imageSetWidth->getWidth(), 300);
|
||||||
|
$this->assertEquals($image->Filename, $imageSetWidth->Filename);
|
||||||
|
|
||||||
|
// Set height to 300 pixels
|
||||||
|
$imageSetHeight = $image->SetHeight(300);
|
||||||
|
$this->assertEquals($imageSetHeight->getHeight(), 300);
|
||||||
|
$this->assertEquals($image->Filename, $imageSetHeight->Filename);
|
||||||
|
|
||||||
|
// Crop image to 300 x 300
|
||||||
|
$imageCropped = $image->CroppedImage(300, 300);
|
||||||
|
$this->assertTrue($imageCropped->isSize(300, 300));
|
||||||
|
$this->assertEquals($image->Filename, $imageCropped->Filename);
|
||||||
|
|
||||||
|
// Resize (padded) to 300 x 300
|
||||||
|
$imageSized = $image->SetSize(300, 300);
|
||||||
|
$this->assertTrue($imageSized->isSize(300, 300));
|
||||||
|
$this->assertEquals($image->Filename, $imageSized->Filename);
|
||||||
|
|
||||||
|
// Padded image 300 x 300 (same as above)
|
||||||
|
$imagePadded = $image->PaddedImage(300, 300);
|
||||||
|
$this->assertTrue($imagePadded->isSize(300, 300));
|
||||||
|
$this->assertEquals($image->Filename, $imagePadded->Filename);
|
||||||
|
|
||||||
|
// Resized (stretched) to 300 x 300
|
||||||
|
$imageStretched = $image->ResizedImage(300, 300);
|
||||||
|
$this->assertTrue($imageStretched->isSize(300, 300));
|
||||||
|
$this->assertEquals($image->Filename, $imageStretched->Filename);
|
||||||
|
|
||||||
|
// SetRatioSize (various options)
|
||||||
|
$imageSetRatioSize = $image->SetRatioSize(300, 600);
|
||||||
|
$this->assertTrue($imageSetRatioSize->isSize(300, 300));
|
||||||
|
$this->assertEquals($image->Filename, $imageSetRatioSize->Filename);
|
||||||
|
$imageSetRatioSize = $image->SetRatioSize(600, 300);
|
||||||
|
$this->assertTrue($imageSetRatioSize->isSize(300, 300));
|
||||||
|
$this->assertEquals($image->Filename, $imageSetRatioSize->Filename);
|
||||||
|
$imageSetRatioSize = $image->SetRatioSize(300, 300);
|
||||||
|
$this->assertTrue($imageSetRatioSize->isSize(300, 300));
|
||||||
|
$this->assertEquals($image->Filename, $imageSetRatioSize->Filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testImageResize() {
|
||||||
|
$image = $this->objFromFixture('Image', 'imageWithoutTitle');
|
||||||
|
$this->assertTrue($image->isSize(300, 300));
|
||||||
|
|
||||||
|
// Test normal resize
|
||||||
|
$resized = $image->SetSize(150, 100);
|
||||||
|
$this->assertTrue($resized->isSize(150, 100));
|
||||||
|
|
||||||
|
// Test cropped resize
|
||||||
|
$cropped = $image->CroppedImage(100, 200);
|
||||||
|
$this->assertTrue($cropped->isSize(100, 200));
|
||||||
|
|
||||||
|
// Test padded resize
|
||||||
|
$padded = $image->PaddedImage(200, 100);
|
||||||
|
$this->assertTrue($padded->isSize(200, 100));
|
||||||
|
|
||||||
|
// Test SetRatioSize
|
||||||
|
$ratio = $image->SetRatioSize(80, 160);
|
||||||
|
$this->assertTrue($ratio->isSize(80, 80));
|
||||||
|
}
|
||||||
|
|
||||||
public function testGeneratedImageDeletion() {
|
public function testGeneratedImageDeletion() {
|
||||||
$image = $this->objFromFixture('Image', 'imageWithMetacharacters');
|
$image = $this->objFromFixture('Image', 'imageWithMetacharacters');
|
||||||
$image_generated = $image->SetWidth(200);
|
$image_generated = $image->SetWidth(200);
|
||||||
|
Loading…
Reference in New Issue
Block a user