Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 64 additions & 17 deletions apps/theming/lib/ImageManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,32 +243,79 @@ public function updateImage(string $key, string $tmpFile): string {
throw new \Exception('Unsupported image type');
}

if ($key === 'background' && strpos($detectedMimeType, 'image/svg') === false && strpos($detectedMimeType, 'image/gif') === false) {
// Optimize the image since some people may upload images that will be
// either to big or are not progressive rendering.
$newImage = @imagecreatefromstring(file_get_contents($tmpFile));
if ($key === 'background' && $this->shouldOptimizeBackgroundImage($detectedMimeType, filesize($tmpFile))) {
try {
// Optimize the image since some people may upload images that will be
// either to big or are not progressive rendering.
$newImage = @imagecreatefromstring(file_get_contents($tmpFile));
if ($newImage === false) {
throw new \Exception('Could not read background image, possibly corrupted.');
}

// Preserve transparency
imagesavealpha($newImage, true);
imagealphablending($newImage, true);
// Preserve transparency
imagesavealpha($newImage, true);
imagealphablending($newImage, true);

$tmpFile = $this->tempManager->getTemporaryFile();
$newWidth = (int)(imagesx($newImage) < 4096 ? imagesx($newImage) : 4096);
$newHeight = (int)(imagesy($newImage) / (imagesx($newImage) / $newWidth));
$outputImage = imagescale($newImage, $newWidth, $newHeight);
$newWidth = (int)(imagesx($newImage) < 4096 ? imagesx($newImage) : 4096);
$newHeight = (int)(imagesy($newImage) / (imagesx($newImage) / $newWidth));
$outputImage = imagescale($newImage, $newWidth, $newHeight);
if ($outputImage === false) {
throw new \Exception('Could not scale uploaded background image.');
}

imageinterlace($outputImage, 1);
imagepng($outputImage, $tmpFile, 8);
imagedestroy($outputImage);
$newTmpFile = $this->tempManager->getTemporaryFile();
imageinterlace($outputImage, 1);
// Keep jpeg images encoded as jpeg
if (strpos($detectedMimeType, 'image/jpeg') !== false) {
if (!imagejpeg($outputImage, $newTmpFile, 90)) {
throw new \Exception('Could not recompress background image as JPEG');
}
} else {
if (!imagepng($outputImage, $newTmpFile, 8)) {
throw new \Exception('Could not recompress background image as PNG');
}
}
$tmpFile = $newTmpFile;
imagedestroy($outputImage);
} catch (\Exception $e) {
if (is_resource($outputImage) || $outputImage instanceof \GdImage) {
imagedestroy($outputImage);
}

$target->putContent(file_get_contents($tmpFile));
} else {
$target->putContent(file_get_contents($tmpFile));
$this->logger->debug($e->getMessage());
}
}

$target->putContent(file_get_contents($tmpFile));

return $detectedMimeType;
}

/**
* Decide whether an image benefits from shrinking and reconverting
*
* @param string $mimeType the mime type of the image
* @param int $contentSize size of the image file
* @return bool
*/
private function shouldOptimizeBackgroundImage(string $mimeType, int $contentSize): bool {
// Do not touch SVGs
if (strpos($mimeType, 'image/svg') !== false) {
return false;
}
// GIF does not benefit from converting
if (strpos($mimeType, 'image/gif') !== false) {
return false;
}
// WebP also does not benefit from converting
// We could possibly try to convert to progressive image, but normally webP images are quite small
if (strpos($mimeType, 'image/webp') !== false) {
return false;
}
// As a rule of thumb background images should be max. 150-300 KiB, small images do not benefit from converting
return $contentSize > 150000;
}

/**
* Returns a list of supported mime types for image uploads.
* "favicon" images are only allowed to be SVG when imagemagick with SVG support is available.
Expand Down
9 changes: 6 additions & 3 deletions apps/theming/tests/ImageManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,12 @@ public function testCleanup() {

public function dataUpdateImage() {
return [
['background', __DIR__ . '/../../../tests/data/testimage.png', true, true],
['background', __DIR__ . '/../../../tests/data/testimage.png', false, true],
['background', __DIR__ . '/../../../tests/data/testimage.jpg', true, true],
['background', __DIR__ . '/../../../tests/data/testimage.png', true, false],
['background', __DIR__ . '/../../../tests/data/testimage.png', false, false],
['background', __DIR__ . '/../../../tests/data/testimage.jpg', true, false],
['background', __DIR__ . '/../../../tests/data/testimage.webp', true, false],
['background', __DIR__ . '/../../../tests/data/testimage-large.jpg', true, true],
['background', __DIR__ . '/../../../tests/data/testimage-wide.png', true, true],
['logo', __DIR__ . '/../../../tests/data/testimagelarge.svg', true, false],
];
}
Expand Down
Binary file added tests/data/testimage-large.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/data/testimage.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.