mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Preserving the Animation of Gif Images
Summary: Preserving animation of GIF profile Pictures Test Plan: Uploaded Animated images as profile pictures to check if the animation of gif images is preserved and it does :) somewhat ! Reviewers: epriestley Reviewed By: epriestley CC: aran, Korvin Differential Revision: https://secure.phabricator.com/D4833
This commit is contained in:
parent
cc084822da
commit
9c19e9b7d8
6 changed files with 103 additions and 9 deletions
|
@ -882,6 +882,10 @@ return array(
|
||||||
'image/vnd.microsoft.icon' => true,
|
'image/vnd.microsoft.icon' => true,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Configuration option for enabling imagemagick
|
||||||
|
// to resize animated profile pictures (gif)
|
||||||
|
'files.enable-imagemagick' => false,
|
||||||
|
|
||||||
// -- Storage --------------------------------------------------------------- //
|
// -- Storage --------------------------------------------------------------- //
|
||||||
|
|
||||||
// Phabricator allows users to upload files, and can keep them in various
|
// Phabricator allows users to upload files, and can keep them in various
|
||||||
|
|
|
@ -1261,6 +1261,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php',
|
'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php',
|
||||||
'PhabricatorSetupCheckFacebook' => 'applications/config/check/PhabricatorSetupCheckFacebook.php',
|
'PhabricatorSetupCheckFacebook' => 'applications/config/check/PhabricatorSetupCheckFacebook.php',
|
||||||
'PhabricatorSetupCheckGD' => 'applications/config/check/PhabricatorSetupCheckGD.php',
|
'PhabricatorSetupCheckGD' => 'applications/config/check/PhabricatorSetupCheckGD.php',
|
||||||
|
'PhabricatorSetupCheckImagemagick' => 'applications/config/check/PhabricatorSetupCheckImagemagick.php',
|
||||||
'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php',
|
'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php',
|
||||||
'PhabricatorSetupCheckMail' => 'applications/config/check/PhabricatorSetupCheckMail.php',
|
'PhabricatorSetupCheckMail' => 'applications/config/check/PhabricatorSetupCheckMail.php',
|
||||||
'PhabricatorSetupCheckMySQL' => 'applications/config/check/PhabricatorSetupCheckMySQL.php',
|
'PhabricatorSetupCheckMySQL' => 'applications/config/check/PhabricatorSetupCheckMySQL.php',
|
||||||
|
@ -2677,6 +2678,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckFacebook' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckFacebook' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck',
|
||||||
|
'PhabricatorSetupCheckImagemagick' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck',
|
||||||
'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck',
|
'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck',
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorSetupCheckImagemagick extends PhabricatorSetupCheck {
|
||||||
|
|
||||||
|
protected function executeChecks() {
|
||||||
|
$imagemagick = PhabricatorEnv::getEnvConfig('files.enable-imagemagick');
|
||||||
|
if ($imagemagick) {
|
||||||
|
list($err) = exec_manual('which convert');
|
||||||
|
if ($err) {
|
||||||
|
$message = pht(
|
||||||
|
'You have enabled Imagemagick in your config, but the \'convert\''.
|
||||||
|
' binary is not in the webserver\'s $PATH. Disable imagemagick'.
|
||||||
|
' or make it available to the webserver.');
|
||||||
|
|
||||||
|
$this->newIssue('files.enable-imagemagick')
|
||||||
|
->setName(pht(
|
||||||
|
"'convert' binary not found or Imagemagick is not installed."))
|
||||||
|
->setMessage($message)
|
||||||
|
->addPhabricatorConfig('files.enable-imagemagick')
|
||||||
|
->addPhabricatorConfig('environment.append-paths');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ final class PhabricatorCoreConfigOptions
|
||||||
->setDescription(
|
->setDescription(
|
||||||
pht('Array containing list of Uninstalled applications.')
|
pht('Array containing list of Uninstalled applications.')
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function didValidateOption(
|
protected function didValidateOption(
|
||||||
|
|
|
@ -95,8 +95,14 @@ final class PhabricatorImageTransformer {
|
||||||
$scaled_y = $min_y;
|
$scaled_y = $min_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$cropped = $this->applyScaleWithImagemagick($file, $x, $scaled_y);
|
||||||
|
|
||||||
|
if ($cropped != null) {
|
||||||
|
return $cropped;
|
||||||
|
}
|
||||||
|
|
||||||
$img = $this->applyScaleTo(
|
$img = $this->applyScaleTo(
|
||||||
$img,
|
$file,
|
||||||
$x,
|
$x,
|
||||||
$scaled_y);
|
$scaled_y);
|
||||||
|
|
||||||
|
@ -131,11 +137,13 @@ final class PhabricatorImageTransformer {
|
||||||
* Very crudely scale an image up or down to an exact size.
|
* Very crudely scale an image up or down to an exact size.
|
||||||
*/
|
*/
|
||||||
private function crudelyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
private function crudelyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
||||||
$data = $file->loadFileData();
|
$scaled = $this->applyScaleWithImagemagick($file, $dx, $dy);
|
||||||
$src = imagecreatefromstring($data);
|
|
||||||
|
|
||||||
$dst = $this->applyScaleTo($src, $dx, $dy);
|
if ($scaled != null) {
|
||||||
|
return $scaled;
|
||||||
|
}
|
||||||
|
|
||||||
|
$dst = $this->applyScaleTo($file, $dx, $dy);
|
||||||
return $this->saveImageDataInAnyFormat($dst, $file->getMimeType());
|
return $this->saveImageDataInAnyFormat($dst, $file->getMimeType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,17 +155,22 @@ final class PhabricatorImageTransformer {
|
||||||
return $dst;
|
return $dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function applyScaleTo($src, $dx, $dy) {
|
private function applyScaleTo(PhabricatorFile $file, $dx, $dy) {
|
||||||
|
$data = $file->loadFileData();
|
||||||
|
$src = imagecreatefromstring($data);
|
||||||
|
|
||||||
$x = imagesx($src);
|
$x = imagesx($src);
|
||||||
$y = imagesy($src);
|
$y = imagesy($src);
|
||||||
|
|
||||||
$scale = min(($dx / $x), ($dy / $y), 1);
|
$scale = min(($dx / $x), ($dy / $y), 1);
|
||||||
|
|
||||||
$dst = $this->getBlankDestinationFile($dx, $dy);
|
|
||||||
|
|
||||||
$sdx = $scale * $x;
|
$sdx = $scale * $x;
|
||||||
$sdy = $scale * $y;
|
$sdy = $scale * $y;
|
||||||
|
|
||||||
|
$dst = $this->getBlankDestinationFile($dx, $dy);
|
||||||
|
imagesavealpha($dst, true);
|
||||||
|
imagefill($dst, 0, 0, imagecolorallocatealpha($dst, 255, 255, 255, 127));
|
||||||
|
|
||||||
imagecopyresampled(
|
imagecopyresampled(
|
||||||
$dst,
|
$dst,
|
||||||
$src,
|
$src,
|
||||||
|
@ -167,6 +180,7 @@ final class PhabricatorImageTransformer {
|
||||||
$x, $y);
|
$x, $y);
|
||||||
|
|
||||||
return $dst;
|
return $dst;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getPreviewDimensions(PhabricatorFile $file, $size) {
|
public static function getPreviewDimensions(PhabricatorFile $file, $size) {
|
||||||
|
@ -337,7 +351,7 @@ final class PhabricatorImageTransformer {
|
||||||
|
|
||||||
private function saveImageDataInAnyFormat($data, $preferred_mime = '') {
|
private function saveImageDataInAnyFormat($data, $preferred_mime = '') {
|
||||||
switch ($preferred_mime) {
|
switch ($preferred_mime) {
|
||||||
case 'image/gif': // GIF doesn't support true color.
|
case 'image/gif': // Gif doesn't support true color
|
||||||
case 'image/png':
|
case 'image/png':
|
||||||
if (function_exists('imagepng')) {
|
if (function_exists('imagepng')) {
|
||||||
ob_start();
|
ob_start();
|
||||||
|
@ -368,4 +382,43 @@ final class PhabricatorImageTransformer {
|
||||||
return $img;
|
return $img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function applyScaleWithImagemagick(PhabricatorFile $file, $dx, $dy) {
|
||||||
|
|
||||||
|
$img_type = $file->getMimeType();
|
||||||
|
$imagemagick = PhabricatorEnv::getEnvConfig('files.enable-imagemagick');
|
||||||
|
|
||||||
|
if ($img_type != 'image/gif' || $imagemagick == false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $file->loadFileData();
|
||||||
|
$src = imagecreatefromstring($data);
|
||||||
|
|
||||||
|
$x = imagesx($src);
|
||||||
|
$y = imagesy($src);
|
||||||
|
|
||||||
|
$scale = min(($dx / $x), ($dy / $y), 1);
|
||||||
|
|
||||||
|
$sdx = $scale * $x;
|
||||||
|
$sdy = $scale * $y;
|
||||||
|
|
||||||
|
$input = new TempFile();
|
||||||
|
Filesystem::writeFile($input, $data);
|
||||||
|
|
||||||
|
$resized = new TempFile();
|
||||||
|
|
||||||
|
list($err) = exec_manual(
|
||||||
|
'convert %s -coalesce -resize %sX%s\! %s'
|
||||||
|
, $input, $sdx, $sdy, $resized
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$err) {
|
||||||
|
$new_data = Filesystem::readFile($resized);
|
||||||
|
return $new_data;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,16 @@ final class PhabricatorFilesConfigOptions
|
||||||
"value and the UI will then reflect the actual configured ".
|
"value and the UI will then reflect the actual configured ".
|
||||||
"limit."))
|
"limit."))
|
||||||
->addExample('10M', pht("Valid setting.")),
|
->addExample('10M', pht("Valid setting.")),
|
||||||
|
$this->newOption('files.enable-imagemagick', 'bool', false)
|
||||||
|
->setBoolOptions(
|
||||||
|
array(
|
||||||
|
pht('Enable'),
|
||||||
|
pht('Disable')
|
||||||
|
))->setDescription(
|
||||||
|
pht("This option will enable animated gif images".
|
||||||
|
"to be set as profile pictures. The \'convert\' binary ".
|
||||||
|
"should be available to the webserver for this to work")),
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue