How to Resize Specific Product Image using Command Line in Magento 2?

How to Resize Specific Product Image using Command Line in Magento 2

Hello Magento Friends,

With this Magento 2 tutorial, I will provide the solution for Resizing Specific Product Image using Command Line in Magento 2.

Product images attract the user’s attention. If they are not displayed properly, it will create a bad user experience. Hence, to make sure the product images fit correctly and display properly, you may need to resize them.

Magento 2 provides an image resize command which will resize all the product images at once. If you want to resize only a specific product image, the below steps will help you to accomplish it.

Steps to Resize Specific Product Image using Command Line in Magento 2:

Step 1: Create a di.xml file at the given path

app/code/Vendor/Extension/etc/di.xml

Now add the code as follows

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Framework\Console\CommandListInterface">
        <arguments>
            <argument name="commands" xsi:type="array">
                <item name="imagesResizeCommand" xsi:type="object">
                    Vendor\Extension\Console\Command\ImagesResizeCommand
                </item>
            </argument>
        </arguments>
    </type>
    <type name="Vendor\Extension\Console\Command\ImagesResizeCommand">
        <arguments>
            <argument name="imageResizeScheduler" xsi:type="object">
                Magento\MediaStorage\Service\ImageResizeScheduler\Proxy
            </argument>
        </arguments>
    </type>
</config>

Step 2: Now, you need to create the ImagesResizeCommand.php file at the below path

app/code/Vendor/Extension/Console/Command/ImagesResizeCommand.php

Then add the following code

<?php

declare(strict_types=1);

namespace Vendor\Extension\Console\Command;

use Magento\Framework\App\Area;
use Magento\Framework\App\State;
use Magento\Framework\Console\Cli;
use Magento\MediaStorage\Service\ImageResize;
use Magento\MediaStorage\Service\ImageResizeScheduler;

use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Helper\ProgressBarFactory;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;

use Magento\Framework\DB\Query\Generator;
use Magento\Framework\DB\Select;
use Magento\Framework\App\ResourceConnection;
use Magento\Catalog\Model\ResourceModel\Product\Gallery;
use Magento\Catalog\Model\ResourceModel\Product\Image as Produc-tImage;

/**
* Resizes product images according to theme view definitions.
*/

class ImagesResizeCommand extends Command
{
    /**
    * Asynchronous image resize mode
    */

    const ASYNC_RESIZE = 'async';

    /**
    * @var ImageResizeScheduler
    */

    private $imageResizeScheduler;

    /**
    * @var ImageResize
    */

    private $imageResize;

    /**
    * @var State
    */

    private $appState;

    /**
    * @var ProgressBarFactory
    */

    private $progressBarFactory;

    /**
    * @var ProductImage
    */

    private $productImage;

    /**
    * @var ResourceConnection
    */

    private $resourceConnection;

    public function __construct(
        State $appState,
        ImageResize $imageResize,
        ImageResizeScheduler $imageResizeScheduler,
        ProgressBarFactory $progressBarFactory,
        ProductImage $productImage,
        Generator $generator,
        ResourceConnection $resourceConnection
    )
    {
        parent::__construct();
        $this->appState = $appState;
        $this->imageResize = $imageResize;
        $this->imageResizeScheduler = $imageResizeScheduler;
        $this->progressBarFactory = $progressBarFactory;
        $this->productImage = $productImage;
        $this->batchQueryGenerator = $generator;
        $this->resourceConnection = $resourceConnection;
    }

    /**
    * @inheritdoc
    */

    protected function configure()
    {
        $this->setName('test:product:resize')
        ->setDefinition($this->getOptionsList());
        $this->addOption(
            'product_id',
            null,
            InputOption::VALUE_REQUIRED,
            'Add Product ID'
        );
    }

    /**
    * Image resize command options list
    *
    * @return array
    */

    private function getOptionsList() : array
    {
        return [
            new InputOption(
                self::ASYNC_RESIZE,
                'a',
                InputOption::VALUE_NONE,
                'Resize image in asynchronous mode'
            ),
        ];
    }

    /**
    * @inheritdoc
    * @param InputInterface $input
    * @param OutputInterface $output
    */

    protected function execute(InputInterface $input, OutputInter-face $output)
    {
        $product_id = $input->getOption('product_id');
        $result = $this->executeAsync($output, $product_id);
        return $result;
    }

