SmythSys IT Consulting

Mejorar la calidad de las imágenes que se suben o se importan en Prestashop

Hace unos días hemos hecho una página web para un cliente en Prestashop. Este cliente, tenía la peculiaridad (respecto a clientes anteriores) que disponía de unas imágenes con buena calidad. Al subirlas a Prestashop, tanto en la subida por producto, como en la importación masiva, la pérdida de calidad era más que evidente. Las fotos de Prestashop no tenían una calidad aceptable teniendo en cuenta las fotos de origen. Y en esa página, las imágenes eran clave.

La página la hemos creado en 1.7, pero lo probamos en 1.6 y el resultado era el mismo. Calidad muy por debajo de lo aceptable cuando las imágenes originales son de calidad (para imágenes “usuales” si que es funcional).
Obviamente modificamos todas las opciones de calidad en el backend de Prestashop ( Diseño > Ajustes de imágenes ), sin mejora importante del resultado.

Nos somos a los primeros a los que les pasó (ver aquí y aquí). Es un tema recurrente y sin resolver (“sorpresa” por parte de Prestashop).

Al final descubrimos por qué y cómo resolverlo. Os lo contamos en este artículo.

Cómo mejorar la calidad de las imágenes que se suben o se importan en Prestashop.

Lo primero es la causa que ocasiona esta pérdida de calidad. Prestashop comprime todas las imágenes al subirlas. Y crea varias imágenes de diferentes tamaños (que se definen en Diseño > Ajustes de imágenes ). Esto es lógico y bueno. El problema es que usa un método de compresión, GD2, que antes se usaba mucho por estar integrado en Php (o en la mayoría de las instalaciones). Sin embargo no es la librería que mejores resultados da, tiene pocas opciones y, además, creo que Php 7 ya no la incluye por defecto.

Después de varias pruebas infructuosas con GD, optamos por cambiar a Imagemagick siguiendo las indicaciones de un post al que enlazamos en los párrafos anteriores.

Siguiendo los resultados arreglaba algo la subida producto a producto, pero no la masiva. Y aún así, no conseguíamos los mejores resultados así que modificamos el proceso para lo que queríamos. Esto es lo que hicimos..

Para las subidas desde el backend.

Tenemos que:

  • Hacer un override (copiar en la carpeta override/classes) de la clase ImageManager.php porque queremos modificar la función resize para que use ImageMagick.
    Nota:  Para esto tu servidor tiene que tener ImageMagick o deberías poder instalarlo. Si no no funciona.
  • En ese fichero   override/classes/ImageManager.php ponemos lo siguiente:

    <?php

    class ImageManager extends ImageManagerCore
    {

    /**
    * Resize, cut and optimize image
    *
    * @param string $src_file Image object from $_FILE
    * @param string $dst_file Destination filename
    * @param int $dst_width Desired width (optional)
    * @param int $dst_height Desired height (optional)
    * @param string $file_type
    * @param bool $force_type
    * @param int $error
    * @param int $tgt_width
    * @param int $tgt_height
    * @param int $quality
    * @param int $src_width
    * @param int $src_height
    * @return bool Operation result
    */
    public static function resize2($src_file, $dst_file, $dst_width = null, $dst_height = null, $file_type = ‘jpg’,
    $force_type = false, &$error = 0, &$tgt_width = null, &$tgt_height = null, $quality = 5,
    &$src_width = null, &$src_height = null)
    {
    if (PHP_VERSION_ID < 50300) {
    clearstatcache();
    } else {
    clearstatcache(true, $src_file);
    }

    if (!file_exists($src_file) || !filesize($src_file)) {
    return !($error = self::ERROR_FILE_NOT_EXIST);
    }

    list($src_width, $src_height, $type) = getimagesize($src_file);

    // 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) && !$force_type) {
    $file_type = ‘png’;
    }

    if (!$src_width) {
    return !($error = self::ERROR_FILE_WIDTH);
    }
    if (!$dst_width) {
    $dst_width = $src_width;
    }
    if (!$dst_height) {
    $dst_height = $src_height;
    }

    $width_diff = $dst_width / $src_width;
    $height_diff = $dst_height / $src_height;

    $ps_image_generation_method = Configuration::get(‘PS_IMAGE_GENERATION_METHOD’);
    if ($width_diff > 1 && $height_diff > 1) {
    $next_width = $src_width;
    $next_height = $src_height;
    } else {
    if ($ps_image_generation_method == 2 || (!$ps_image_generation_method && $width_diff > $height_diff)) {
    $next_height = $dst_height;
    $next_width = round(($src_width * $next_height) / $src_height);
    $dst_width = (int)(!$ps_image_generation_method ? $dst_width : $next_width);
    } else {
    $next_width = $dst_width;
    $next_height = round($src_height * $dst_width / $src_width);
    $dst_height = (int)(!$ps_image_generation_method ? $dst_height : $next_height);
    }
    }

    if (!ImageManager::checkImageMemoryLimit($src_file)) {
    return !($error = self::ERROR_MEMORY_LIMIT);
    }

    //Set Imagick Object values
    /* $src_image = new Imagick();
    $src_image->readImage($src_file);
    $src_image->setImageCompression(Imagick::COMPRESSION_JPEG);
    $src_image->setInterlaceScheme(Imagick::INTERLACE_PLANE);
    $src_image->setImageCompressionQuality(89);
    $src_image->sharpenimage(2, 0.5, 134217727);
    $src_image->gaussianBlurImage(0.03,0.03);
    $src_image->stripImage();
    $src_image->thumbnailImage($dst_width, $dst_height, Imagick::FILTER_SINC, 1);*/
    $src_image = new Imagick();
    $src_image->readImage($src_file);
    $src_image->setImageCompression(Imagick::COMPRESSION_JPEG);
    /*$src_image->setImageFormat(‘png’);*/
    /*$src_image->setInterlaceScheme(Imagick::INTERLACE_PLANE);*/
    $src_image->setImageCompressionQuality(89);
    /*$src_image->sharpenimage(1.5, 0.5, Imagick::CHANNEL_ALL);*/
    /* $src_image->gaussianBlurImage(0.03,0.03);*/
    $src_image->stripImage();
    $src_image->thumbnailImage($dst_width, $dst_height, Imagick::FILTER_LANCZOS, 1);
    $src_image->brightnessContrastImage(1,0,Imagick::CHANNEL_ALL);
    $src_image->gammaImage(0.9,Imagick::CHANNEL_ALL);
    $src_image->modulateImage(100,120,100);
    //Output the final Image using Imagick
    return $src_image->writeImage($dst_file);

    }

    }

