From 27330714687a1dc941b71ed06f5c32749987a6d1 Mon Sep 17 00:00:00 2001 From: Isaac Date: Thu, 23 Nov 2017 13:13:19 -0800 Subject: [PATCH 01/13] Changed Imagemagik parameters to stop cropping. --- app/Models/Image.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Models/Image.php b/app/Models/Image.php index 0bf18079..eda8edb4 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -137,7 +137,7 @@ class Image extends Model } if (isset($coverType['width']) && isset($coverType['height'])) { - $command .= " -thumbnail ${coverType['width']}x${coverType['height']}^ -gravity center -extent ${coverType['width']}x${coverType['height']}"; + $command .= " -thumbnail ${coverType['width']}x${coverType['height']} -gravity center -extent ${coverType['width']}x${coverType['height']}"; } $command .= ' "'.$image->getFile($coverType['id']).'"'; From ccb7361547cbb952b78050004410ae5409da3ef7 Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 24 Nov 2017 19:00:37 -0800 Subject: [PATCH 02/13] Thumbs now crop while cover have variable height --- .gitignore | 1 + app/Models/Image.php | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index fde04a84..009e4911 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ Homestead.yaml _ide_helper.php .idea resources/views/emails/html +/composer.phar diff --git a/app/Models/Image.php b/app/Models/Image.php index eda8edb4..2c9c2c2c 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -57,10 +57,10 @@ class Image extends Model const SMALL = 4; public static $ImageTypes = [ - self::NORMAL => ['id' => self::NORMAL, 'name' => 'normal', 'width' => 350, 'height' => 350], - self::ORIGINAL => ['id' => self::ORIGINAL, 'name' => 'original', 'width' => null, 'height' => null], - self::SMALL => ['id' => self::SMALL, 'name' => 'small', 'width' => 100, 'height' => 100], - self::THUMBNAIL => ['id' => self::THUMBNAIL, 'name' => 'thumbnail', 'width' => 50, 'height' => 50] + self::NORMAL => ['id' => self::NORMAL, 'name' => 'normal', 'width' => 350, 'height' => 350, 'geometry' => '350'], + self::ORIGINAL => ['id' => self::ORIGINAL, 'name' => 'original', 'width' => null, 'height' => null, 'geometry' => null], + self::SMALL => ['id' => self::SMALL, 'name' => 'small', 'width' => 100, 'height' => 100, 'geometry' => '100x100^'], + self::THUMBNAIL => ['id' => self::THUMBNAIL, 'name' => 'thumbnail', 'width' => 50, 'height' => 50, 'geometry' => '50x50^'] ]; public static function getImageTypeFromName($name) @@ -136,8 +136,8 @@ class Image extends Model $command .= ' -quality 95 -format png'; } - if (isset($coverType['width']) && isset($coverType['height'])) { - $command .= " -thumbnail ${coverType['width']}x${coverType['height']} -gravity center -extent ${coverType['width']}x${coverType['height']}"; + if (isset($coverType['geometry'])) { + $command .= " -gravity center -thumbnail ${coverType['geometry']} -extent ${coverType['geometry']}"; } $command .= ' "'.$image->getFile($coverType['id']).'"'; From 7ae95fa46f0e1bbf8cb2c4378c41fe468253c4bb Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 24 Nov 2017 19:08:41 -0800 Subject: [PATCH 03/13] Added ResizeImages command --- app/Console/Commands/ResizeImages.php | 42 +++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 app/Console/Commands/ResizeImages.php diff --git a/app/Console/Commands/ResizeImages.php b/app/Console/Commands/ResizeImages.php new file mode 100644 index 00000000..0473f107 --- /dev/null +++ b/app/Console/Commands/ResizeImages.php @@ -0,0 +1,42 @@ + Date: Fri, 24 Nov 2017 20:13:45 -0800 Subject: [PATCH 04/13] Added getOriginalFiles() to Image --- app/Models/Image.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/app/Models/Image.php b/app/Models/Image.php index 2c9c2c2c..dfa0bf29 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -154,6 +154,21 @@ class Image extends Model } } + /** + * Finds the names of all the original-sized images uploaded to the server + * @return string[] + */ + public static function getOriginalFiles() { + $rv = array(); + + //We use a cursor to cut down on memory + foreach (Image::cursor() as $image) { + $rv[] = $image->getFile(Image::ORIGINAL); + } + + return $rv; + } + protected $table = 'images'; public function getUrl($type = self::NORMAL) From 2f498f44d3ffaabd43124c27d92e8205d1b2e4f8 Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 24 Nov 2017 20:45:41 -0800 Subject: [PATCH 05/13] Removed getOriginalFiles and refactored image processing --- app/Models/Image.php | 55 +++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/app/Models/Image.php b/app/Models/Image.php index dfa0bf29..1483af17 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -24,6 +24,7 @@ use External; use Illuminate\Database\Eloquent\Model; use Config; use Illuminate\Support\Str; +use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; /** @@ -124,27 +125,7 @@ class Image extends Model $image->ensureDirectoryExists(); foreach (self::$ImageTypes as $coverType) { - if ($coverType['id'] === self::ORIGINAL && $image->mime === 'image/jpeg') { - $command = 'cp "'.$file->getPathname().'" '.$image->getFile($coverType['id']); - } else { - // ImageMagick options reference: http://www.imagemagick.org/script/command-line-options.php - $command = 'convert 2>&1 "'.$file->getPathname().'" -background white -alpha remove -alpha off -strip'; - - if ($image->mime === 'image/jpeg') { - $command .= ' -quality 100 -format jpeg'; - } else { - $command .= ' -quality 95 -format png'; - } - - if (isset($coverType['geometry'])) { - $command .= " -gravity center -thumbnail ${coverType['geometry']} -extent ${coverType['geometry']}"; - } - - $command .= ' "'.$image->getFile($coverType['id']).'"'; - } - - External::execute($command); - chmod($image->getFile($coverType['id']), 0644); + self::processFile($file, $image->getFile($coverType['id']), $coverType); } return $image; @@ -155,18 +136,34 @@ class Image extends Model } /** - * Finds the names of all the original-sized images uploaded to the server - * @return string[] + * Converts the image into the specified cover type to the specified path. + * + * @param File $image The image file to be processed + * @param string $path The path to save the processed image file + * @param int $coverType The type to process the image to */ - public static function getOriginalFiles() { - $rv = array(); + public static function processFile(File $image, string $path, $coverType) { + if ($coverType['id'] === self::ORIGINAL && $image->getMimeType() === 'image/jpeg') { + $command = 'cp "'.$image->getPathname().'" '.$path; + } else { + // ImageMagick options reference: http://www.imagemagick.org/script/command-line-options.php + $command = 'convert 2>&1 "'.$image->getPathname().'" -background white -alpha remove -alpha off -strip'; - //We use a cursor to cut down on memory - foreach (Image::cursor() as $image) { - $rv[] = $image->getFile(Image::ORIGINAL); + if ($image->getMimeType() === 'image/jpeg') { + $command .= ' -quality 100 -format jpeg'; + } else { + $command .= ' -quality 95 -format png'; + } + + if (isset($coverType['geometry'])) { + $command .= " -gravity center -thumbnail ${coverType['geometry']} -extent ${coverType['geometry']}"; + } + + $command .= ' "'.$path.'"'; } - return $rv; + External::execute($command); + chmod($path, 0644); } protected $table = 'images'; From d8b9795ddc03b28c052328f45816b3807c0333c3 Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 24 Nov 2017 21:02:35 -0800 Subject: [PATCH 06/13] Created Image::clearExisting and refactored upload --- app/Models/Image.php | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/app/Models/Image.php b/app/Models/Image.php index 1483af17..46a10b70 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -58,10 +58,10 @@ class Image extends Model const SMALL = 4; public static $ImageTypes = [ - self::NORMAL => ['id' => self::NORMAL, 'name' => 'normal', 'width' => 350, 'height' => 350, 'geometry' => '350'], - self::ORIGINAL => ['id' => self::ORIGINAL, 'name' => 'original', 'width' => null, 'height' => null, 'geometry' => null], - self::SMALL => ['id' => self::SMALL, 'name' => 'small', 'width' => 100, 'height' => 100, 'geometry' => '100x100^'], - self::THUMBNAIL => ['id' => self::THUMBNAIL, 'name' => 'thumbnail', 'width' => 50, 'height' => 50, 'geometry' => '50x50^'] + self::NORMAL => ['id' => self::NORMAL, 'name' => 'normal', 'width' => 350, 'height' => 350, 'geometry' => '350'], + self::ORIGINAL => ['id' => self::ORIGINAL, 'name' => 'original', 'width' => null, 'height' => null, 'geometry' => null], + self::SMALL => ['id' => self::SMALL, 'name' => 'small', 'width' => 100, 'height' => 100, 'geometry' => '100x100^'], + self::THUMBNAIL => ['id' => self::THUMBNAIL, 'name' => 'thumbnail', 'width' => 50, 'height' => 50, 'geometry' => '50x50^'] ]; public static function getImageTypeFromName($name) @@ -96,17 +96,7 @@ class Image extends Model if ($image) { if ($forceReupload) { - // delete existing versions of the image - $filenames = scandir($image->getDirectory()); - $imagePrefix = $image->id.'_'; - - $filenames = array_filter($filenames, function (string $filename) use ($imagePrefix) { - return Str::startsWith($filename, $imagePrefix); - }); - - foreach ($filenames as $filename) { - unlink($image->getDirectory().'/'.$filename); - } + $image->clearExisting(true); } else { return $image; } @@ -203,4 +193,25 @@ class Image extends Model mkdir($destination, 0777, true); } } + + /** + * Deletes any generated files if they exist + * @param bool $includeOriginal Deletes + */ + public function clearExisting($includeOriginal = false) { + $files = scandir($this->getDirectory()); + $filePrefix = $this->id.'_'; + + $files = array_filter($files, function($file) use ($includeOriginal, $filePrefix) { + $originalName = Image::$ImageTypes[Image::ORIGINAL]['name']; + + if ($file === $filePrefix.$originalName && !$includeOriginal) + return false; + else return (Str::startsWith($file, $filePrefix)); + }); + + foreach ($files as $file) { + unlink($this->getDirectory().'/'.$file); + } + } } From 917aea2f2d70d7a1bbe859cf518235cd982c8118 Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 24 Nov 2017 21:20:44 -0800 Subject: [PATCH 07/13] Implemented Commands/resizeImages --- app/Console/Commands/ResizeImages.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/Console/Commands/ResizeImages.php b/app/Console/Commands/ResizeImages.php index 0473f107..b121c348 100644 --- a/app/Console/Commands/ResizeImages.php +++ b/app/Console/Commands/ResizeImages.php @@ -3,6 +3,8 @@ namespace Poniverse\Ponyfm\Console\Commands; use Illuminate\Console\Command; +use Poniverse\Ponyfm\Models\Image; +use Symfony\Component\HttpFoundation\File\File; class ResizeImages extends Command { @@ -33,10 +35,19 @@ class ResizeImages extends Command /** * Execute the console command. * - * @return mixed + * @return void */ public function handle() { + $images = Image::all(); + foreach ($images as $image) { + $this->info("Regenerating images for ".$image->filename); + $image->clearExisting(); + $originalFile = new File($image->getFile(Image::ORIGINAL)); + foreach (Image::$ImageTypes as $imageType) { + Image::processFile($originalFile, $image->getFile($imageType['id']), $imageType); + } + } } } From e502785c2d1de6f0c1cd99f3dbf7a0b832a1d096 Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 24 Nov 2017 21:23:44 -0800 Subject: [PATCH 08/13] Renamed to RebuildImages and added to Kernel --- app/Console/Commands/{ResizeImages.php => RebuildImages.php} | 2 +- app/Console/Kernel.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) rename app/Console/Commands/{ResizeImages.php => RebuildImages.php} (97%) diff --git a/app/Console/Commands/ResizeImages.php b/app/Console/Commands/RebuildImages.php similarity index 97% rename from app/Console/Commands/ResizeImages.php rename to app/Console/Commands/RebuildImages.php index b121c348..51c6a9bf 100644 --- a/app/Console/Commands/ResizeImages.php +++ b/app/Console/Commands/RebuildImages.php @@ -6,7 +6,7 @@ use Illuminate\Console\Command; use Poniverse\Ponyfm\Models\Image; use Symfony\Component\HttpFoundation\File\File; -class ResizeImages extends Command +class RebuildImages extends Command { /** * The name and signature of the console command. diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index d7f0233d..88416f2b 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -48,6 +48,7 @@ class Kernel extends ConsoleKernel \Poniverse\Ponyfm\Console\Commands\FixMLPMAImages::class, \Poniverse\Ponyfm\Console\Commands\VersionFiles::class, \Poniverse\Ponyfm\Console\Commands\ImportEQBeats::class, + \Poniverse\Ponyfm\Console\Commands\RebuildImages::class ]; /** From e6103bbd547d9837444daaaa601d096e905954f9 Mon Sep 17 00:00:00 2001 From: Isaac Date: Fri, 24 Nov 2017 22:18:31 -0800 Subject: [PATCH 09/13] Fixed an issue with Image::clearExisting Now no longer deletes original image regardless of paramter --- app/Console/Commands/RebuildImages.php | 2 +- app/Models/Image.php | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/Console/Commands/RebuildImages.php b/app/Console/Commands/RebuildImages.php index 51c6a9bf..d2fb2048 100644 --- a/app/Console/Commands/RebuildImages.php +++ b/app/Console/Commands/RebuildImages.php @@ -41,7 +41,7 @@ class RebuildImages extends Command { $images = Image::all(); foreach ($images as $image) { - $this->info("Regenerating images for ".$image->filename); + $this->info("Regenerating images for id:".$image->id. " (".$image->filename.")"); $image->clearExisting(); $originalFile = new File($image->getFile(Image::ORIGINAL)); diff --git a/app/Models/Image.php b/app/Models/Image.php index 46a10b70..253ce857 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -201,12 +201,10 @@ class Image extends Model public function clearExisting($includeOriginal = false) { $files = scandir($this->getDirectory()); $filePrefix = $this->id.'_'; + $originalName = $filePrefix.Image::$ImageTypes[Image::ORIGINAL]['name']; - $files = array_filter($files, function($file) use ($includeOriginal, $filePrefix) { - $originalName = Image::$ImageTypes[Image::ORIGINAL]['name']; - - if ($file === $filePrefix.$originalName && !$includeOriginal) - return false; + $files = array_filter($files, function($file) use ($originalName, $includeOriginal, $filePrefix) { + if (Str::startsWith($file,$originalName) && !$includeOriginal) return false; else return (Str::startsWith($file, $filePrefix)); }); From cd348dff7debce4bfcd8dd6e19a37dd2347012cc Mon Sep 17 00:00:00 2001 From: Isaac Date: Tue, 28 Nov 2017 11:01:17 -0800 Subject: [PATCH 10/13] Added copyright to RebuildImages.php --- app/Console/Commands/RebuildImages.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/Console/Commands/RebuildImages.php b/app/Console/Commands/RebuildImages.php index d2fb2048..30b28dda 100644 --- a/app/Console/Commands/RebuildImages.php +++ b/app/Console/Commands/RebuildImages.php @@ -1,4 +1,21 @@ . + */ namespace Poniverse\Ponyfm\Console\Commands; From e5c5dec14aee3ffba84f26d0b11c60847f0418fc Mon Sep 17 00:00:00 2001 From: Isaac Date: Tue, 28 Nov 2017 11:19:36 -0800 Subject: [PATCH 11/13] Some small changes --- app/Console/Commands/RebuildImages.php | 21 +++++++++++++-------- app/Models/Image.php | 12 ++++++++---- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/app/Console/Commands/RebuildImages.php b/app/Console/Commands/RebuildImages.php index 30b28dda..38959af9 100644 --- a/app/Console/Commands/RebuildImages.php +++ b/app/Console/Commands/RebuildImages.php @@ -56,15 +56,20 @@ class RebuildImages extends Command */ public function handle() { - $images = Image::all(); - foreach ($images as $image) { - $this->info("Regenerating images for id:".$image->id. " (".$image->filename.")"); - $image->clearExisting(); + $this->info("Regenerating Images"); + $progressBar = $this->output->createProgressBar(Image::count()); - $originalFile = new File($image->getFile(Image::ORIGINAL)); - foreach (Image::$ImageTypes as $imageType) { - Image::processFile($originalFile, $image->getFile($imageType['id']), $imageType); + Image::chunk(1000, function($images) use ($progressBar) { + foreach ($images as $image) { + $image->clearExisting(); + + $originalFile = new File($image->getFile(Image::ORIGINAL)); + foreach (Image::$ImageTypes as $imageType) { + Image::processFile($originalFile, $image->getFile($imageType['id']), $imageType); + } + + $progressBar->advance(); } - } + }); } } diff --git a/app/Models/Image.php b/app/Models/Image.php index 253ce857..5f4e99e8 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -196,16 +196,20 @@ class Image extends Model /** * Deletes any generated files if they exist - * @param bool $includeOriginal Deletes + * @param bool $includeOriginal Set to true if the original image should be deleted as well. */ - public function clearExisting($includeOriginal = false) { + public function clearExisting(bool $includeOriginal = false) { $files = scandir($this->getDirectory()); $filePrefix = $this->id.'_'; $originalName = $filePrefix.Image::$ImageTypes[Image::ORIGINAL]['name']; $files = array_filter($files, function($file) use ($originalName, $includeOriginal, $filePrefix) { - if (Str::startsWith($file,$originalName) && !$includeOriginal) return false; - else return (Str::startsWith($file, $filePrefix)); + if (Str::startsWith($file,$originalName) && !$includeOriginal) { + return false; + } + else { + return (Str::startsWith($file, $filePrefix)); + } }); foreach ($files as $file) { From 821b5c5bdd6243ffdb79ef387aaeeb3b113cb811 Mon Sep 17 00:00:00 2001 From: Isaac Date: Tue, 28 Nov 2017 13:47:37 -0800 Subject: [PATCH 12/13] Moved rebuilding code into Image and added error handling. --- app/Console/Commands/RebuildImages.php | 11 +++++++---- app/Models/Image.php | 20 ++++++++++++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/app/Console/Commands/RebuildImages.php b/app/Console/Commands/RebuildImages.php index 38959af9..408af47a 100644 --- a/app/Console/Commands/RebuildImages.php +++ b/app/Console/Commands/RebuildImages.php @@ -21,6 +21,7 @@ namespace Poniverse\Ponyfm\Console\Commands; use Illuminate\Console\Command; use Poniverse\Ponyfm\Models\Image; +use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; use Symfony\Component\HttpFoundation\File\File; class RebuildImages extends Command @@ -61,11 +62,13 @@ class RebuildImages extends Command Image::chunk(1000, function($images) use ($progressBar) { foreach ($images as $image) { - $image->clearExisting(); + try { + $image->buildCovers(); + } catch (FileNotFoundException $e) { + $name = $image->filename; + $id = $image->id; - $originalFile = new File($image->getFile(Image::ORIGINAL)); - foreach (Image::$ImageTypes as $imageType) { - Image::processFile($originalFile, $image->getFile($imageType['id']), $imageType); + $this->error("Unable to process image $name (id: $id): ".$e->getMessage()); } $progressBar->advance(); diff --git a/app/Models/Image.php b/app/Models/Image.php index 5f4e99e8..ce2875c8 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -24,6 +24,7 @@ use External; use Illuminate\Database\Eloquent\Model; use Config; use Illuminate\Support\Str; +use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -64,6 +65,8 @@ class Image extends Model self::THUMBNAIL => ['id' => self::THUMBNAIL, 'name' => 'thumbnail', 'width' => 50, 'height' => 50, 'geometry' => '50x50^'] ]; + const MIME_JPEG = 'image/jpeg'; + public static function getImageTypeFromName($name) { foreach (self::$ImageTypes as $cover) { @@ -133,13 +136,13 @@ class Image extends Model * @param int $coverType The type to process the image to */ public static function processFile(File $image, string $path, $coverType) { - if ($coverType['id'] === self::ORIGINAL && $image->getMimeType() === 'image/jpeg') { + if ($coverType['id'] === self::ORIGINAL && $image->getMimeType() === self::MIME_JPEG) { $command = 'cp "'.$image->getPathname().'" '.$path; } else { // ImageMagick options reference: http://www.imagemagick.org/script/command-line-options.php $command = 'convert 2>&1 "'.$image->getPathname().'" -background white -alpha remove -alpha off -strip'; - if ($image->getMimeType() === 'image/jpeg') { + if ($image->getMimeType() === self::MIME_JPEG) { $command .= ' -quality 100 -format jpeg'; } else { $command .= ' -quality 95 -format png'; @@ -216,4 +219,17 @@ class Image extends Model unlink($this->getDirectory().'/'.$file); } } + + /** + * Builds the cover images for the image, overwriting if needed. + * + * @throws FileNotFoundException If the original file cannot be found. + */ + public function buildCovers() { + $originalFile = new File($this->getFile(self::ORIGINAL)); + + foreach (self::$ImageTypes as $imageType) { + self::processFile($originalFile, $this->getFile($imageType['id']), $imageType); + } + } } From d96fde1f5581b2ff5aa2f6a7e1f98f6670e2eeab Mon Sep 17 00:00:00 2001 From: Isaac Date: Sat, 2 Dec 2017 19:06:25 -0800 Subject: [PATCH 13/13] Minor changes --- app/Models/Image.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Models/Image.php b/app/Models/Image.php index ce2875c8..f1feef37 100644 --- a/app/Models/Image.php +++ b/app/Models/Image.php @@ -133,9 +133,9 @@ class Image extends Model * * @param File $image The image file to be processed * @param string $path The path to save the processed image file - * @param int $coverType The type to process the image to + * @param array $coverType The type to process the image to */ - public static function processFile(File $image, string $path, $coverType) { + private static function processFile(File $image, string $path, $coverType) { if ($coverType['id'] === self::ORIGINAL && $image->getMimeType() === self::MIME_JPEG) { $command = 'cp "'.$image->getPathname().'" '.$path; } else {