From 60f4dd9d4a11f401e1c784bb25c443c5b78927ee Mon Sep 17 00:00:00 2001 From: Marcin Kurczewski Date: Fri, 24 Oct 2014 18:25:33 +0200 Subject: [PATCH] Fixed getting dimensions of videos and flashes --- src/Services/ImageConverter.php | 130 ++++++++++++++++++ src/Services/PostService.php | 18 ++- ...ilGenerator.php => ThumbnailGenerator.php} | 57 ++++---- .../FlashThumbnailGenerator.php | 60 -------- .../IThumbnailGenerator.php | 10 -- .../SmartThumbnailGenerator.php | 36 ----- .../VideoThumbnailGenerator.php | 56 -------- src/Services/ThumbnailService.php | 9 +- tests/Services/PostServiceTest.php | 7 + tests/Services/ThumbnailGeneratorTest.php | 31 ++--- tests/Services/ThumbnailServiceTest.php | 9 +- 11 files changed, 203 insertions(+), 220 deletions(-) create mode 100644 src/Services/ImageConverter.php rename src/Services/{ThumbnailGenerators/ImageThumbnailGenerator.php => ThumbnailGenerator.php} (56%) delete mode 100644 src/Services/ThumbnailGenerators/FlashThumbnailGenerator.php delete mode 100644 src/Services/ThumbnailGenerators/IThumbnailGenerator.php delete mode 100644 src/Services/ThumbnailGenerators/SmartThumbnailGenerator.php delete mode 100644 src/Services/ThumbnailGenerators/VideoThumbnailGenerator.php diff --git a/src/Services/ImageConverter.php b/src/Services/ImageConverter.php new file mode 100644 index 00000000..b7659434 --- /dev/null +++ b/src/Services/ImageConverter.php @@ -0,0 +1,130 @@ +imageManipulator = $imageManipulator; + } + + + public function createImageFromBuffer($source) + { + $tmpSourcePath = tempnam(sys_get_temp_dir(), 'thumb') . '.dat'; + $tmpTargetPath = tempnam(sys_get_temp_dir(), 'thumb') . '.png'; + try + { + file_put_contents($tmpSourcePath, $source); + if (!$this->convert($tmpSourcePath, $tmpTargetPath)) + throw new \Exception('Error while converting supplied file to image'); + + $tmpSource = file_get_contents($tmpTargetPath); + return $this->imageManipulator->loadFromBuffer($tmpSource); + } + finally + { + $this->deleteIfExists($tmpSourcePath); + $this->deleteIfExists($tmpTargetPath); + } + } + + public function convert($sourcePath, $targetPath) + { + $mime = MimeHelper::getMimeTypeFromFile($sourcePath); + + if (MimeHelper::isImage($mime)) + { + copy($sourcePath, $targetPath); + return true; + } + + if (MimeHelper::isFlash($mime)) + return $this->convertFromFlash($sourcePath, $targetPath); + + if (MimeHelper::isVideo($mime)) + return $this->convertFromVideo($sourcePath, $targetPath); + + return false; + } + + private function convertFromFlash($sourcePath, $targetPath) + { + if (ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_DUMP_GNASH)) + { + ProgramExecutor::run( + self::PROGRAM_NAME_DUMP_GNASH, + [ + '--screenshot', 'last', + '--screenshot-file', $targetPath, + '-1', + '-r1', + '--max-advances', '15', + $sourcePath, + ]); + } + + if (!file_exists($targetPath) and ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_SWFRENDER)) + { + ProgramExecutor::run( + self::PROGRAM_NAME_SWFRENDER, + [ + 'swfrender', + $sourcePath, + '-o', + $targetPath, + ]); + } + + if (!file_exists($targetPath)) + return false; + + return true; + } + + private function convertFromVideo($sourcePath, $targetPath) + { + if (ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_FFMPEGTHUMBNAILER)) + { + ProgramExecutor::run( + self::PROGRAM_NAME_FFMPEGTHUMBNAILER, + [ + '-i' . $sourcePath, + '-o' . $targetPath, + '-s0', + '-t12%%' + ]); + } + + if (!file_exists($targetPath) and ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_FFMPEG)) + { + ProgramExecutor::run(self::PROGRAM_NAME_FFMEPG, + [ + '-i', $sourcePath, + '-vframes', '1', + $targetPath + ]); + } + + if (!file_exists($targetPath)) + return false; + + return true; + } + + private function deleteIfExists($path) + { + if (file_exists($path)) + unlink($path); + } +} diff --git a/src/Services/PostService.php b/src/Services/PostService.php index 13ad92f5..120325b5 100644 --- a/src/Services/PostService.php +++ b/src/Services/PostService.php @@ -18,6 +18,7 @@ use Szurubooru\SearchServices\Requirements\RequirementCompositeValue; use Szurubooru\SearchServices\Requirements\RequirementSingleValue; use Szurubooru\Services\AuthService; use Szurubooru\Services\HistoryService; +use Szurubooru\Services\ImageConverter; use Szurubooru\Services\ImageManipulation\ImageManipulator; use Szurubooru\Services\NetworkingService; use Szurubooru\Services\TagService; @@ -36,6 +37,7 @@ class PostService private $networkingService; private $tagService; private $historyService; + private $imageConverter; private $imageManipulator; public function __construct( @@ -49,6 +51,7 @@ class PostService NetworkingService $networkingService, TagService $tagService, HistoryService $historyService, + ImageConverter $imageConverter, ImageManipulator $imageManipulator) { $this->config = $config; @@ -61,6 +64,7 @@ class PostService $this->networkingService = $networkingService; $this->tagService = $tagService; $this->historyService = $historyService; + $this->imageConverter = $imageConverter; $this->imageManipulator = $imageManipulator; } @@ -247,9 +251,17 @@ class PostService $post->setContent($content); - $image = $this->imageManipulator->loadFromBuffer($content); - $post->setImageWidth($this->imageManipulator->getImageWidth($image)); - $post->setImageHeight($this->imageManipulator->getImageHeight($image)); + try + { + $image = $this->imageConverter->createImageFromBuffer($content); + $post->setImageWidth($this->imageManipulator->getImageWidth($image)); + $post->setImageHeight($this->imageManipulator->getImageHeight($image)); + } + catch (\Exception $e) + { + $post->setImageWidth(null); + $post->setImageHeight(null); + } $post->setOriginalFileSize(strlen($content)); } diff --git a/src/Services/ThumbnailGenerators/ImageThumbnailGenerator.php b/src/Services/ThumbnailGenerator.php similarity index 56% rename from src/Services/ThumbnailGenerators/ImageThumbnailGenerator.php rename to src/Services/ThumbnailGenerator.php index 655bdc82..4e576d4f 100644 --- a/src/Services/ThumbnailGenerators/ImageThumbnailGenerator.php +++ b/src/Services/ThumbnailGenerator.php @@ -1,47 +1,48 @@ imageManipulator = $imageManipulator; + $this->imageConverter = $imageConverter; } public function generate($source, $width, $height, $cropStyle) { - try + $image = $this->imageConverter->createImageFromBuffer($source); + if (!$image) + throw new \Exception('Error while loading supplied image'); + + $srcWidth = $this->imageManipulator->getImageWidth($image); + $srcHeight = $this->imageManipulator->getImageHeight($image); + + switch ($cropStyle) { - $image = $this->imageManipulator->loadFromBuffer($source); - $srcWidth = $this->imageManipulator->getImageWidth($image); - $srcHeight = $this->imageManipulator->getImageHeight($image); + case ThumbnailGenerator::CROP_OUTSIDE: + $this->cropOutside($image, $srcWidth, $srcHeight, $width, $height); + break; - switch ($cropStyle) - { - case IThumbnailGenerator::CROP_OUTSIDE: - $this->cropOutside($image, $srcWidth, $srcHeight, $width, $height); - break; + case ThumbnailGenerator::CROP_INSIDE: + $this->cropInside($image, $srcWidth, $srcHeight, $width, $height); + break; - case IThumbnailGenerator::CROP_INSIDE: - $this->cropInside($image, $srcWidth, $srcHeight, $width, $height); - break; - - default: - throw new \InvalidArgumentException('Unknown thumbnail crop style'); - } - - return $this->imageManipulator->saveToBuffer( - $image, - IImageManipulator::FORMAT_JPEG); - } - catch (\Exception $e) - { - return null; + default: + throw new \InvalidArgumentException('Unknown thumbnail crop style'); } + + return $this->imageManipulator->saveToBuffer( + $image, + IImageManipulator::FORMAT_JPEG); } private function cropOutside(&$image, $srcWidth, $srcHeight, $dstWidth, $dstHeight) diff --git a/src/Services/ThumbnailGenerators/FlashThumbnailGenerator.php b/src/Services/ThumbnailGenerators/FlashThumbnailGenerator.php deleted file mode 100644 index 22ffeb47..00000000 --- a/src/Services/ThumbnailGenerators/FlashThumbnailGenerator.php +++ /dev/null @@ -1,60 +0,0 @@ -imageThumbnailGenerator = $imageThumbnailGenerator; - } - - public function generate($source, $width, $height, $cropStyle) - { - $tmpSourcePath = tempnam(sys_get_temp_dir(), 'thumb') . '.dat'; - $tmpTargetPath = tempnam(sys_get_temp_dir(), 'thumb') . '.png'; - file_put_contents($tmpSourcePath, $source); - - if (ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_DUMP_GNASH)) - { - ProgramExecutor::run( - self::PROGRAM_NAME_DUMP_GNASH, - [ - '--screenshot', 'last', - '--screenshot-file', $tmpTargetPath, - '-1', - '-r1', - '--max-advances', '15', - $tmpSourcePath, - ]); - } - - if (!file_exists($tmpTargetPath) and ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_SWFRENDER)) - { - ProgramExecutor::run( - self::PROGRAM_NAME_SWFRENDER, - [ - 'swfrender', - $tmpSourcePath, - '-o', - $tmpTargetPath, - ]); - } - - if (!file_exists($tmpTargetPath)) - { - unlink($tmpSourcePath); - return null; - } - - $ret = $this->imageThumbnailGenerator->generate(file_get_contents($tmpTargetPath), $width, $height, $cropStyle); - unlink($tmpSourcePath); - unlink($tmpTargetPath); - return $ret; - } -} diff --git a/src/Services/ThumbnailGenerators/IThumbnailGenerator.php b/src/Services/ThumbnailGenerators/IThumbnailGenerator.php deleted file mode 100644 index 9ebe9880..00000000 --- a/src/Services/ThumbnailGenerators/IThumbnailGenerator.php +++ /dev/null @@ -1,10 +0,0 @@ -flashThumbnailGenerator = $flashThumbnailGenerator; - $this->videoThumbnailGenerator = $videoThumbnailGenerator; - $this->imageThumbnailGenerator = $imageThumbnailGenerator; - } - - public function generate($source, $width, $height, $cropStyle) - { - $mime = MimeHelper::getMimeTypeFromBuffer($source); - - if (MimeHelper::isFlash($mime)) - return $this->flashThumbnailGenerator->generate($source, $width, $height, $cropStyle); - - if (MimeHelper::isVideo($mime)) - return $this->videoThumbnailGenerator->generate($source, $width, $height, $cropStyle); - - if (MimeHelper::isImage($mime)) - return $this->imageThumbnailGenerator->generate($source, $width, $height, $cropStyle); - - return null; - } -} diff --git a/src/Services/ThumbnailGenerators/VideoThumbnailGenerator.php b/src/Services/ThumbnailGenerators/VideoThumbnailGenerator.php deleted file mode 100644 index fc67850b..00000000 --- a/src/Services/ThumbnailGenerators/VideoThumbnailGenerator.php +++ /dev/null @@ -1,56 +0,0 @@ -imageThumbnailGenerator = $imageThumbnailGenerator; - } - - public function generate($source, $width, $height, $cropStyle) - { - $tmpSourcePath = tempnam(sys_get_temp_dir(), 'thumb') . '.dat'; - $tmpTargetPath = tempnam(sys_get_temp_dir(), 'thumb') . '.png'; - file_put_contents($tmpSourcePath, $source); - - if (ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_FFMPEGTHUMBNAILER)) - { - ProgramExecutor::run( - self::PROGRAM_NAME_FFMPEGTHUMBNAILER, - [ - '-i' . $tmpSourcePath, - '-o' . $tmpTargetPath, - '-s0', - '-t12%%' - ]); - } - - if (!file_exists($tmpTargetPath) and ProgramExecutor::isProgramAvailable(self::PROGRAM_NAME_FFMPEG)) - { - ProgramExecutor::run(self::PROGRAM_NAME_FFMEPG, - [ - '-i', $tmpSourcePath, - '-vframes', '1', - $tmpTargetPath - ]); - } - - if (!file_exists($tmpTargetPath)) - { - unlink($tmpSourcePath); - return null; - } - - $ret = $this->imageThumbnailGenerator->generate(file_get_contents($tmpTargetPath), $width, $height, $cropStyle); - unlink($tmpSourcePath); - unlink($tmpTargetPath); - return $ret; - } -} diff --git a/src/Services/ThumbnailService.php b/src/Services/ThumbnailService.php index 9e7ec6f9..d9b3d7ba 100644 --- a/src/Services/ThumbnailService.php +++ b/src/Services/ThumbnailService.php @@ -2,8 +2,7 @@ namespace Szurubooru\Services; use Szurubooru\Config; use Szurubooru\Dao\PublicFileDao; -use Szurubooru\Services\ThumbnailGenerators\IThumbnailGenerator; -use Szurubooru\Services\ThumbnailGenerators\SmartThumbnailGenerator; +use Szurubooru\Services\ThumbnailGenerator; class ThumbnailService { @@ -14,7 +13,7 @@ class ThumbnailService public function __construct( Config $config, PublicFileDao $fileDao, - SmartThumbnailGenerator $thumbnailGenerator) + ThumbnailGenerator $thumbnailGenerator) { $this->config = $config; $this->fileDao = $fileDao; @@ -46,11 +45,11 @@ class ThumbnailService switch ($this->config->misc->thumbnailCropStyle) { case 'outside': - $cropStyle = IThumbnailGenerator::CROP_OUTSIDE; + $cropStyle = ThumbnailGenerator::CROP_OUTSIDE; break; case 'inside': - $cropStyle = IThumbnailGenerator::CROP_INSIDE; + $cropStyle = humbnailGenerator::CROP_INSIDE; break; default: diff --git a/tests/Services/PostServiceTest.php b/tests/Services/PostServiceTest.php index 4d93b09f..6eb296a6 100644 --- a/tests/Services/PostServiceTest.php +++ b/tests/Services/PostServiceTest.php @@ -9,6 +9,7 @@ use Szurubooru\FormData\UploadFormData; use Szurubooru\Injector; use Szurubooru\Services\AuthService; use Szurubooru\Services\HistoryService; +use Szurubooru\Services\ImageConverter; use Szurubooru\Services\ImageManipulation\ImageManipulator; use Szurubooru\Services\NetworkingService; use Szurubooru\Services\PostService; @@ -29,6 +30,7 @@ final class PostServiceTest extends AbstractDatabaseTestCase private $networkingServiceMock; private $tagService; private $historyServiceMock; + private $imageConverterMock; private $imageManipulatorMock; public function setUp() @@ -45,6 +47,7 @@ final class PostServiceTest extends AbstractDatabaseTestCase $this->tagService = Injector::get(TagService::class); $this->historyServiceMock = $this->mock(HistoryService::class); $this->configMock->set('database/maxPostSize', 1000000); + $this->imageConverterMock = $this->mock(ImageConverter::class); $this->imageManipulatorMock = $this->mock(ImageManipulator::class); } @@ -59,6 +62,7 @@ final class PostServiceTest extends AbstractDatabaseTestCase $this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0)); $this->authServiceMock->expects($this->once())->method('getLoggedInUser')->willReturn(new User(5)); $this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new Snapshot()); + $this->imageConverterMock->expects($this->never())->method('createImageFromBuffer'); $this->postService = $this->getPostService(); $savedPost = $this->postService->createPost($formData); @@ -109,6 +113,7 @@ final class PostServiceTest extends AbstractDatabaseTestCase $this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0)); $this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new Snapshot()); + $this->imageConverterMock->expects($this->once())->method('createImageFromBuffer'); $this->postService = $this->getPostService(); $savedPost = $this->postService->createPost($formData); @@ -128,6 +133,7 @@ final class PostServiceTest extends AbstractDatabaseTestCase $this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0)); $this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new Snapshot()); + $this->imageConverterMock->expects($this->once())->method('createImageFromBuffer'); $this->postService = $this->getPostService(); $savedPost = $this->postService->createPost($formData); @@ -210,6 +216,7 @@ final class PostServiceTest extends AbstractDatabaseTestCase $this->networkingServiceMock, $this->tagService, $this->historyServiceMock, + $this->imageConverterMock, $this->imageManipulatorMock); } } diff --git a/tests/Services/ThumbnailGeneratorTest.php b/tests/Services/ThumbnailGeneratorTest.php index c530142a..3dc4abb7 100644 --- a/tests/Services/ThumbnailGeneratorTest.php +++ b/tests/Services/ThumbnailGeneratorTest.php @@ -2,19 +2,17 @@ namespace Szurubooru\Tests\Services; use Szurubooru\Helpers\ProgramExecutor; use Szurubooru\Injector; +use Szurubooru\Services\ImageConverter; use Szurubooru\Services\ImageManipulation\ImageManipulator; -use Szurubooru\Services\ThumbnailGenerators\FlashThumbnailGenerator; -use Szurubooru\Services\ThumbnailGenerators\IThumbnailGenerator; -use Szurubooru\Services\ThumbnailGenerators\SmartThumbnailGenerator; -use Szurubooru\Services\ThumbnailGenerators\VideoThumbnailGenerator; +use Szurubooru\Services\ThumbnailGenerator; use Szurubooru\Tests\AbstractTestCase; final class ThumbnailGeneratorTest extends AbstractTestCase { public function testFlashThumbnails() { - if (!ProgramExecutor::isProgramAvailable(FlashThumbnailGenerator::PROGRAM_NAME_DUMP_GNASH) - and !ProgramExecutor::isProgramAvailable(FlashThumbnailGenerator::PROGRAM_NAME_SWFRENDER)) + if (!ProgramExecutor::isProgramAvailable(ImageConverter::PROGRAM_NAME_DUMP_GNASH) + and !ProgramExecutor::isProgramAvailable(ImageConverter::PROGRAM_NAME_SWFRENDER)) { $this->markTestSkipped('External software necessary to run this test is missing.'); } @@ -26,7 +24,7 @@ final class ThumbnailGeneratorTest extends AbstractTestCase $this->getTestFile('flash.swf'), 150, 150, - IThumbnailGenerator::CROP_OUTSIDE); + ThumbnailGenerator::CROP_OUTSIDE); $image = $imageManipulator->loadFromBuffer($result); $this->assertEquals(150, $imageManipulator->getImageWidth($image)); @@ -35,8 +33,8 @@ final class ThumbnailGeneratorTest extends AbstractTestCase public function testVideoThumbnails() { - if (!ProgramExecutor::isProgramAvailable(VideoThumbnailGenerator::PROGRAM_NAME_FFMPEG) - and !ProgramExecutor::isProgramAvailable(VideoThumbnailGenerator::PROGRAM_NAME_FFMPEGTHUMBNAILER)) + if (!ProgramExecutor::isProgramAvailable(ImageConverter::PROGRAM_NAME_FFMPEG) + and !ProgramExecutor::isProgramAvailable(ImageConverter::PROGRAM_NAME_FFMPEGTHUMBNAILER)) { $this->markTestSkipped('External software necessary to run this test is missing.'); } @@ -48,7 +46,7 @@ final class ThumbnailGeneratorTest extends AbstractTestCase $this->getTestFile('video.mp4'), 150, 150, - IThumbnailGenerator::CROP_OUTSIDE); + ThumbnailGenerator::CROP_OUTSIDE); $image = $imageManipulator->loadFromBuffer($result); $this->assertEquals(150, $imageManipulator->getImageWidth($image)); @@ -64,7 +62,7 @@ final class ThumbnailGeneratorTest extends AbstractTestCase $this->getTestFile('image.jpg'), 150, 150, - IThumbnailGenerator::CROP_OUTSIDE); + ThumbnailGenerator::CROP_OUTSIDE); $image = $imageManipulator->loadFromBuffer($result); $this->assertEquals(150, $imageManipulator->getImageWidth($image)); @@ -74,7 +72,7 @@ final class ThumbnailGeneratorTest extends AbstractTestCase $this->getTestFile('image.jpg'), 150, 150, - IThumbnailGenerator::CROP_INSIDE); + ThumbnailGenerator::CROP_INSIDE); $image = $imageManipulator->loadFromBuffer($result); $this->assertEquals(150, $imageManipulator->getImageWidth($image)); @@ -86,13 +84,12 @@ final class ThumbnailGeneratorTest extends AbstractTestCase $thumbnailGenerator = $this->getThumbnailGenerator(); $imageManipulator = $this->getImageManipulator(); - $result = $thumbnailGenerator->generate( + $this->setExpectedException(\Exception::class); + $thumbnailGenerator->generate( $this->getTestFile('text.txt'), 150, 150, - IThumbnailGenerator::CROP_OUTSIDE); - - $this->assertNull($result); + ThumbnailGenerator::CROP_OUTSIDE); } public function getImageManipulator() @@ -102,6 +99,6 @@ final class ThumbnailGeneratorTest extends AbstractTestCase public function getThumbnailGenerator() { - return Injector::get(SmartThumbnailGenerator::class); + return Injector::get(ThumbnailGenerator::class); } } diff --git a/tests/Services/ThumbnailServiceTest.php b/tests/Services/ThumbnailServiceTest.php index 7561256f..62706e80 100644 --- a/tests/Services/ThumbnailServiceTest.php +++ b/tests/Services/ThumbnailServiceTest.php @@ -1,8 +1,7 @@ configMock = $this->mockConfig(); $this->fileDaoMock = $this->mock(PublicFileDao::class); $this->thumbnailServiceMock = $this->mock(ThumbnailService::class); - $this->thumbnailGeneratorMock = $this->mock(SmartThumbnailGenerator::class); + $this->thumbnailGeneratorMock = $this->mock(ThumbnailGenerator::class); } public function testGetUsedThumbnailSizes() @@ -100,7 +99,7 @@ final class ThumbnailServiceTest extends AbstractTestCase 'content of file', 100, 100, - IThumbnailGenerator::CROP_OUTSIDE) + ThumbnailGenerator::CROP_OUTSIDE) ->willReturn(null); $this->fileDaoMock @@ -130,7 +129,7 @@ final class ThumbnailServiceTest extends AbstractTestCase 'content of file', 100, 100, - IThumbnailGenerator::CROP_OUTSIDE) + ThumbnailGenerator::CROP_OUTSIDE) ->willReturn('content of thumbnail'); $this->fileDaoMock