Enh #3978 Image scale/resize options; Added FileController for console

This commit is contained in:
Lucas Bartholemy 2020-10-12 14:44:23 +02:00
parent 2af59fa766
commit 54ae3f05cf
6 changed files with 215 additions and 3 deletions

View File

@ -48,3 +48,4 @@ HumHub Changelog
- Enh #4195: Increased scaled logo size for high res displays
- Enh #4469: Added TextConverter maximum length
- Enh #4469: Added file converter id attribute
- Enh #3978: Added option to compress and resize images automatically on upload

View File

@ -53,4 +53,27 @@ class Module extends \humhub\components\Module
*/
public $converterOptions = [];
/**
* @since 1.7
* @var string maximum image resolution before downscaling e.g. 1920x1080
*/
public $imageMaxResolution = null;
/**
* @since 1.7
* @var string The JPEG quality for uploaded JPEG images. From 0 to 100.
*/
public $imageJpegQuality = null;
/**
* @since 1.7
* @var string The PNG compression level for uploaded PNG images. From 0 to 9.
*/
public $imagePngCompressionLevel = null;
/**
* @since 1.7
* @var string The WebP quality for uploaded WebP files. From 0 to 100.
*/
public $imageWebpQuality = null;
}

View File

@ -9,6 +9,7 @@
namespace humhub\modules\file\actions;
use humhub\libs\Html;
use humhub\modules\file\libs\ImageHelper;
use Yii;
use yii\base\Action;
use yii\web\UploadedFile;
@ -96,6 +97,7 @@ class UploadAction extends Action
if ($this->record !== null) {
$this->record->fileManager->attach($file);
}
$this->afterFileUpload($file);
return array_merge(['error' => false], FileHelper::getFileInfos($file));
} else {
return $this->getErrorResponse($file);
@ -107,6 +109,18 @@ class UploadAction extends Action
return (Yii::$app->request->post('hideInStream') == 1) || (Yii::$app->request->get('hideInStream') == 1);
}
/**
* Is called after a file has been successfully uploaded and saved.
*
* @param File $file
* @since 1.7
*/
protected function afterFileUpload(File $file)
{
ImageHelper::downscaleImage($file);
}
/**
* Loads the target record by request parameter if defined.
* The default implementation only supports uploads to ContentActiveRecord or ContentAddonActiveRecords.

View File

@ -0,0 +1,95 @@
<?php
/**
* @link https://www.humhub.org/
* @copyright Copyright (c) 2020 HumHub GmbH & Co. KG
* @license https://www.humhub.com/licences
*/
namespace humhub\modules\file\commands;
use humhub\modules\file\libs\ImageHelper;
use humhub\modules\file\models\File;
use Yii;
use yii\console\widgets\Table;
/**
* Management of uploaded files
*
* @since 1.7
*/
class FileController extends \yii\console\Controller
{
/**
* Overview of uploaded files and automatically generated variants.
*/
public function actionIndex()
{
$this->stdout("*** File module console\n\n");
$fileSize = 0;
$fileSizes = [];
/** @var File $file */
foreach (File::find()->all() as $file) {
$fileSize += filesize($file->store->get());
foreach ($file->store->getVariants() as $variant) {
if (!isset($fileSizes[$variant])) {
$fileSizes[$variant] = 0;
}
$fileSizes[$variant] += filesize($file->store->get($variant));
}
}
echo Table::widget(['rows' => [
['Total number of uploaded files', File::find()->count()],
['Size', Yii::$app->formatter->asShortSize($fileSize)],
]]);
$this->stdout("\nAutomatically generated file variants:\n");
$table = [];
foreach ($fileSizes as $v => $s) {
$table[] = [$v, Yii::$app->formatter->asShortSize($s)];
}
echo Table::widget(['headers' => ['Variant', 'Size'], 'rows' => $table]);
}
/**
* Deletes all automatically generated file variants (previews, converted versions).
*/
public function actionDeleteVariants()
{
$this->stdout("*** File module console\n\n");
$this->stdout('Deleting automatically created file variants:');
/** @var File $file */
foreach (File::find()->all() as $file) {
foreach ($file->store->getVariants() as $variant) {
$file->store->delete($variant);
$this->stdout('.');
}
}
$this->stdout("OK!\n\n");
}
/**
* Scales down already uploaded images to the maximum dimensions and quality.
*/
public function actionDownscaleImages()
{
$this->stdout("*** File module console\n\n");
$this->stdout('Downscaling uploaded files:');
/** @var File $file */
foreach (File::find()->all() as $file) {
ImageHelper::downscaleImage($file);
$this->stdout('.');
}
$this->stdout("OK!\n\n");
}
}

