@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Support animated gif in meme

Summary:
Use imagemagick convert to first detect the number of gif frames,
then +adjoin to split them in tmpfile, then call applyMemeTo to
each frame, then convert them back.

Test Plan:
Add memes in sandbox
with both gifs and non-gifs. Note that gifs are quite slow.

CC: aran, epriestley, chad

Differential Revision: https://secure.phabricator.com/D5821

authored by

yitao and committed by
epriestley
ff410134 16b54a6e

+70 -3
+70 -3
src/applications/files/PhabricatorImageTransformer.php
··· 6 6 PhabricatorFile $file, 7 7 $upper_text, 8 8 $lower_text) { 9 - $image = $this->applyMemeTo($file, $upper_text, $lower_text); 9 + $image = $this->applyMemeToFile($file, $upper_text, $lower_text); 10 10 return PhabricatorFile::newFromFileData( 11 11 $image, 12 12 array( ··· 257 257 return self::saveImageDataInAnyFormat($dst, $file->getMimeType()); 258 258 } 259 259 260 - private function applyMemeTo( 260 + private function applyMemeToFile( 261 261 PhabricatorFile $file, 262 262 $upper_text, 263 263 $lower_text) { 264 264 $data = $file->loadFileData(); 265 + 266 + $img_type = $file->getMimeType(); 267 + $imagemagick = PhabricatorEnv::getEnvConfig('files.enable-imagemagick'); 268 + 269 + if ($img_type != 'image/gif' || $imagemagick == false) { 270 + return $this->applyMemeTo( 271 + $data, $upper_text, $lower_text, $img_type); 272 + } 273 + 274 + $data = $file->loadFileData(); 275 + $input = new TempFile(); 276 + Filesystem::writeFile($input, $data); 277 + 278 + list($out) = execx('convert %s info:', $input); 279 + $split = phutil_split_lines($out); 280 + if (count($split) > 1) { 281 + return $this->applyMemeWithImagemagick( 282 + $input, 283 + $upper_text, 284 + $lower_text, 285 + count($split), 286 + $img_type); 287 + } else { 288 + return $this->applyMemeTo($data, $upper_text, $lower_text, $img_type); 289 + } 290 + } 291 + 292 + private function applyMemeTo( 293 + $data, 294 + $upper_text, 295 + $lower_text, 296 + $mime_type) { 265 297 $img = imagecreatefromstring($data); 266 298 $phabricator_root = dirname(phutil_get_library_root('phabricator')); 267 299 $font_root = $phabricator_root.'/resources/font/'; ··· 314 346 break; 315 347 } 316 348 } 317 - return self::saveImageDataInAnyFormat($img, $file->getMimeType()); 349 + return self::saveImageDataInAnyFormat($img, $mime_type); 318 350 } 319 351 320 352 private function makeImageWithTextBorder($img, $font_size, $x, $y, ··· 355 387 public static function saveImageDataInAnyFormat($data, $preferred_mime = '') { 356 388 switch ($preferred_mime) { 357 389 case 'image/gif': // Gif doesn't support true color 390 + ob_start(); 391 + imagegif($data); 392 + return ob_get_clean(); 393 + break; 358 394 case 'image/png': 359 395 if (function_exists('imagepng')) { 360 396 ob_start(); ··· 421 457 return null; 422 458 } 423 459 460 + } 461 + 462 + private function applyMemeWithImagemagick( 463 + $input, 464 + $above, 465 + $below, 466 + $count, 467 + $img_type) { 468 + 469 + $output = new TempFile(); 470 + 471 + execx('convert %s -coalesce +adjoin %s_%%09d', 472 + $input, 473 + $input); 474 + 475 + for ($ii = 0; $ii < $count; $ii++) { 476 + $frame_name = sprintf('%s_%09d', $input, $ii); 477 + $output_name = sprintf('%s_%09d', $output, $ii); 478 + 479 + $frame_data = Filesystem::readFile($frame_name); 480 + $memed_frame_data = $this->applyMemeTo( 481 + $frame_data, 482 + $above, 483 + $below, 484 + $img_type); 485 + Filesystem::writeFile($output_name, $memed_frame_data); 486 + } 487 + 488 + execx('convert -loop 0 %s_* %s', $output, $output); 489 + 490 + return Filesystem::readFile($output); 424 491 } 425 492 426 493 }