Como veis hemos creado la función resize2 que usará ImageMagick. Dejando el nombre resize arregla el backend. Pero no las masivas. Eso si, si sólo hacemos esto con otro nombre no usa resize2 al subir productos. Tenemos que indicarle que lo haga. Para eso.

  • Hacer un override en override/controllers/admin/AdminProductsController.php  . Ahí hay 5 sitios en el que llama a resize. Cambia los 5 a la función anterior (pon un 2 y ya está si has usado nuestro método.

Para las importaciones masivas desde ficheros CSV o Excel en el backend.

Sólo modificando el ImageManager no arreglaba las importaciones masivas. Estas van “por otro lado”. Usaban en resize pero además el GD de nuevo. Para eso tenemos que hacer lo siguiente.

  • Ahora copiamos el fichero controlador AdminImportController.php en override/controllers/admin/AdminImportController.php
  • Lo editamos y veréis que hay dos sitios que usan la biblioteca resize. Para el resultado que queríamos el primero hay que dejarlo usando la original (con resize) y el segundo el resize2. Así:

    ImageManager::resize($tmpfile, $path.’.jpg’, null, null, ‘jpg’, false, $error, $tgt_width, $tgt_height, 5, $src_width, $src_height);
    $images_types = ImageType::getImagesTypes($entity, true);

    if ($regenerate) {
    $previous_path = null;
    $path_infos = array();
    $path_infos[] = array($tgt_width, $tgt_height, $path.’.jpg’);
    foreach ($images_types as $image_type) {
    $tmpfile = self::get_best_path($image_type[‘width’], $image_type[‘height’], $path_infos);

    if (ImageManager::resize2(
    $tmpfile,
    $path.’-‘.stripslashes($image_type[‘name’]).’.jpg’,
    $image_type[‘width’],
    $image_type[‘height’],
    ‘jpg’,
    false,
    $error,
    $tgt_width,
    $tgt_height,
    5,
    $src_width,
    $src_height

Con esto nuestra imágenes han mejorado notablemente. Puedes modificar o añadir los filtros usados (deberías) en ImageMagick. Esta página nos vino muy bien para entenderlos y hacer pruebas. Aquí las librerías de PHP.

También os recomiendo que subáis el tamaño de las imágenes a uno de mucha resolución en las de producto. Luego podéis bajarlo por CSS. Pero la diferencia es notable si usáis fotos de, digamos 1500px o de 900px.

Deja un comentario

Resumen de nuestra Política de Privacidad

  • Responsable: SmythSys IT Consulting SLNE.
  • Finalidad: Gestionar y moderar los comentarios.
  • Legitimación: Necesitas dar tu consentimiento para publicar un comentario.
  • Destinatarios: Tus datos se alojan en los servidores de OVH.
  • Derechos: Tienes derecho a acceder, rectificar, limitar y suprimir los datos en la dirección del responsable (en nuestra política de privacidad).