    /**
    * Schedule asynchronous image resizing
    *
    * @param OutputInterface $output
    * @param int $product_id
    * @return int
    */

    private function executeAsync(OutputInterface $output, $product_id): int
    {
        try
        {
            $errors = [];
            $this->appState->setAreaCode(Area::AREA_GLOBAL);

            /** @var ProgressBar $progress */

            $progress = $this->progressBarFactory->create(
                [
                    'output' => $output,
                    'max' => $this->getCountUsedProductImages($product_id)
                ]
            );
            $progress->setFormat(
                "%current%/%max% [%bar%] %percent:3s%% %elapsed% %memory:6s% \t| <info>%message%</info>"
            );
            if ($output->getVerbosity() !== OutputInter-face::VERBOSITY_NORMAL)
            {
                $progress->setOverwrite(false);
            }
            $productImages = $this->getUsedProductImages($product_id);
            foreach ($productImages as $image)
            {
                $result = $this->imageResizeScheduler->schedule($image['filepath']);
                if (!$result)
                {
                    $errors[$image['filepath']] = 'Error image scheduling: ' . $image['filepath'];
                }
                $progress->setMessage($image['filepath']);
                $progress->advance();
            }
        }
        catch (\Exception $e)
        {
            $output->writeln("<error>{$e->getMessage()}</error>");
            return Cli::RETURN_FAILURE;
        }
        $output->write(PHP_EOL);
        if (count($errors))
        {
            $output->writeln("<info>Product images resized with er-rors:</info>");
            foreach ($errors as $error)
            {
                $output->writeln("<error>{$error}</error>");
            }
        }
        else
        {
            $output->writeln("<info>Product images scheduled successful-ly</info>");
        }
        return Cli::RETURN_SUCCESS;
    }

    /**
    * Get used product images.
    *
    * @param int $product_id
    * @return \Generator
    */

    private function getUsedProductImages($product_id): \Generator
    {
        $batchSelectIterator = $this->batchQueryGenerator->generate(
            'value_id',
            $this->getUsedImagesSelect($product_id),
            100,
            \Magento\Framework\DB\Query\BatchIteratorInterface::NON_UNIQUE_FIELD_ITERATOR
        );
        foreach ($batchSelectIterator as $select)
        {
            foreach ($this->resourceConnection->getConnection()->fetchAll($select) as $key => $value)
            {
                yield $key => $value;
            }
        }
    }

    /**
    * Return select to fetch all used product images.
    *
    * @param int $product_id
    * @return Select
    */

    private function getUsedImagesSelect($product_id): Select
    {
        $query = 'images.disabled = 0 AND image_value.disabled = 0 AND image_value.entity_id = '.$product_id;
        return $this->resourceConnection->getConnection()->select()->distinct()
        ->from(
            ['images' => $this->resourceConnection->getTableName(Gallery::GALLERY_TABLE)],
            'value as filepath'
        )->joinInner(
            ['image_value' => $this->resourceConnection->getTableName(Gallery::GALLERY_VALUE_TABLE)],
            'images.value_id = image_value.value_id',
            []
        )->where($query);
    }

    /**
    * Get the number of unique and used images of products.
    *
    * @param int $product_id
    * @return int
    */

    private function getCountUsedProductImages($product_id): int
    {
        $select = $this->getUsedImagesSelect($product_id)
        ->reset('columns')
        ->reset('distinct')
        ->columns(
            new \Zend_Db_Expr('count(distinct value)')
        );
        return (int) $this->resourceConnection->getConnection()->fetchOne($select);
    }
}

Step 3: After deploying this module, you need to execute this below command to resize a specific product image.

php bin/magento test:product:resize --product_id=1

Here, test:product:resize is custom command and product_id is an argument where you need to pass your product id.

Conclusion:

Using the above method, you can easily resize specific product images in Magento 2 via the command line. Moreover, Image Optimizer Extension for Magento 2 helps to reduce the image size without losing its quality.

Happy Coding!

Previous Article

Magento 2: Add Readonly Field in ui_component Form

Next Article

How to Choose Best Laravel Developer?

Write a Comment

Leave a Comment

Your email address will not be published. Required fields are marked *

Get Connect With Us

Subscribe to our email newsletter to get the latest posts delivered right to your email.
Pure inspiration, zero spam ✨