View File

@ -13,6 +13,9 @@ return [
'id' => 'file',
'class' => Module::class,
'isCoreModule' => true,
'consoleControllerMap' => [
'file' => 'humhub\modules\file\commands\FileController'
],
'events' => [
['class' => WallEntryAddons::class, 'event' => WallEntryAddons::EVENT_INIT, 'callback' => [Events::class, 'onWallEntryAddonInit']],
['class' => CronController::class, 'event' => CronController::EVENT_ON_DAILY_RUN, 'callback' => [Events::class, 'onCronDailyRun']],

View File

@ -10,7 +10,11 @@ namespace humhub\modules\file\libs;
use humhub\modules\file\models\File;
use humhub\modules\file\Module;
use Imagine\Image\ImageInterface;
use Yii;
use yii\base\InvalidConfigException;
use yii\imagine\Image;
/**
* Class ImageHelper
@ -56,4 +60,76 @@ class ImageHelper
}
}
}
/**
* Scales down a file image if necessary.
* The limits can be defined in the File Module class.
*
* @param $file File
* @since 1.7
*/
public static function downscaleImage($file)
{
if (substr($file->mime_type, 0, 6) !== 'image/') {
return;
}
/** @var Module $module */
$module = Yii::$app->getModule('file');
// Is used to avoid saving without any configured scaling option.
$isModified = false;
$imagineOptions = [];
if ($file->mime_type === 'image/jpeg') {
if (!empty($module->imageJpegQuality)) {
$imagineOptions['jpeg_quality'] = $module->imageJpegQuality;
$isModified = true;
}
$imagineOptions['format'] = 'jpeg';
} elseif ($file->mime_type === 'image/png') {
if (!empty($module->imagePngCompressionLevel)) {
$imagineOptions['png_compression_level'] = $module->imagePngCompressionLevel;
$isModified = true;
}
$imagineOptions['format'] = 'png';
} elseif ($file->mime_type === 'image/webp') {
if (!empty($module->imageWebpQuality)) {
$imagineOptions['webp_quality'] = $module->imageWebpQuality;
$isModified = true;
}
$imagineOptions = ['format' => 'webp'];
} elseif ($file->mime_type === 'image/gif') {
$imagineOptions = ['format' => 'gif'];
} else {
return;
}
$image = Image::getImagine()->open($file->store->get());
static::fixJpegOrientation($image, $file);
if ($module->imageMaxResolution !== null) {
$maxResolution = explode('x', $module->imageMaxResolution, 2);
if (empty($maxResolution)) {
throw new InvalidConfigException('Invalid max. image resolution configured!');
}
if ($image->getSize()->getWidth() > $maxResolution[0]) {
$image->resize($image->getSize()->widen($maxResolution[0]));
$isModified = true;
}
if ($image->getSize()->getHeight() > $maxResolution[1]) {
$image->resize($image->getSize()->heighten($maxResolution[1]));
$isModified = true;
}
}
if ($isModified) {
$image->save($file->store->get(), $imagineOptions);
$file->updateAttributes(['size' => filesize($file->store->get())]);
}
}
}