pad420 Posted December 28, 2022 Share Posted December 28, 2022 I got about 4000 products on a different platform and when I try to import them with CSV to the Prestashop store 1.7.8.7 , all of the product images that had the Webp file format are completely white. I guess it's probably because Prestashop doesn't support Webp. Is there a way to fix this? Link to comment Share on other sites More sharing options...
Piotr3qx Posted December 28, 2022 Share Posted December 28, 2022 Hi, I literally had the same problem recently. I had to write a short PHP script that would convert photos from .webp to .jpg. Just a question - how do you import the products? If you manually write the import code, it's easy to fix the photos Link to comment Share on other sites More sharing options...
pad420 Posted December 28, 2022 Author Share Posted December 28, 2022 Hello, Im using the default import wizard which prestashop has on default. Never thought about making the import code myself. This is the first time Im importing products and the product images are being downloaded from a different store (at least I think since there are urls to the product images in the CSV) so I don't know if it would be possible If it's not too complicated I would really appreciate a link with a tutorial or documentation on this 🙏 3 hours ago, Piotr3qx said: Hi, I literally had the same problem recently. I had to write a short PHP script that would convert photos from .webp to .jpg. Just a question - how do you import the products? If you manually write the import code, it's easy to fix the photos Link to comment Share on other sites More sharing options...
Piotr3qx Posted December 28, 2022 Share Posted December 28, 2022 There is no documentation. I had to came up with my own solution. Later I will post my code for converting webp photos into jpegs. Is this a 'one time' import and you won't import any products in the future? If that's the case you could just write a script for updating only photos Link to comment Share on other sites More sharing options...
ps8modules Posted December 28, 2022 Share Posted December 28, 2022 (edited) Hi. If you dare, editing is easy. 1. open ./classes/ImageManager.php 2. add 3. change function isCorrectImageFileExt 4. add 5. add 6. add 7. save changes and clear cache 8. full source Prestashop 1.7.8.7 <?php /** * Copyright since 2007 PrestaShop SA and Contributors * PrestaShop is an International Registered Trademark & Property of PrestaShop SA * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.md. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/OSL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://devdocs.prestashop.com/ for more information. * * @author PrestaShop SA and Contributors <[email protected]> * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) */ /** * Class ImageManagerCore. * * This class includes functions for image manipulation * * @since 1.5.0 */ class ImageManagerCore { const ERROR_FILE_NOT_EXIST = 1; const ERROR_FILE_WIDTH = 2; const ERROR_MEMORY_LIMIT = 3; const MIME_TYPE_SUPPORTED = [ 'image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/webp', ]; /** * Generate a cached thumbnail for object lists (eg. carrier, order statuses...etc). * * @param string $image Real image filename * @param string $cacheImage Cached filename * @param int $size Desired size * @param string $imageType Image type * @param bool $disableCache When turned on a timestamp will be added to the image URI to disable the HTTP cache * @param bool $regenerate When turned on and the file already exist, the file will be regenerated * *@return string */ public static function thumbnail($image, $cacheImage, $size, $imageType = 'jpg', $disableCache = true, $regenerate = false) { if (!file_exists($image)) { return ''; } if (file_exists(_PS_TMP_IMG_DIR_ . $cacheImage) && $regenerate) { @unlink(_PS_TMP_IMG_DIR_ . $cacheImage); } if ($regenerate || !file_exists(_PS_TMP_IMG_DIR_ . $cacheImage)) { $infos = getimagesize($image); // Evaluate the memory required to resize the image: if it's too much, you can't resize it. if (!ImageManager::checkImageMemoryLimit($image)) { return false; } $x = $infos[0]; $y = $infos[1]; $maxX = $size * 3; // Size is already ok if ($y < $size && $x <= $maxX) { copy($image, _PS_TMP_IMG_DIR_ . $cacheImage); } else { // We need to resize */ $ratioX = $x / ($y / $size); if ($ratioX > $maxX) { $ratioX = $maxX; $size = $y / ($x / $maxX); } ImageManager::resize($image, _PS_TMP_IMG_DIR_ . $cacheImage, $ratioX, $size, $imageType); } } return '<img src="' . self::getThumbnailPath($cacheImage, $disableCache) . '" alt="" class="imgm img-thumbnail" />'; } /** * @param $cacheImage * @param $disableCache * * @return string */ public static function getThumbnailPath($cacheImage, $disableCache) { $cacheParam = $disableCache ? '?time=' . time() : ''; if (Context::getContext()->controller->controller_type == 'admin') { return __PS_BASE_URI__ . 'img/tmp/' . $cacheImage . $cacheParam; } return _PS_TMP_IMG_ . $cacheImage . $cacheParam; } /** * Check if memory limit is too long or not. * * @param string $image * * @return bool */ public static function checkImageMemoryLimit($image) { $infos = @getimagesize($image); if (!is_array($infos) || !isset($infos['bits'])) { return true; } $memoryLimit = Tools::getMemoryLimit(); // memory_limit == -1 => unlimited memory if (isset($infos['bits']) && function_exists('memory_get_usage') && (int) $memoryLimit != -1) { $currentMemory = memory_get_usage(); $bits = $infos['bits'] / 8; $channel = isset($infos['channels']) ? $infos['channels'] : 1; // Evaluate the memory required to resize the image: if it's too much, you can't resize it. // For perfs, avoid computing static maths formulas in the code. pow(2, 16) = 65536 ; 1024 * 1024 = 1048576 if (($infos[0] * $infos[1] * $bits * $channel + 65536) * 1.8 + $currentMemory > $memoryLimit - 1048576) { return false; } } return true; } /** * Resize, cut and optimize image. * * @param string $sourceFile Image object from $_FILE * @param string $destinationFile Destination filename * @param int $destinationWidth Desired width (optional) * @param int $destinationHeight Desired height (optional) * @param string $fileType Desired file_type (may be override by PS_IMAGE_QUALITY) * @param bool $forceType Don't override $file_type * @param int $error Out error code * @param int $targetWidth Needed by AdminImportController to speed up the import process * @param int $targetHeight Needed by AdminImportController to speed up the import process * @param int $quality Needed by AdminImportController to speed up the import process * @param int $sourceWidth Needed by AdminImportController to speed up the import process * @param int $sourceHeight Needed by AdminImportController to speed up the import process * *@return bool Operation result */ public static function resize( $sourceFile, $destinationFile, $destinationWidth = null, $destinationHeight = null, $fileType = 'jpg', $forceType = false, &$error = 0, &$targetWidth = null, &$targetHeight = null, $quality = 5, &$sourceWidth = null, &$sourceHeight = null ) { clearstatcache(true, $sourceFile); if (!file_exists($sourceFile) || !filesize($sourceFile)) { return !($error = self::ERROR_FILE_NOT_EXIST); } list($tmpWidth, $tmpHeight, $type) = getimagesize($sourceFile); $rotate = 0; if (function_exists('exif_read_data') && function_exists('mb_strtolower')) { $exif = @exif_read_data($sourceFile); if ($exif && isset($exif['Orientation'])) { switch ($exif['Orientation']) { case 3: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; $rotate = 180; break; case 6: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = -90; break; case 8: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = 90; break; default: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } // If PS_IMAGE_QUALITY is activated, the generated image will be a PNG with .jpg as a file extension. // This allow for higher quality and for transparency. JPG source files will also benefit from a higher quality // because JPG reencoding by GD, even with max quality setting, degrades the image. if (Configuration::get('PS_IMAGE_QUALITY') == 'png_all' || (Configuration::get('PS_IMAGE_QUALITY') == 'png' && $type == IMAGETYPE_PNG) && !$forceType) { $fileType = 'png'; } if (!$sourceWidth) { return !($error = self::ERROR_FILE_WIDTH); } if (!$destinationWidth) { $destinationWidth = $sourceWidth; } if (!$destinationHeight) { $destinationHeight = $sourceHeight; } $widthDiff = $destinationWidth / $sourceWidth; $heightDiff = $destinationHeight / $sourceHeight; $psImageGenerationMethod = Configuration::get('PS_IMAGE_GENERATION_METHOD'); if ($widthDiff > 1 && $heightDiff > 1) { $nextWidth = $sourceWidth; $nextHeight = $sourceHeight; } else { if ($psImageGenerationMethod == 2 || (!$psImageGenerationMethod && $widthDiff > $heightDiff)) { $nextHeight = $destinationHeight; $nextWidth = round(($sourceWidth * $nextHeight) / $sourceHeight); $destinationWidth = (int) (!$psImageGenerationMethod ? $destinationWidth : $nextWidth); } else { $nextWidth = $destinationWidth; $nextHeight = round($sourceHeight * $destinationWidth / $sourceWidth); $destinationHeight = (int) (!$psImageGenerationMethod ? $destinationHeight : $nextHeight); } } if (!ImageManager::checkImageMemoryLimit($sourceFile)) { return !($error = self::ERROR_MEMORY_LIMIT); } $targetWidth = $destinationWidth; $targetHeight = $destinationHeight; $destImage = imagecreatetruecolor($destinationWidth, $destinationHeight); // If image is a PNG and the output is PNG, fill with transparency. Else fill with white background. if ($fileType == 'png' && $type == IMAGETYPE_PNG) { imagealphablending($destImage, false); imagesavealpha($destImage, true); $transparent = imagecolorallocatealpha($destImage, 255, 255, 255, 127); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $transparent); } else { $white = imagecolorallocate($destImage, 255, 255, 255); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $white); } $srcImage = ImageManager::create($type, $sourceFile); if ($rotate) { $srcImage = imagerotate($srcImage, $rotate, 0); } if ($destinationWidth >= $sourceWidth && $destinationHeight >= $sourceHeight) { imagecopyresized($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight); } else { ImageManager::imagecopyresampled($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight, $quality); } $writeFile = ImageManager::write($fileType, $destImage, $destinationFile); Hook::exec('actionOnImageResizeAfter', ['dst_file' => $destinationFile, 'file_type' => $fileType]); @imagedestroy($srcImage); file_put_contents( dirname($destinationFile) . DIRECTORY_SEPARATOR . 'fileType', $fileType ); return $writeFile; } /** * @param $dstImage * @param $srcImage * @param $dstX * @param $dstY * @param $srcX * @param $srcY * @param $dstW * @param $dstH * @param $srcW * @param $srcH * @param int $quality * * @return bool */ public static function imagecopyresampled( &$dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH, $quality = 3 ) { // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled. // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled". // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting. // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain. // // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero. // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect. // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized. // 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3. // 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster. // 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images. // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled. if (empty($srcImage) || empty($dstImage) || $quality <= 0) { return false; } if ($quality < 5 && (($dstW * $quality) < $srcW || ($dstH * $quality) < $srcH)) { $temp = imagecreatetruecolor($dstW * $quality + 1, $dstH * $quality + 1); imagecopyresized($temp, $srcImage, 0, 0, $srcX, $srcY, $dstW * $quality + 1, $dstH * $quality + 1, $srcW, $srcH); imagecopyresampled($dstImage, $temp, $dstX, $dstY, 0, 0, $dstW, $dstH, $dstW * $quality, $dstH * $quality); imagedestroy($temp); } else { imagecopyresampled($dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); } return true; } /** * @param string $filename * * @return string|bool */ public static function getMimeType(string $filename) { $mimeType = false; // Try with GD if (function_exists('getimagesize')) { $imageInfo = @getimagesize($filename); if ($imageInfo) { $mimeType = $imageInfo['mime']; } } // Try with FileInfo if (!$mimeType && function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mimeType = finfo_file($finfo, $filename); finfo_close($finfo); } // Try with Mime if (!$mimeType && function_exists('mime_content_type')) { $mimeType = mime_content_type($filename); } // Try with exec command and file binary if (!$mimeType && function_exists('exec')) { $mimeType = trim(exec('file -b --mime-type ' . escapeshellarg($filename))); if (!$mimeType) { $mimeType = trim(exec('file --mime ' . escapeshellarg($filename))); } if (!$mimeType) { $mimeType = trim(exec('file -bi ' . escapeshellarg($filename))); } } return $mimeType; } /** * Check if file is a real image. * * @param string $filename File path to check * @param string $fileMimeType File known mime type (generally from $_FILES) * @param array<string>|null $mimeTypeList Allowed MIME types * * @return bool */ public static function isRealImage($filename, $fileMimeType = null, $mimeTypeList = null) { if (!$mimeTypeList) { $mimeTypeList = static::MIME_TYPE_SUPPORTED; } $mimeType = static::getMimeType($filename); if ($fileMimeType && (empty($mimeType) || $mimeType == 'regular file' || $mimeType == 'text/plain')) { $mimeType = $fileMimeType; } // For each allowed MIME type, we are looking for it inside the current MIME type foreach ($mimeTypeList as $type) { if (strstr($mimeType, $type)) { return true; } } return false; } /** * Check if image file extension is correct. * * @param string $filename Real filename * @param array|null $authorizedExtensions * * @return bool True if it's correct */ public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension //if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; //} $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } /*if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true;*/ } /** * Validate image upload (check image type and weight). * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * @param array<string>|null $types Authorized extensions * @param array<string>|null $mimeTypeList Authorized mimetypes * * @return bool|string Return false if no error encountered */ public static function validateUpload($file, $maxFileSize = 0, $types = null, $mimeTypeList = null) { if ((int) $maxFileSize > 0 && $file['size'] > (int) $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1024, $maxFileSize / 1024], 'Admin.Notifications.Error'); } if (!ImageManager::isRealImage($file['tmp_name'], $file['type'], $mimeTypeList) || !ImageManager::isCorrectImageFileExt($file['name'], $types) || preg_match('/\%00/', $file['name'])) { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .gif, .jpg, .png, .webp', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings. (Error code: %s)', [$file['error']], 'Admin.Notifications.Error'); } return false; } /** * Validate icon upload. * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * * @return bool|string Return false if no error encountered */ public static function validateIconUpload($file, $maxFileSize = 0) { if ((int) $maxFileSize > 0 && $file['size'] > $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1000, $maxFileSize / 1000], 'Admin.Notifications.Error'); } if (substr($file['name'], -4) != '.ico') { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .ico', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings.', [], 'Admin.Notifications.Error'); } return false; } /** * Cut image. * * @param array $srcFile Origin filename * @param string $dstFile Destination filename * @param int $dstWidth Desired width * @param int $dstHeight Desired height * @param string $fileType * @param int $dstX * @param int $dstY * * @return bool Operation result */ public static function cut($srcFile, $dstFile, $dstWidth = null, $dstHeight = null, $fileType = 'jpg', $dstX = 0, $dstY = 0) { if (!file_exists($srcFile)) { return false; } // Source information $srcInfo = getimagesize($srcFile); $src = [ 'width' => $srcInfo[0], 'height' => $srcInfo[1], 'ressource' => ImageManager::create($srcInfo[2], $srcFile), ]; // Destination information $dest = []; $dest['x'] = $dstX; $dest['y'] = $dstY; $dest['width'] = null !== $dstWidth ? $dstWidth : $src['width']; $dest['height'] = null !== $dstHeight ? $dstHeight : $src['height']; $dest['ressource'] = ImageManager::createWhiteImage($dest['width'], $dest['height']); $white = imagecolorallocate($dest['ressource'], 255, 255, 255); imagecopyresampled($dest['ressource'], $src['ressource'], 0, 0, $dest['x'], $dest['y'], $dest['width'], $dest['height'], $dest['width'], $dest['height']); imagecolortransparent($dest['ressource'], $white); $return = ImageManager::write($fileType, $dest['ressource'], $dstFile); Hook::exec('actionOnImageCutAfter', ['dst_file' => $dstFile, 'file_type' => $fileType]); @imagedestroy($src['ressource']); return $return; } /** * Create an image with GD extension from a given type. * * @param string $type * @param string $filename * * @return resource */ public static function create($type, $filename) { switch ($type) { case IMAGETYPE_GIF: return imagecreatefromgif($filename); break; case IMAGETYPE_PNG: return imagecreatefrompng($filename); break; case IMAGETYPE_WEBP: return imagecreatefromwebp($filename); break; case IMAGETYPE_JPEG: default: return imagecreatefromjpeg($filename); break; } } /** * Create an empty image with white background. * * @param int $width * @param int $height * * @return resource */ public static function createWhiteImage($width, $height) { $image = imagecreatetruecolor($width, $height); $white = imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $white); return $image; } /** * Generate and write image. * * @param string $type * @param resource $resource * @param string $filename * * @return bool */ public static function write($type, $resource, $filename) { static $psPngQuality = null; static $psJpegQuality = null; if ($psPngQuality === null) { $psPngQuality = Configuration::get('PS_PNG_QUALITY'); } if ($psJpegQuality === null) { $psJpegQuality = Configuration::get('PS_JPEG_QUALITY'); } switch ($type) { case 'gif': $success = imagegif($resource, $filename); break; case 'png': $quality = ($psPngQuality === false ? 7 : $psPngQuality); $success = imagepng($resource, $filename, (int) $quality); break; case 'jpg': case 'jpeg': default: $quality = ($psJpegQuality === false ? 90 : $psJpegQuality); imageinterlace($resource, 1); /// make it PROGRESSIVE $success = imagejpeg($resource, $filename, (int) $quality); break; } imagedestroy($resource); @chmod($filename, 0664); return $success; } /** * Return the mime type by the file extension. * * @param string $fileName * * @return string */ public static function getMimeTypeByExtension($fileName) { $types = [ 'image/gif' => ['gif'], 'image/jpeg' => ['jpg', 'jpeg'], 'image/png' => ['png'], 'image/webp' => ['webp'], ]; $extension = substr($fileName, strrpos($fileName, '.') + 1); $mimeType = null; foreach ($types as $mime => $exts) { if (in_array($extension, $exts)) { $mimeType = $mime; break; } } if ($mimeType === null) { $mimeType = 'image/jpeg'; } return $mimeType; } } Edited December 28, 2022 by prestashopfree.com (see edit history) 1 3 Link to comment Share on other sites More sharing options...
knacky Posted December 29, 2022 Share Posted December 29, 2022 Hi. Thank you, it works perfectly. Now I can also upload images in the webP product administration. I also tested import from CSV and it works too. Good work. 1 Link to comment Share on other sites More sharing options...
pad420 Posted December 29, 2022 Author Share Posted December 29, 2022 It worked! Much appreciated. 1 Link to comment Share on other sites More sharing options...
ps8modules Posted December 29, 2022 Share Posted December 29, 2022 I gladly helped 😉 Link to comment Share on other sites More sharing options...
juanrojas Posted December 29, 2022 Share Posted December 29, 2022 I've tried it and it doesn't work Link to comment Share on other sites More sharing options...
pad420 Posted December 29, 2022 Author Share Posted December 29, 2022 12 minutes ago, juanrojas said: I've tried it and it doesn't work Try to copy and paste the source code, when I followed the steps it didn't work as well. 1 Link to comment Share on other sites More sharing options...
ps8modules Posted December 29, 2022 Share Posted December 29, 2022 ......... full source Prestashop 1.7.8.7 Link to comment Share on other sites More sharing options...
Mediacom87 Posted December 29, 2022 Share Posted December 29, 2022 Hi, subject discussed on GitHub in this thread: https://github.com/PrestaShop/PrestaShop/pull/24394 Link to comment Share on other sites More sharing options...
ps8modules Posted December 29, 2022 Share Posted December 29, 2022 34 minutes ago, Mediacom87 said: Hi, subject discussed on GitHub in this thread: https://github.com/PrestaShop/PrestaShop/pull/24394 Now it's discussed here, not on github. Prestashop developers have made it clear that they will not build any new features. The interviewer needed a modification to import webP images. Now it can without any problems. A functional solution was given to the question in the form of Ctrl + C / Ctrl + V. Link to comment Share on other sites More sharing options...
Mediacom87 Posted December 29, 2022 Share Posted December 29, 2022 il y a 14 minutes, prestashopfree.com a dit : Now it's discussed here, not on github. Prestashop developers have made it clear that they will not build any new features. The interviewer needed a modification to import webP images. Now it can without any problems. A functional solution was given to the question in the form of Ctrl + C / Ctrl + V. I was just sharing additional information to fuel the debate, relax. 1 Link to comment Share on other sites More sharing options...
ps8modules Posted December 29, 2022 Share Posted December 29, 2022 People here need immediate solutions. When they want to read a serial without a resulting ending, they will go to github. How long does it take to solve something on github? I'm calm, I just take it as pointless to write a link here to something that is not resolved and won't be for a long time. Link to comment Share on other sites More sharing options...
Mediacom87 Posted December 29, 2022 Share Posted December 29, 2022 il y a 7 minutes, prestashopfree.com a dit : People here need immediate solutions. When they want to read a serial without a resulting ending, they will go to github. How long does it take to solve something on github? I'm calm, I just take it as pointless to write a link here to something that is not resolved and won't be for a long time. The solution is integrated into the code since October 15, 2021 The solution is given with all the modified files and it was validated by several people After that, I don't know if it integrates as is on any version of PrestaShop, but what I do know is that someone who stumbles on this topic will have access to additional information if he wants to go further in his learning. It is possible that some people like to be given a ready-made solution without thinking, but I know many others who seek to learn to be more independent in their store management so one does not prevent the other. Link to comment Share on other sites More sharing options...
juanrojas Posted December 29, 2022 Share Posted December 29, 2022 hace 5 horas, prestashopfree.com dijo: ......... fuente completa Prestashop 1.7.8.7 I confirm for 1.7.8.8 it does not work, paste the complete file, it works fine apparently, but when you try to enter modules it gives problems Link to comment Share on other sites More sharing options...
mdmax Posted April 8, 2023 Share Posted April 8, 2023 Hi. Can anyone post solution for prestashop 1.6.1.24? I tried the solution above for prestashop 1.7.8.7 but it didn't work. Any help is appreciated. Link to comment Share on other sites More sharing options...
gouna Posted June 6, 2023 Share Posted June 6, 2023 Hi, Do you have a solution for prestashop 1.7.8.8 and 1.7.8.9? THANKS Link to comment Share on other sites More sharing options...
Roger Głowacki Posted July 28, 2023 Share Posted July 28, 2023 On 12/28/2022 at 5:16 PM, ps8moduly.cz said: Hi. If you dare, editing is easy. 1. open ./classes/ImageManager.php 2. add 3. change function isCorrectImageFileExt 4. add 5. add 6. add 7. save changes and clear cache 8. full source Prestashop 1.7.8.7 <?php /** * Copyright since 2007 PrestaShop SA and Contributors * PrestaShop is an International Registered Trademark & Property of PrestaShop SA * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.md. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/OSL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://devdocs.prestashop.com/ for more information. * * @author PrestaShop SA and Contributors <[email protected]> * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) */ /** * Class ImageManagerCore. * * This class includes functions for image manipulation * * @since 1.5.0 */ class ImageManagerCore { const ERROR_FILE_NOT_EXIST = 1; const ERROR_FILE_WIDTH = 2; const ERROR_MEMORY_LIMIT = 3; const MIME_TYPE_SUPPORTED = [ 'image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/webp', ]; /** * Generate a cached thumbnail for object lists (eg. carrier, order statuses...etc). * * @param string $image Real image filename * @param string $cacheImage Cached filename * @param int $size Desired size * @param string $imageType Image type * @param bool $disableCache When turned on a timestamp will be added to the image URI to disable the HTTP cache * @param bool $regenerate When turned on and the file already exist, the file will be regenerated * *@return string */ public static function thumbnail($image, $cacheImage, $size, $imageType = 'jpg', $disableCache = true, $regenerate = false) { if (!file_exists($image)) { return ''; } if (file_exists(_PS_TMP_IMG_DIR_ . $cacheImage) && $regenerate) { @unlink(_PS_TMP_IMG_DIR_ . $cacheImage); } if ($regenerate || !file_exists(_PS_TMP_IMG_DIR_ . $cacheImage)) { $infos = getimagesize($image); // Evaluate the memory required to resize the image: if it's too much, you can't resize it. if (!ImageManager::checkImageMemoryLimit($image)) { return false; } $x = $infos[0]; $y = $infos[1]; $maxX = $size * 3; // Size is already ok if ($y < $size && $x <= $maxX) { copy($image, _PS_TMP_IMG_DIR_ . $cacheImage); } else { // We need to resize */ $ratioX = $x / ($y / $size); if ($ratioX > $maxX) { $ratioX = $maxX; $size = $y / ($x / $maxX); } ImageManager::resize($image, _PS_TMP_IMG_DIR_ . $cacheImage, $ratioX, $size, $imageType); } } return '<img src="' . self::getThumbnailPath($cacheImage, $disableCache) . '" alt="" class="imgm img-thumbnail" />'; } /** * @param $cacheImage * @param $disableCache * * @return string */ public static function getThumbnailPath($cacheImage, $disableCache) { $cacheParam = $disableCache ? '?time=' . time() : ''; if (Context::getContext()->controller->controller_type == 'admin') { return __PS_BASE_URI__ . 'img/tmp/' . $cacheImage . $cacheParam; } return _PS_TMP_IMG_ . $cacheImage . $cacheParam; } /** * Check if memory limit is too long or not. * * @param string $image * * @return bool */ public static function checkImageMemoryLimit($image) { $infos = @getimagesize($image); if (!is_array($infos) || !isset($infos['bits'])) { return true; } $memoryLimit = Tools::getMemoryLimit(); // memory_limit == -1 => unlimited memory if (isset($infos['bits']) && function_exists('memory_get_usage') && (int) $memoryLimit != -1) { $currentMemory = memory_get_usage(); $bits = $infos['bits'] / 8; $channel = isset($infos['channels']) ? $infos['channels'] : 1; // Evaluate the memory required to resize the image: if it's too much, you can't resize it. // For perfs, avoid computing static maths formulas in the code. pow(2, 16) = 65536 ; 1024 * 1024 = 1048576 if (($infos[0] * $infos[1] * $bits * $channel + 65536) * 1.8 + $currentMemory > $memoryLimit - 1048576) { return false; } } return true; } /** * Resize, cut and optimize image. * * @param string $sourceFile Image object from $_FILE * @param string $destinationFile Destination filename * @param int $destinationWidth Desired width (optional) * @param int $destinationHeight Desired height (optional) * @param string $fileType Desired file_type (may be override by PS_IMAGE_QUALITY) * @param bool $forceType Don't override $file_type * @param int $error Out error code * @param int $targetWidth Needed by AdminImportController to speed up the import process * @param int $targetHeight Needed by AdminImportController to speed up the import process * @param int $quality Needed by AdminImportController to speed up the import process * @param int $sourceWidth Needed by AdminImportController to speed up the import process * @param int $sourceHeight Needed by AdminImportController to speed up the import process * *@return bool Operation result */ public static function resize( $sourceFile, $destinationFile, $destinationWidth = null, $destinationHeight = null, $fileType = 'jpg', $forceType = false, &$error = 0, &$targetWidth = null, &$targetHeight = null, $quality = 5, &$sourceWidth = null, &$sourceHeight = null ) { clearstatcache(true, $sourceFile); if (!file_exists($sourceFile) || !filesize($sourceFile)) { return !($error = self::ERROR_FILE_NOT_EXIST); } list($tmpWidth, $tmpHeight, $type) = getimagesize($sourceFile); $rotate = 0; if (function_exists('exif_read_data') && function_exists('mb_strtolower')) { $exif = @exif_read_data($sourceFile); if ($exif && isset($exif['Orientation'])) { switch ($exif['Orientation']) { case 3: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; $rotate = 180; break; case 6: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = -90; break; case 8: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = 90; break; default: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } // If PS_IMAGE_QUALITY is activated, the generated image will be a PNG with .jpg as a file extension. // This allow for higher quality and for transparency. JPG source files will also benefit from a higher quality // because JPG reencoding by GD, even with max quality setting, degrades the image. if (Configuration::get('PS_IMAGE_QUALITY') == 'png_all' || (Configuration::get('PS_IMAGE_QUALITY') == 'png' && $type == IMAGETYPE_PNG) && !$forceType) { $fileType = 'png'; } if (!$sourceWidth) { return !($error = self::ERROR_FILE_WIDTH); } if (!$destinationWidth) { $destinationWidth = $sourceWidth; } if (!$destinationHeight) { $destinationHeight = $sourceHeight; } $widthDiff = $destinationWidth / $sourceWidth; $heightDiff = $destinationHeight / $sourceHeight; $psImageGenerationMethod = Configuration::get('PS_IMAGE_GENERATION_METHOD'); if ($widthDiff > 1 && $heightDiff > 1) { $nextWidth = $sourceWidth; $nextHeight = $sourceHeight; } else { if ($psImageGenerationMethod == 2 || (!$psImageGenerationMethod && $widthDiff > $heightDiff)) { $nextHeight = $destinationHeight; $nextWidth = round(($sourceWidth * $nextHeight) / $sourceHeight); $destinationWidth = (int) (!$psImageGenerationMethod ? $destinationWidth : $nextWidth); } else { $nextWidth = $destinationWidth; $nextHeight = round($sourceHeight * $destinationWidth / $sourceWidth); $destinationHeight = (int) (!$psImageGenerationMethod ? $destinationHeight : $nextHeight); } } if (!ImageManager::checkImageMemoryLimit($sourceFile)) { return !($error = self::ERROR_MEMORY_LIMIT); } $targetWidth = $destinationWidth; $targetHeight = $destinationHeight; $destImage = imagecreatetruecolor($destinationWidth, $destinationHeight); // If image is a PNG and the output is PNG, fill with transparency. Else fill with white background. if ($fileType == 'png' && $type == IMAGETYPE_PNG) { imagealphablending($destImage, false); imagesavealpha($destImage, true); $transparent = imagecolorallocatealpha($destImage, 255, 255, 255, 127); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $transparent); } else { $white = imagecolorallocate($destImage, 255, 255, 255); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $white); } $srcImage = ImageManager::create($type, $sourceFile); if ($rotate) { $srcImage = imagerotate($srcImage, $rotate, 0); } if ($destinationWidth >= $sourceWidth && $destinationHeight >= $sourceHeight) { imagecopyresized($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight); } else { ImageManager::imagecopyresampled($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight, $quality); } $writeFile = ImageManager::write($fileType, $destImage, $destinationFile); Hook::exec('actionOnImageResizeAfter', ['dst_file' => $destinationFile, 'file_type' => $fileType]); @imagedestroy($srcImage); file_put_contents( dirname($destinationFile) . DIRECTORY_SEPARATOR . 'fileType', $fileType ); return $writeFile; } /** * @param $dstImage * @param $srcImage * @param $dstX * @param $dstY * @param $srcX * @param $srcY * @param $dstW * @param $dstH * @param $srcW * @param $srcH * @param int $quality * * @return bool */ public static function imagecopyresampled( &$dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH, $quality = 3 ) { // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled. // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled". // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting. // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain. // // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero. // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect. // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized. // 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3. // 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster. // 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images. // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled. if (empty($srcImage) || empty($dstImage) || $quality <= 0) { return false; } if ($quality < 5 && (($dstW * $quality) < $srcW || ($dstH * $quality) < $srcH)) { $temp = imagecreatetruecolor($dstW * $quality + 1, $dstH * $quality + 1); imagecopyresized($temp, $srcImage, 0, 0, $srcX, $srcY, $dstW * $quality + 1, $dstH * $quality + 1, $srcW, $srcH); imagecopyresampled($dstImage, $temp, $dstX, $dstY, 0, 0, $dstW, $dstH, $dstW * $quality, $dstH * $quality); imagedestroy($temp); } else { imagecopyresampled($dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); } return true; } /** * @param string $filename * * @return string|bool */ public static function getMimeType(string $filename) { $mimeType = false; // Try with GD if (function_exists('getimagesize')) { $imageInfo = @getimagesize($filename); if ($imageInfo) { $mimeType = $imageInfo['mime']; } } // Try with FileInfo if (!$mimeType && function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mimeType = finfo_file($finfo, $filename); finfo_close($finfo); } // Try with Mime if (!$mimeType && function_exists('mime_content_type')) { $mimeType = mime_content_type($filename); } // Try with exec command and file binary if (!$mimeType && function_exists('exec')) { $mimeType = trim(exec('file -b --mime-type ' . escapeshellarg($filename))); if (!$mimeType) { $mimeType = trim(exec('file --mime ' . escapeshellarg($filename))); } if (!$mimeType) { $mimeType = trim(exec('file -bi ' . escapeshellarg($filename))); } } return $mimeType; } /** * Check if file is a real image. * * @param string $filename File path to check * @param string $fileMimeType File known mime type (generally from $_FILES) * @param array<string>|null $mimeTypeList Allowed MIME types * * @return bool */ public static function isRealImage($filename, $fileMimeType = null, $mimeTypeList = null) { if (!$mimeTypeList) { $mimeTypeList = static::MIME_TYPE_SUPPORTED; } $mimeType = static::getMimeType($filename); if ($fileMimeType && (empty($mimeType) || $mimeType == 'regular file' || $mimeType == 'text/plain')) { $mimeType = $fileMimeType; } // For each allowed MIME type, we are looking for it inside the current MIME type foreach ($mimeTypeList as $type) { if (strstr($mimeType, $type)) { return true; } } return false; } /** * Check if image file extension is correct. * * @param string $filename Real filename * @param array|null $authorizedExtensions * * @return bool True if it's correct */ public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension //if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; //} $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } /*if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true;*/ } /** * Validate image upload (check image type and weight). * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * @param array<string>|null $types Authorized extensions * @param array<string>|null $mimeTypeList Authorized mimetypes * * @return bool|string Return false if no error encountered */ public static function validateUpload($file, $maxFileSize = 0, $types = null, $mimeTypeList = null) { if ((int) $maxFileSize > 0 && $file['size'] > (int) $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1024, $maxFileSize / 1024], 'Admin.Notifications.Error'); } if (!ImageManager::isRealImage($file['tmp_name'], $file['type'], $mimeTypeList) || !ImageManager::isCorrectImageFileExt($file['name'], $types) || preg_match('/\%00/', $file['name'])) { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .gif, .jpg, .png, .webp', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings. (Error code: %s)', [$file['error']], 'Admin.Notifications.Error'); } return false; } /** * Validate icon upload. * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * * @return bool|string Return false if no error encountered */ public static function validateIconUpload($file, $maxFileSize = 0) { if ((int) $maxFileSize > 0 && $file['size'] > $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1000, $maxFileSize / 1000], 'Admin.Notifications.Error'); } if (substr($file['name'], -4) != '.ico') { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .ico', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings.', [], 'Admin.Notifications.Error'); } return false; } /** * Cut image. * * @param array $srcFile Origin filename * @param string $dstFile Destination filename * @param int $dstWidth Desired width * @param int $dstHeight Desired height * @param string $fileType * @param int $dstX * @param int $dstY * * @return bool Operation result */ public static function cut($srcFile, $dstFile, $dstWidth = null, $dstHeight = null, $fileType = 'jpg', $dstX = 0, $dstY = 0) { if (!file_exists($srcFile)) { return false; } // Source information $srcInfo = getimagesize($srcFile); $src = [ 'width' => $srcInfo[0], 'height' => $srcInfo[1], 'ressource' => ImageManager::create($srcInfo[2], $srcFile), ]; // Destination information $dest = []; $dest['x'] = $dstX; $dest['y'] = $dstY; $dest['width'] = null !== $dstWidth ? $dstWidth : $src['width']; $dest['height'] = null !== $dstHeight ? $dstHeight : $src['height']; $dest['ressource'] = ImageManager::createWhiteImage($dest['width'], $dest['height']); $white = imagecolorallocate($dest['ressource'], 255, 255, 255); imagecopyresampled($dest['ressource'], $src['ressource'], 0, 0, $dest['x'], $dest['y'], $dest['width'], $dest['height'], $dest['width'], $dest['height']); imagecolortransparent($dest['ressource'], $white); $return = ImageManager::write($fileType, $dest['ressource'], $dstFile); Hook::exec('actionOnImageCutAfter', ['dst_file' => $dstFile, 'file_type' => $fileType]); @imagedestroy($src['ressource']); return $return; } /** * Create an image with GD extension from a given type. * * @param string $type * @param string $filename * * @return resource */ public static function create($type, $filename) { switch ($type) { case IMAGETYPE_GIF: return imagecreatefromgif($filename); break; case IMAGETYPE_PNG: return imagecreatefrompng($filename); break; case IMAGETYPE_WEBP: return imagecreatefromwebp($filename); break; case IMAGETYPE_JPEG: default: return imagecreatefromjpeg($filename); break; } } /** * Create an empty image with white background. * * @param int $width * @param int $height * * @return resource */ public static function createWhiteImage($width, $height) { $image = imagecreatetruecolor($width, $height); $white = imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $white); return $image; } /** * Generate and write image. * * @param string $type * @param resource $resource * @param string $filename * * @return bool */ public static function write($type, $resource, $filename) { static $psPngQuality = null; static $psJpegQuality = null; if ($psPngQuality === null) { $psPngQuality = Configuration::get('PS_PNG_QUALITY'); } if ($psJpegQuality === null) { $psJpegQuality = Configuration::get('PS_JPEG_QUALITY'); } switch ($type) { case 'gif': $success = imagegif($resource, $filename); break; case 'png': $quality = ($psPngQuality === false ? 7 : $psPngQuality); $success = imagepng($resource, $filename, (int) $quality); break; case 'jpg': case 'jpeg': default: $quality = ($psJpegQuality === false ? 90 : $psJpegQuality); imageinterlace($resource, 1); /// make it PROGRESSIVE $success = imagejpeg($resource, $filename, (int) $quality); break; } imagedestroy($resource); @chmod($filename, 0664); return $success; } /** * Return the mime type by the file extension. * * @param string $fileName * * @return string */ public static function getMimeTypeByExtension($fileName) { $types = [ 'image/gif' => ['gif'], 'image/jpeg' => ['jpg', 'jpeg'], 'image/png' => ['png'], 'image/webp' => ['webp'], ]; $extension = substr($fileName, strrpos($fileName, '.') + 1); $mimeType = null; foreach ($types as $mime => $exts) { if (in_array($extension, $exts)) { $mimeType = $mime; break; } } if ($mimeType === null) { $mimeType = 'image/jpeg'; } return $mimeType; } } please notice, that this modification only makes pseudo WebP file; obviously, PrestaShop now allow to upload *.webp file, but still write (convert) image to JPEG format; the uploaded file has *.webp extenstion, but is still JPEG image; this is wrong; you can check this by download any uploaded image and review his metadata (for example by open it in GIMP and view Image > Image Properties); to make real WebP format on upload image, should do one more step; edit ImageManager.php file and add few line to "write" function, as shown in screenshot; Link to comment Share on other sites More sharing options...
@diegofrancesco Posted September 21, 2023 Share Posted September 21, 2023 Hello everyone, I have applied all the changes, by ps8moduly.cz even the last one indicated by Roger Głowacki. I also followed the instructions on Github. The product images in webp are loaded, without errors, but in reality it is a jpg image. In other parts of the template I noticed that webp images are accepted, this even before editing the source files. (I have a development and operational version of the site). It seems that it does not accept product and category images in the webp format. Why does this happen? Ps v 1.7.8.9 Thanks in advance Link to comment Share on other sites More sharing options...
Stewarti89 Posted September 22, 2023 Share Posted September 22, 2023 I am facing the same error in webp image and looking for solution. But after reading this discussion I am still confused what is the exact solution.😒 Link to comment Share on other sites More sharing options...
Talbi ConSept Posted March 28 Share Posted March 28 (edited) Hello, It is maybe late, but will help some users. In addition to "ps8modules.com" answer, you also need to change the function isCorrectImageFileExt on the "./classes/ImageManager.php" file: After this code: // Filter on file extension if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; } Add this: if(!in_array('webp', $authorizedExtensions)){ $authorizedExtensions[] = 'webp'; } Good luck Edited March 28 by Talbi ConSept (see edit history) 1 Link to comment Share on other sites More sharing options...
gouna Posted March 28 Share Posted March 28 Does this solution work with Prestashop 1.7.8.11? THANKS Link to comment Share on other sites More sharing options...
Talbi ConSept Posted March 28 Share Posted March 28 59 minutes ago, gouna said: Does this solution work with Prestashop 1.7.8.11? THANKS Yes it is working 1 Link to comment Share on other sites More sharing options...
gouna Posted March 28 Share Posted March 28 Il y a 6 heures, Talbi ConSept a dit : ... In addition to "ps8modules.com" answer, you also need to change the function isCorrectImageFileExt on the "./classes/ImageManager.php" file: After this code: // Filter on file extension if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; } Add this: if(!in_array('webp', $authorizedExtensions)){ $authorizedExtensions[] = 'webp'; } ps8modules.com recommends this code: public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension //if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; //} $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } /*if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true;*/ } Should it be modified like this ? (for PS 1.7.8.11) : public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; } if(!in_array('webp', $authorizedExtensions)){ $authorizedExtensions[] = 'webp'; } $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } /*if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true;*/ } Thank's ! Link to comment Share on other sites More sharing options...
Talbi ConSept Posted March 28 Share Posted March 28 3 hours ago, gouna said: ps8modules.com recommends this code: public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension //if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; //} $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } /*if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true;*/ } Should it be modified like this ? (for PS 1.7.8.11) : public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; } if(!in_array('webp', $authorizedExtensions)){ $authorizedExtensions[] = 'webp'; } $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } /*if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true;*/ } Thank's ! It is working without commenting this code : /*if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true;*/ You can try with the code commented, else try to uncomment the code. Good luck Link to comment Share on other sites More sharing options...
gouna Posted March 29 Share Posted March 29 Images in webp format sent to the back office are still converted to jpg despite the modification. My Prestashop 1.7.8.11 ImageManager.php code : <?php /** * Copyright since 2007 PrestaShop SA and Contributors * PrestaShop is an International Registered Trademark & Property of PrestaShop SA * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.md. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/OSL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://devdocs.prestashop.com/ for more information. * * @author PrestaShop SA and Contributors <[email protected]> * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) */ /** * Class ImageManagerCore. * * This class includes functions for image manipulation * * @since 1.5.0 */ class ImageManagerCore { const ERROR_FILE_NOT_EXIST = 1; const ERROR_FILE_WIDTH = 2; const ERROR_MEMORY_LIMIT = 3; const MIME_TYPE_SUPPORTED = [ 'image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/webp', ]; const EXTENSIONS_SUPPORTED = [ 'gif', 'jpg', 'jpeg', 'jpe', 'png', ]; /** * Generate a cached thumbnail for object lists (eg. carrier, order statuses...etc). * * @param string $image Real image filename * @param string $cacheImage Cached filename * @param int $size Desired size * @param string $imageType Image type * @param bool $disableCache When turned on a timestamp will be added to the image URI to disable the HTTP cache * @param bool $regenerate When turned on and the file already exist, the file will be regenerated * *@return string */ public static function thumbnail($image, $cacheImage, $size, $imageType = 'jpg', $disableCache = true, $regenerate = false) { if (!file_exists($image)) { return ''; } if (file_exists(_PS_TMP_IMG_DIR_ . $cacheImage) && $regenerate) { @unlink(_PS_TMP_IMG_DIR_ . $cacheImage); } if ($regenerate || !file_exists(_PS_TMP_IMG_DIR_ . $cacheImage)) { $infos = getimagesize($image); // Evaluate the memory required to resize the image: if it's too much, you can't resize it. if (!ImageManager::checkImageMemoryLimit($image)) { return false; } $x = $infos[0]; $y = $infos[1]; $maxX = $size * 3; // Size is already ok if ($y < $size && $x <= $maxX) { copy($image, _PS_TMP_IMG_DIR_ . $cacheImage); } else { // We need to resize */ $ratioX = $x / ($y / $size); if ($ratioX > $maxX) { $ratioX = $maxX; $size = $y / ($x / $maxX); } ImageManager::resize($image, _PS_TMP_IMG_DIR_ . $cacheImage, $ratioX, $size, $imageType); } } return '<img src="' . self::getThumbnailPath($cacheImage, $disableCache) . '" alt="" class="imgm img-thumbnail" />'; } /** * @param $cacheImage * @param $disableCache * * @return string */ public static function getThumbnailPath($cacheImage, $disableCache) { $cacheParam = $disableCache ? '?time=' . time() : ''; if (Context::getContext()->controller->controller_type == 'admin') { return __PS_BASE_URI__ . 'img/tmp/' . $cacheImage . $cacheParam; } return _PS_TMP_IMG_ . $cacheImage . $cacheParam; } /** * Check if memory limit is too long or not. * * @param string $image * * @return bool */ public static function checkImageMemoryLimit($image) { $infos = @getimagesize($image); if (!is_array($infos) || !isset($infos['bits'])) { return true; } $memoryLimit = Tools::getMemoryLimit(); // memory_limit == -1 => unlimited memory if (isset($infos['bits']) && function_exists('memory_get_usage') && (int) $memoryLimit != -1) { $currentMemory = memory_get_usage(); $bits = $infos['bits'] / 8; $channel = isset($infos['channels']) ? $infos['channels'] : 1; // Evaluate the memory required to resize the image: if it's too much, you can't resize it. // For perfs, avoid computing static maths formulas in the code. pow(2, 16) = 65536 ; 1024 * 1024 = 1048576 if (($infos[0] * $infos[1] * $bits * $channel + 65536) * 1.8 + $currentMemory > $memoryLimit - 1048576) { return false; } } return true; } /** * Resize, cut and optimize image. * * @param string $sourceFile Image object from $_FILE * @param string $destinationFile Destination filename * @param int $destinationWidth Desired width (optional) * @param int $destinationHeight Desired height (optional) * @param string $fileType Desired file_type (may be override by PS_IMAGE_QUALITY) * @param bool $forceType Don't override $file_type * @param int $error Out error code * @param int $targetWidth Needed by AdminImportController to speed up the import process * @param int $targetHeight Needed by AdminImportController to speed up the import process * @param int $quality Needed by AdminImportController to speed up the import process * @param int $sourceWidth Needed by AdminImportController to speed up the import process * @param int $sourceHeight Needed by AdminImportController to speed up the import process * *@return bool Operation result */ public static function resize( $sourceFile, $destinationFile, $destinationWidth = null, $destinationHeight = null, $fileType = 'jpg', $forceType = false, &$error = 0, &$targetWidth = null, &$targetHeight = null, $quality = 5, &$sourceWidth = null, &$sourceHeight = null ) { clearstatcache(true, $sourceFile); if (!file_exists($sourceFile) || !filesize($sourceFile)) { return !($error = self::ERROR_FILE_NOT_EXIST); } list($tmpWidth, $tmpHeight, $type) = getimagesize($sourceFile); $rotate = 0; if (function_exists('exif_read_data') && function_exists('mb_strtolower')) { $exif = @exif_read_data($sourceFile); if ($exif && isset($exif['Orientation'])) { switch ($exif['Orientation']) { case 3: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; $rotate = 180; break; case 6: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = -90; break; case 8: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = 90; break; default: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } // If PS_IMAGE_QUALITY is activated, the generated image will be a PNG with .jpg as a file extension. // This allow for higher quality and for transparency. JPG source files will also benefit from a higher quality // because JPG reencoding by GD, even with max quality setting, degrades the image. if (Configuration::get('PS_IMAGE_QUALITY') == 'png_all' || (Configuration::get('PS_IMAGE_QUALITY') == 'png' && $type == IMAGETYPE_PNG) && !$forceType) { $fileType = 'png'; } if (!$sourceWidth) { return !($error = self::ERROR_FILE_WIDTH); } if (!$destinationWidth) { $destinationWidth = $sourceWidth; } if (!$destinationHeight) { $destinationHeight = $sourceHeight; } $widthDiff = $destinationWidth / $sourceWidth; $heightDiff = $destinationHeight / $sourceHeight; $psImageGenerationMethod = Configuration::get('PS_IMAGE_GENERATION_METHOD'); if ($widthDiff > 1 && $heightDiff > 1) { $nextWidth = $sourceWidth; $nextHeight = $sourceHeight; } else { if ($psImageGenerationMethod == 2 || (!$psImageGenerationMethod && $widthDiff > $heightDiff)) { $nextHeight = $destinationHeight; $nextWidth = round(($sourceWidth * $nextHeight) / $sourceHeight); $destinationWidth = (int) (!$psImageGenerationMethod ? $destinationWidth : $nextWidth); } else { $nextWidth = $destinationWidth; $nextHeight = round($sourceHeight * $destinationWidth / $sourceWidth); $destinationHeight = (int) (!$psImageGenerationMethod ? $destinationHeight : $nextHeight); } } if (!ImageManager::checkImageMemoryLimit($sourceFile)) { return !($error = self::ERROR_MEMORY_LIMIT); } $targetWidth = $destinationWidth; $targetHeight = $destinationHeight; $destImage = imagecreatetruecolor($destinationWidth, $destinationHeight); // If image is a PNG and the output is PNG, fill with transparency. Else fill with white background. if ($fileType == 'png' && $type == IMAGETYPE_PNG) { imagealphablending($destImage, false); imagesavealpha($destImage, true); $transparent = imagecolorallocatealpha($destImage, 255, 255, 255, 127); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $transparent); } else { $white = imagecolorallocate($destImage, 255, 255, 255); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $white); } $srcImage = ImageManager::create($type, $sourceFile); if ($rotate) { $srcImage = imagerotate($srcImage, $rotate, 0); } if ($destinationWidth >= $sourceWidth && $destinationHeight >= $sourceHeight) { imagecopyresized($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight); } else { ImageManager::imagecopyresampled($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight, $quality); } $writeFile = ImageManager::write($fileType, $destImage, $destinationFile); Hook::exec('actionOnImageResizeAfter', ['dst_file' => $destinationFile, 'file_type' => $fileType]); @imagedestroy($srcImage); file_put_contents( dirname($destinationFile) . DIRECTORY_SEPARATOR . 'fileType', $fileType ); return $writeFile; } /** * @param $dstImage * @param $srcImage * @param $dstX * @param $dstY * @param $srcX * @param $srcY * @param $dstW * @param $dstH * @param $srcW * @param $srcH * @param int $quality * * @return bool */ public static function imagecopyresampled( &$dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH, $quality = 3 ) { // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled. // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled". // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting. // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain. // // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero. // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect. // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized. // 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3. // 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster. // 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images. // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled. if (empty($srcImage) || empty($dstImage) || $quality <= 0) { return false; } if ($quality < 5 && (($dstW * $quality) < $srcW || ($dstH * $quality) < $srcH)) { $temp = imagecreatetruecolor($dstW * $quality + 1, $dstH * $quality + 1); imagecopyresized($temp, $srcImage, 0, 0, $srcX, $srcY, $dstW * $quality + 1, $dstH * $quality + 1, $srcW, $srcH); imagecopyresampled($dstImage, $temp, $dstX, $dstY, 0, 0, $dstW, $dstH, $dstW * $quality, $dstH * $quality); imagedestroy($temp); } else { imagecopyresampled($dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); } return true; } /** * @param string $filename * * @return string|bool */ public static function getMimeType(string $filename) { $mimeType = false; // Try with GD if (function_exists('getimagesize')) { $imageInfo = @getimagesize($filename); if ($imageInfo) { $mimeType = $imageInfo['mime']; } } // Try with FileInfo if (!$mimeType && function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mimeType = finfo_file($finfo, $filename); finfo_close($finfo); } // Try with Mime if (!$mimeType && function_exists('mime_content_type')) { $mimeType = mime_content_type($filename); } // Try with exec command and file binary if (!$mimeType && function_exists('exec')) { $mimeType = trim(exec('file -b --mime-type ' . escapeshellarg($filename))); if (!$mimeType) { $mimeType = trim(exec('file --mime ' . escapeshellarg($filename))); } if (!$mimeType) { $mimeType = trim(exec('file -bi ' . escapeshellarg($filename))); } } return $mimeType; } /** * Check if file is a real image. * * @param string $filename File path to check * @param string $fileMimeType File known mime type (generally from $_FILES) * @param array<string>|null $mimeTypeList Allowed MIME types * * @return bool */ public static function isRealImage($filename, $fileMimeType = null, $mimeTypeList = null) { if (!$mimeTypeList) { $mimeTypeList = static::MIME_TYPE_SUPPORTED; } $mimeType = static::getMimeType($filename); if ($fileMimeType && (empty($mimeType) || $mimeType == 'regular file' || $mimeType == 'text/plain')) { $mimeType = $fileMimeType; } // For each allowed MIME type, we are looking for it inside the current MIME type foreach ($mimeTypeList as $type) { if (strstr($mimeType, $type)) { return true; } } return false; } /** * Check if image file extension is correct. * * @param string $filename Real filename * @param array|null $authorizedExtensions * * @return bool True if it's correct */ public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; } if(!in_array('webp', $authorizedExtensions)){ $authorizedExtensions[] = 'webp'; } $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true; } /** * Validate image upload (check image type and weight). * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * @param array<string>|null $types Authorized extensions * @param array<string>|null $mimeTypeList Authorized mimetypes * * @return bool|string Return false if no error encountered */ public static function validateUpload($file, $maxFileSize = 0, $types = null, $mimeTypeList = null) { if ((int) $maxFileSize > 0 && $file['size'] > (int) $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1024, $maxFileSize / 1024], 'Admin.Notifications.Error'); } if (!ImageManager::isRealImage($file['tmp_name'], $file['type'], $mimeTypeList) || !ImageManager::isCorrectImageFileExt($file['name'], $types) || preg_match('/\%00/', $file['name'])) { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .gif, .jpg, .png, .webp', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings. (Error code: %s)', [$file['error']], 'Admin.Notifications.Error'); } return false; } /** * Validate icon upload. * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * * @return bool|string Return false if no error encountered */ public static function validateIconUpload($file, $maxFileSize = 0) { if ((int) $maxFileSize > 0 && $file['size'] > $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1000, $maxFileSize / 1000], 'Admin.Notifications.Error'); } if (substr($file['name'], -4) != '.ico') { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .ico', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings.', [], 'Admin.Notifications.Error'); } return false; } /** * Cut image. * * @param array $srcFile Origin filename * @param string $dstFile Destination filename * @param int $dstWidth Desired width * @param int $dstHeight Desired height * @param string $fileType * @param int $dstX * @param int $dstY * * @return bool Operation result */ public static function cut($srcFile, $dstFile, $dstWidth = null, $dstHeight = null, $fileType = 'jpg', $dstX = 0, $dstY = 0) { if (!file_exists($srcFile)) { return false; } // Source information $srcInfo = getimagesize($srcFile); $src = [ 'width' => $srcInfo[0], 'height' => $srcInfo[1], 'ressource' => ImageManager::create($srcInfo[2], $srcFile), ]; // Destination information $dest = []; $dest['x'] = $dstX; $dest['y'] = $dstY; $dest['width'] = null !== $dstWidth ? $dstWidth : $src['width']; $dest['height'] = null !== $dstHeight ? $dstHeight : $src['height']; $dest['ressource'] = ImageManager::createWhiteImage($dest['width'], $dest['height']); $white = imagecolorallocate($dest['ressource'], 255, 255, 255); imagecopyresampled($dest['ressource'], $src['ressource'], 0, 0, $dest['x'], $dest['y'], $dest['width'], $dest['height'], $dest['width'], $dest['height']); imagecolortransparent($dest['ressource'], $white); $return = ImageManager::write($fileType, $dest['ressource'], $dstFile); Hook::exec('actionOnImageCutAfter', ['dst_file' => $dstFile, 'file_type' => $fileType]); @imagedestroy($src['ressource']); return $return; } /** * Create an image with GD extension from a given type. * * @param string $type * @param string $filename * * @return resource */ public static function create($type, $filename) { switch ($type) { case IMAGETYPE_GIF: return imagecreatefromgif($filename); break; case IMAGETYPE_PNG: return imagecreatefrompng($filename); break; case IMAGETYPE_WEBP: return imagecreatefromwebp($filename); break; case IMAGETYPE_JPEG: default: return imagecreatefromjpeg($filename); break; } } /** * Create an empty image with white background. * * @param int $width * @param int $height * * @return resource */ public static function createWhiteImage($width, $height) { $image = imagecreatetruecolor($width, $height); $white = imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $white); return $image; } /** * Generate and write image. * * @param string $type * @param resource $resource * @param string $filename * * @return bool */ public static function write($type, $resource, $filename) { static $psPngQuality = null; static $psJpegQuality = null; if ($psPngQuality === null) { $psPngQuality = Configuration::get('PS_PNG_QUALITY'); } if ($psJpegQuality === null) { $psJpegQuality = Configuration::get('PS_JPEG_QUALITY'); } switch ($type) { case 'gif': $success = imagegif($resource, $filename); break; case 'png': $quality = ($psPngQuality === false ? 7 : $psPngQuality); $success = imagepng($resource, $filename, (int) $quality); break; case 'webp': $success = imagewebp($resource, $filename, 90); break; case 'jpg': case 'jpeg': default: $quality = ($psJpegQuality === false ? 90 : $psJpegQuality); imageinterlace($resource, 1); /// make it PROGRESSIVE $success = imagejpeg($resource, $filename, (int) $quality); break; } imagedestroy($resource); @chmod($filename, 0664); return $success; } /** * Return the mime type by the file extension. * * @param string $fileName * * @return string */ public static function getMimeTypeByExtension($fileName) { $types = [ 'image/gif' => ['gif'], 'image/jpeg' => ['jpg', 'jpeg'], 'image/png' => ['png'], 'image/webp' => ['webp'], ]; $extension = substr($fileName, strrpos($fileName, '.') + 1); $mimeType = null; foreach ($types as $mime => $exts) { if (in_array($extension, $exts)) { $mimeType = $mime; break; } } if ($mimeType === null) { $mimeType = 'image/jpeg'; } return $mimeType; } } Link to comment Share on other sites More sharing options...
Talbi ConSept Posted March 29 Share Posted March 29 9 minutes ago, gouna said: Images in webp format sent to the back office are still converted to jpg despite the modification. My Prestashop 1.7.8.11 ImageManager.php code : <?php /** * Copyright since 2007 PrestaShop SA and Contributors * PrestaShop is an International Registered Trademark & Property of PrestaShop SA * * NOTICE OF LICENSE * * This source file is subject to the Open Software License (OSL 3.0) * that is bundled with this package in the file LICENSE.md. * It is also available through the world-wide-web at this URL: * https://opensource.org/licenses/OSL-3.0 * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to [email protected] so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to https://devdocs.prestashop.com/ for more information. * * @author PrestaShop SA and Contributors <[email protected]> * @copyright Since 2007 PrestaShop SA and Contributors * @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0) */ /** * Class ImageManagerCore. * * This class includes functions for image manipulation * * @since 1.5.0 */ class ImageManagerCore { const ERROR_FILE_NOT_EXIST = 1; const ERROR_FILE_WIDTH = 2; const ERROR_MEMORY_LIMIT = 3; const MIME_TYPE_SUPPORTED = [ 'image/gif', 'image/jpg', 'image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/webp', ]; const EXTENSIONS_SUPPORTED = [ 'gif', 'jpg', 'jpeg', 'jpe', 'png', ]; /** * Generate a cached thumbnail for object lists (eg. carrier, order statuses...etc). * * @param string $image Real image filename * @param string $cacheImage Cached filename * @param int $size Desired size * @param string $imageType Image type * @param bool $disableCache When turned on a timestamp will be added to the image URI to disable the HTTP cache * @param bool $regenerate When turned on and the file already exist, the file will be regenerated * *@return string */ public static function thumbnail($image, $cacheImage, $size, $imageType = 'jpg', $disableCache = true, $regenerate = false) { if (!file_exists($image)) { return ''; } if (file_exists(_PS_TMP_IMG_DIR_ . $cacheImage) && $regenerate) { @unlink(_PS_TMP_IMG_DIR_ . $cacheImage); } if ($regenerate || !file_exists(_PS_TMP_IMG_DIR_ . $cacheImage)) { $infos = getimagesize($image); // Evaluate the memory required to resize the image: if it's too much, you can't resize it. if (!ImageManager::checkImageMemoryLimit($image)) { return false; } $x = $infos[0]; $y = $infos[1]; $maxX = $size * 3; // Size is already ok if ($y < $size && $x <= $maxX) { copy($image, _PS_TMP_IMG_DIR_ . $cacheImage); } else { // We need to resize */ $ratioX = $x / ($y / $size); if ($ratioX > $maxX) { $ratioX = $maxX; $size = $y / ($x / $maxX); } ImageManager::resize($image, _PS_TMP_IMG_DIR_ . $cacheImage, $ratioX, $size, $imageType); } } return '<img src="' . self::getThumbnailPath($cacheImage, $disableCache) . '" alt="" class="imgm img-thumbnail" />'; } /** * @param $cacheImage * @param $disableCache * * @return string */ public static function getThumbnailPath($cacheImage, $disableCache) { $cacheParam = $disableCache ? '?time=' . time() : ''; if (Context::getContext()->controller->controller_type == 'admin') { return __PS_BASE_URI__ . 'img/tmp/' . $cacheImage . $cacheParam; } return _PS_TMP_IMG_ . $cacheImage . $cacheParam; } /** * Check if memory limit is too long or not. * * @param string $image * * @return bool */ public static function checkImageMemoryLimit($image) { $infos = @getimagesize($image); if (!is_array($infos) || !isset($infos['bits'])) { return true; } $memoryLimit = Tools::getMemoryLimit(); // memory_limit == -1 => unlimited memory if (isset($infos['bits']) && function_exists('memory_get_usage') && (int) $memoryLimit != -1) { $currentMemory = memory_get_usage(); $bits = $infos['bits'] / 8; $channel = isset($infos['channels']) ? $infos['channels'] : 1; // Evaluate the memory required to resize the image: if it's too much, you can't resize it. // For perfs, avoid computing static maths formulas in the code. pow(2, 16) = 65536 ; 1024 * 1024 = 1048576 if (($infos[0] * $infos[1] * $bits * $channel + 65536) * 1.8 + $currentMemory > $memoryLimit - 1048576) { return false; } } return true; } /** * Resize, cut and optimize image. * * @param string $sourceFile Image object from $_FILE * @param string $destinationFile Destination filename * @param int $destinationWidth Desired width (optional) * @param int $destinationHeight Desired height (optional) * @param string $fileType Desired file_type (may be override by PS_IMAGE_QUALITY) * @param bool $forceType Don't override $file_type * @param int $error Out error code * @param int $targetWidth Needed by AdminImportController to speed up the import process * @param int $targetHeight Needed by AdminImportController to speed up the import process * @param int $quality Needed by AdminImportController to speed up the import process * @param int $sourceWidth Needed by AdminImportController to speed up the import process * @param int $sourceHeight Needed by AdminImportController to speed up the import process * *@return bool Operation result */ public static function resize( $sourceFile, $destinationFile, $destinationWidth = null, $destinationHeight = null, $fileType = 'jpg', $forceType = false, &$error = 0, &$targetWidth = null, &$targetHeight = null, $quality = 5, &$sourceWidth = null, &$sourceHeight = null ) { clearstatcache(true, $sourceFile); if (!file_exists($sourceFile) || !filesize($sourceFile)) { return !($error = self::ERROR_FILE_NOT_EXIST); } list($tmpWidth, $tmpHeight, $type) = getimagesize($sourceFile); $rotate = 0; if (function_exists('exif_read_data') && function_exists('mb_strtolower')) { $exif = @exif_read_data($sourceFile); if ($exif && isset($exif['Orientation'])) { switch ($exif['Orientation']) { case 3: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; $rotate = 180; break; case 6: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = -90; break; case 8: $sourceWidth = $tmpHeight; $sourceHeight = $tmpWidth; $rotate = 90; break; default: $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } } else { $sourceWidth = $tmpWidth; $sourceHeight = $tmpHeight; } // If PS_IMAGE_QUALITY is activated, the generated image will be a PNG with .jpg as a file extension. // This allow for higher quality and for transparency. JPG source files will also benefit from a higher quality // because JPG reencoding by GD, even with max quality setting, degrades the image. if (Configuration::get('PS_IMAGE_QUALITY') == 'png_all' || (Configuration::get('PS_IMAGE_QUALITY') == 'png' && $type == IMAGETYPE_PNG) && !$forceType) { $fileType = 'png'; } if (!$sourceWidth) { return !($error = self::ERROR_FILE_WIDTH); } if (!$destinationWidth) { $destinationWidth = $sourceWidth; } if (!$destinationHeight) { $destinationHeight = $sourceHeight; } $widthDiff = $destinationWidth / $sourceWidth; $heightDiff = $destinationHeight / $sourceHeight; $psImageGenerationMethod = Configuration::get('PS_IMAGE_GENERATION_METHOD'); if ($widthDiff > 1 && $heightDiff > 1) { $nextWidth = $sourceWidth; $nextHeight = $sourceHeight; } else { if ($psImageGenerationMethod == 2 || (!$psImageGenerationMethod && $widthDiff > $heightDiff)) { $nextHeight = $destinationHeight; $nextWidth = round(($sourceWidth * $nextHeight) / $sourceHeight); $destinationWidth = (int) (!$psImageGenerationMethod ? $destinationWidth : $nextWidth); } else { $nextWidth = $destinationWidth; $nextHeight = round($sourceHeight * $destinationWidth / $sourceWidth); $destinationHeight = (int) (!$psImageGenerationMethod ? $destinationHeight : $nextHeight); } } if (!ImageManager::checkImageMemoryLimit($sourceFile)) { return !($error = self::ERROR_MEMORY_LIMIT); } $targetWidth = $destinationWidth; $targetHeight = $destinationHeight; $destImage = imagecreatetruecolor($destinationWidth, $destinationHeight); // If image is a PNG and the output is PNG, fill with transparency. Else fill with white background. if ($fileType == 'png' && $type == IMAGETYPE_PNG) { imagealphablending($destImage, false); imagesavealpha($destImage, true); $transparent = imagecolorallocatealpha($destImage, 255, 255, 255, 127); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $transparent); } else { $white = imagecolorallocate($destImage, 255, 255, 255); imagefilledrectangle($destImage, 0, 0, $destinationWidth, $destinationHeight, $white); } $srcImage = ImageManager::create($type, $sourceFile); if ($rotate) { $srcImage = imagerotate($srcImage, $rotate, 0); } if ($destinationWidth >= $sourceWidth && $destinationHeight >= $sourceHeight) { imagecopyresized($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight); } else { ImageManager::imagecopyresampled($destImage, $srcImage, (int) (($destinationWidth - $nextWidth) / 2), (int) (($destinationHeight - $nextHeight) / 2), 0, 0, $nextWidth, $nextHeight, $sourceWidth, $sourceHeight, $quality); } $writeFile = ImageManager::write($fileType, $destImage, $destinationFile); Hook::exec('actionOnImageResizeAfter', ['dst_file' => $destinationFile, 'file_type' => $fileType]); @imagedestroy($srcImage); file_put_contents( dirname($destinationFile) . DIRECTORY_SEPARATOR . 'fileType', $fileType ); return $writeFile; } /** * @param $dstImage * @param $srcImage * @param $dstX * @param $dstY * @param $srcX * @param $srcY * @param $dstW * @param $dstH * @param $srcW * @param $srcH * @param int $quality * * @return bool */ public static function imagecopyresampled( &$dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH, $quality = 3 ) { // Plug-and-Play fastimagecopyresampled function replaces much slower imagecopyresampled. // Just include this function and change all "imagecopyresampled" references to "fastimagecopyresampled". // Typically from 30 to 60 times faster when reducing high resolution images down to thumbnail size using the default quality setting. // Author: Tim Eckel - Date: 09/07/07 - Version: 1.1 - Project: FreeRingers.net - Freely distributable - These comments must remain. // // Optional "quality" parameter (defaults is 3). Fractional values are allowed, for example 1.5. Must be greater than zero. // Between 0 and 1 = Fast, but mosaic results, closer to 0 increases the mosaic effect. // 1 = Up to 350 times faster. Poor results, looks very similar to imagecopyresized. // 2 = Up to 95 times faster. Images appear a little sharp, some prefer this over a quality of 3. // 3 = Up to 60 times faster. Will give high quality smooth results very close to imagecopyresampled, just faster. // 4 = Up to 25 times faster. Almost identical to imagecopyresampled for most images. // 5 = No speedup. Just uses imagecopyresampled, no advantage over imagecopyresampled. if (empty($srcImage) || empty($dstImage) || $quality <= 0) { return false; } if ($quality < 5 && (($dstW * $quality) < $srcW || ($dstH * $quality) < $srcH)) { $temp = imagecreatetruecolor($dstW * $quality + 1, $dstH * $quality + 1); imagecopyresized($temp, $srcImage, 0, 0, $srcX, $srcY, $dstW * $quality + 1, $dstH * $quality + 1, $srcW, $srcH); imagecopyresampled($dstImage, $temp, $dstX, $dstY, 0, 0, $dstW, $dstH, $dstW * $quality, $dstH * $quality); imagedestroy($temp); } else { imagecopyresampled($dstImage, $srcImage, $dstX, $dstY, $srcX, $srcY, $dstW, $dstH, $srcW, $srcH); } return true; } /** * @param string $filename * * @return string|bool */ public static function getMimeType(string $filename) { $mimeType = false; // Try with GD if (function_exists('getimagesize')) { $imageInfo = @getimagesize($filename); if ($imageInfo) { $mimeType = $imageInfo['mime']; } } // Try with FileInfo if (!$mimeType && function_exists('finfo_open')) { $finfo = finfo_open(FILEINFO_MIME_TYPE); $mimeType = finfo_file($finfo, $filename); finfo_close($finfo); } // Try with Mime if (!$mimeType && function_exists('mime_content_type')) { $mimeType = mime_content_type($filename); } // Try with exec command and file binary if (!$mimeType && function_exists('exec')) { $mimeType = trim(exec('file -b --mime-type ' . escapeshellarg($filename))); if (!$mimeType) { $mimeType = trim(exec('file --mime ' . escapeshellarg($filename))); } if (!$mimeType) { $mimeType = trim(exec('file -bi ' . escapeshellarg($filename))); } } return $mimeType; } /** * Check if file is a real image. * * @param string $filename File path to check * @param string $fileMimeType File known mime type (generally from $_FILES) * @param array<string>|null $mimeTypeList Allowed MIME types * * @return bool */ public static function isRealImage($filename, $fileMimeType = null, $mimeTypeList = null) { if (!$mimeTypeList) { $mimeTypeList = static::MIME_TYPE_SUPPORTED; } $mimeType = static::getMimeType($filename); if ($fileMimeType && (empty($mimeType) || $mimeType == 'regular file' || $mimeType == 'text/plain')) { $mimeType = $fileMimeType; } // For each allowed MIME type, we are looking for it inside the current MIME type foreach ($mimeTypeList as $type) { if (strstr($mimeType, $type)) { return true; } } return false; } /** * Check if image file extension is correct. * * @param string $filename Real filename * @param array|null $authorizedExtensions * * @return bool True if it's correct */ public static function isCorrectImageFileExt($filename, $authorizedExtensions = null) { // Filter on file extension if ($authorizedExtensions === null) { $authorizedExtensions = ['gif', 'jpg', 'jpeg', 'jpe', 'png', 'webp']; } if(!in_array('webp', $authorizedExtensions)){ $authorizedExtensions[] = 'webp'; } $nameExplode = explode('.', $filename); $currentExtension = strtolower(end($nameExplode)); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } else { return true; } if (count($nameExplode) >= 2) { $currentExtension = strtolower($nameExplode[count($nameExplode) - 1]); if (!in_array($currentExtension, $authorizedExtensions)) { return false; } } else { return false; } return true; } /** * Validate image upload (check image type and weight). * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * @param array<string>|null $types Authorized extensions * @param array<string>|null $mimeTypeList Authorized mimetypes * * @return bool|string Return false if no error encountered */ public static function validateUpload($file, $maxFileSize = 0, $types = null, $mimeTypeList = null) { if ((int) $maxFileSize > 0 && $file['size'] > (int) $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1024, $maxFileSize / 1024], 'Admin.Notifications.Error'); } if (!ImageManager::isRealImage($file['tmp_name'], $file['type'], $mimeTypeList) || !ImageManager::isCorrectImageFileExt($file['name'], $types) || preg_match('/\%00/', $file['name'])) { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .gif, .jpg, .png, .webp', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings. (Error code: %s)', [$file['error']], 'Admin.Notifications.Error'); } return false; } /** * Validate icon upload. * * @param array $file Upload $_FILE value * @param int $maxFileSize Maximum upload size * * @return bool|string Return false if no error encountered */ public static function validateIconUpload($file, $maxFileSize = 0) { if ((int) $maxFileSize > 0 && $file['size'] > $maxFileSize) { return Context::getContext()->getTranslator()->trans('Image is too large (%1$d kB). Maximum allowed: %2$d kB', [$file['size'] / 1000, $maxFileSize / 1000], 'Admin.Notifications.Error'); } if (substr($file['name'], -4) != '.ico') { return Context::getContext()->getTranslator()->trans('Image format not recognized, allowed formats are: .ico', [], 'Admin.Notifications.Error'); } if ($file['error']) { return Context::getContext()->getTranslator()->trans('Error while uploading image; please change your server\'s settings.', [], 'Admin.Notifications.Error'); } return false; } /** * Cut image. * * @param array $srcFile Origin filename * @param string $dstFile Destination filename * @param int $dstWidth Desired width * @param int $dstHeight Desired height * @param string $fileType * @param int $dstX * @param int $dstY * * @return bool Operation result */ public static function cut($srcFile, $dstFile, $dstWidth = null, $dstHeight = null, $fileType = 'jpg', $dstX = 0, $dstY = 0) { if (!file_exists($srcFile)) { return false; } // Source information $srcInfo = getimagesize($srcFile); $src = [ 'width' => $srcInfo[0], 'height' => $srcInfo[1], 'ressource' => ImageManager::create($srcInfo[2], $srcFile), ]; // Destination information $dest = []; $dest['x'] = $dstX; $dest['y'] = $dstY; $dest['width'] = null !== $dstWidth ? $dstWidth : $src['width']; $dest['height'] = null !== $dstHeight ? $dstHeight : $src['height']; $dest['ressource'] = ImageManager::createWhiteImage($dest['width'], $dest['height']); $white = imagecolorallocate($dest['ressource'], 255, 255, 255); imagecopyresampled($dest['ressource'], $src['ressource'], 0, 0, $dest['x'], $dest['y'], $dest['width'], $dest['height'], $dest['width'], $dest['height']); imagecolortransparent($dest['ressource'], $white); $return = ImageManager::write($fileType, $dest['ressource'], $dstFile); Hook::exec('actionOnImageCutAfter', ['dst_file' => $dstFile, 'file_type' => $fileType]); @imagedestroy($src['ressource']); return $return; } /** * Create an image with GD extension from a given type. * * @param string $type * @param string $filename * * @return resource */ public static function create($type, $filename) { switch ($type) { case IMAGETYPE_GIF: return imagecreatefromgif($filename); break; case IMAGETYPE_PNG: return imagecreatefrompng($filename); break; case IMAGETYPE_WEBP: return imagecreatefromwebp($filename); break; case IMAGETYPE_JPEG: default: return imagecreatefromjpeg($filename); break; } } /** * Create an empty image with white background. * * @param int $width * @param int $height * * @return resource */ public static function createWhiteImage($width, $height) { $image = imagecreatetruecolor($width, $height); $white = imagecolorallocate($image, 255, 255, 255); imagefill($image, 0, 0, $white); return $image; } /** * Generate and write image. * * @param string $type * @param resource $resource * @param string $filename * * @return bool */ public static function write($type, $resource, $filename) { static $psPngQuality = null; static $psJpegQuality = null; if ($psPngQuality === null) { $psPngQuality = Configuration::get('PS_PNG_QUALITY'); } if ($psJpegQuality === null) { $psJpegQuality = Configuration::get('PS_JPEG_QUALITY'); } switch ($type) { case 'gif': $success = imagegif($resource, $filename); break; case 'png': $quality = ($psPngQuality === false ? 7 : $psPngQuality); $success = imagepng($resource, $filename, (int) $quality); break; case 'webp': $success = imagewebp($resource, $filename, 90); break; case 'jpg': case 'jpeg': default: $quality = ($psJpegQuality === false ? 90 : $psJpegQuality); imageinterlace($resource, 1); /// make it PROGRESSIVE $success = imagejpeg($resource, $filename, (int) $quality); break; } imagedestroy($resource); @chmod($filename, 0664); return $success; } /** * Return the mime type by the file extension. * * @param string $fileName * * @return string */ public static function getMimeTypeByExtension($fileName) { $types = [ 'image/gif' => ['gif'], 'image/jpeg' => ['jpg', 'jpeg'], 'image/png' => ['png'], 'image/webp' => ['webp'], ]; $extension = substr($fileName, strrpos($fileName, '.') + 1); $mimeType = null; foreach ($types as $mime => $exts) { if (in_array($extension, $exts)) { $mimeType = $mime; break; } } if ($mimeType === null) { $mimeType = 'image/jpeg'; } return $mimeType; } } Yes, this is just to be able to import webp images, but Prestashop will still convert them to jpeg. 1 Link to comment Share on other sites More sharing options...
gouna Posted March 31 Share Posted March 31 Ok thank's! 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now