15

I'm using Magento 2 CE Version 2.1.0

I have Custom Module with Image Field. When it's uploaded, i want different size images as for product we have Thumbnail Image, List Image & Product Detail Page Image.

Able to upload 1 image without resize.

I'm using below code for resizing image, but it's giving product image URL. Not my custom module.

\app\code\Custom\Module\Block\MyPosts\Edit.php

public function getImage($posts, $image) {
    $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
    $_imagehelper = $objectManager->get('Magento\Catalog\Helper\Image');
    echo $postImage = $_imagehelper->init($posts, $image)->constrainOnly(FALSE)->keepAspectRatio(TRUE)->keepFrame(FALSE)->resize(400)->getUrl();
    exit;
}

It gives below URL http://localhost/magento2/pub/static/frontend/Magento/luma/en_US/Magento_Catalog/images/product/placeholder/.jpg

My image is stored here: \magento2\pub\media\custom_module\posts\image.

How can i get resize image with this path & how can i save/retrieve different size image?

5 Answers 5

20

You can check in details by click, Resize Custom Image in Magento 2

Inside Block file keep below code,

   protected $_filesystem ;
   protected $_imageFactory;
   public function __construct(            
        \Magento\Framework\Filesystem $filesystem,         
        \Magento\Framework\Image\AdapterFactory $imageFactory         
        ) {         
        $this->_filesystem = $filesystem;               
        $this->_imageFactory = $imageFactory;         
        }

    // pass imagename, width and height
    public function resize($image, $width = null, $height = null)
    {
        $absolutePath = $this->_filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA)->getAbsolutePath('custom_module/posts/').$image;
        if (!file_exists($absolutePath)) return false;
        $imageResized = $this->_filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA)->getAbsolutePath('resized/'.$width.'/').$image;
        if (!file_exists($imageResized)) { // Only resize image if not already exists.
            //create image factory...
            $imageResize = $this->_imageFactory->create();         
            $imageResize->open($absolutePath);
            $imageResize->constrainOnly(TRUE);         
            $imageResize->keepTransparency(TRUE);         
            $imageResize->keepFrame(FALSE);         
            $imageResize->keepAspectRatio(TRUE);         
            $imageResize->resize($width,$height);  
            //destination folder                
            $destination = $imageResized ;    
            //save image      
            $imageResize->save($destination);         
        } 
        $resizedURL = $this->_storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA).'resized/'.$width.'/'.$image;
        return $resizedURL;
  } 

Now Call inside phtml file,

$block->resize('test.jpg',500,400);
7
  • Bravo. Works perfectly. So while Add Image we don't have to upload with different sizes. Only while displaying we have to manage correct @Rakesh?
    – Jackson
    Commented Sep 2, 2016 at 6:00
  • 1
    yes when we have to display at that time manage. Commented Sep 2, 2016 at 6:07
  • doesn't work when we try to resize 1 image and put it in same folder with same image same. like this : $absolutePath = $this->_filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA)->getRelativePath('C:/xampp/htdocs/magento/app/code/Aht/BannerSlider/view/frontend/web/').$image; $imageResized = $this->_filesystem->getDirectoryRead(\Magento\Framework\App\Filesystem\DirectoryList::MEDIA)->getRelativePath('C:/xampp/htdocs/magento/app/code/Aht/BannerSlider/view/frontend/web/').$image;
    – fudu
    Commented Aug 8, 2018 at 3:37
  • As already mentioned, this should not be the accepted answer. You do not need to do all this yourself - simply use the already existing image helper of the Magento core.
    – fritzmg
    Commented Aug 22, 2018 at 11:29
  • @RakeshJesadiya,its giving me unknown text as a url Commented Feb 18, 2019 at 14:09
18

The accepted answer doesn’t consider caching the image to improve performance. You don’t need to resize and overwrite the image every time it’s requested. The following approach saves the resized image to a "cache" folder so successive calls return the image from the cache. The method is contained on a helper (not a block) so you can call it from any template you like:

app/code/Vendor/Namespace/Helper/Image.php

<?php

namespace Vendor\Namespace\Helper;

use Magento\Framework\App\Filesystem\DirectoryList;

class Image extends \Magento\Framework\App\Helper\AbstractHelper
{
    /**
     * Custom directory relative to the "media" folder
     */
    const DIRECTORY = 'custom_module/posts';

    /**
     * @var \Magento\Framework\Filesystem\Directory\WriteInterface
     */
    protected $_mediaDirectory;

    /**
     * @var \Magento\Framework\Image\Factory
     */
    protected $_imageFactory;

    /**
     * Store manager
     *
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $_storeManager;

    /**
     * @param \Magento\Framework\App\Helper\Context $context
     * @param \Magento\Framework\Filesystem $filesystem
     * @param \Magento\Framework\Image\Factory $imageFactory
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager
     */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Framework\Filesystem $filesystem,
        \Magento\Framework\Image\AdapterFactory $imageFactory,
        \Magento\Store\Model\StoreManagerInterface $storeManager
    ) {
        $this->_mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA);
        $this->_imageFactory = $imageFactory;
        $this->_storeManager = $storeManager;
        parent::__construct($context);
    }

    /**
     * First check this file on FS
     *
     * @param string $filename
     * @return bool
     */
    protected function _fileExists($filename)
    {
        if ($this->_mediaDirectory->isFile($filename)) {
            return true;
        }
        return false;
    }

    /**
     * Resize image
     * @return string
     */
    public function resize($image, $width = null, $height = null)
    {
        $mediaFolder = self::DIRECTORY;

        $path = $mediaFolder . '/cache';
        if ($width !== null) {
            $path .= '/' . $width . 'x';
            if ($height !== null) {
                $path .= $height ;
            }
        }

        $absolutePath = $this->_mediaDirectory->getAbsolutePath($mediaFolder) . $image;
        $imageResized = $this->_mediaDirectory->getAbsolutePath($path) . $image;

        if (!$this->_fileExists($path . $image)) {
            $imageFactory = $this->_imageFactory->create();
            $imageFactory->open($absolutePath);
            $imageFactory->constrainOnly(true);
            $imageFactory->keepTransparency(true);
            $imageFactory->keepFrame(true);
            $imageFactory->keepAspectRatio(true);
            $imageFactory->resize($width, $height);
            $imageFactory->save($imageResized);
        }

        return $this->_storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) . $path . $image;
    }
}

Now from any .phtml template you can call the method like this:

<!-- Get a reference to the Image helper -->
<?php $image = $this->helper('Vendor\Namespace\Helper\Image'); ?>
.
.
.
<!-- Resize the image by specifying width only -->
<img src="<?php echo $image->resize('/my-picture.jpg', 1200); ?>">

<!-- Resize the image by specifying width and height -->
<img src="<?php echo $image->resize('/my-picture.jpg', 640, 480); ?>">
6
  • 1
    May I suggest adding a check for the original file, in case that it doesn't exist? in the resize() function: I changed if (!$this->_fileExists($path . $image)) { to if (!$this->_fileExists($path . $image) && $this->_fileExists($mediaFolder . $image)) { Commented Jul 21, 2017 at 13:53
  • Work like a charm, thanks you. This should be the accepted answer
    – fudu
    Commented Aug 8, 2018 at 3:54
  • You can also simply use the existing \Magento\Catalog\Helper\Image.
    – fritzmg
    Commented Aug 22, 2018 at 11:30
  • 2
    @fritzmg isn't this helper only intended for product images? How can I use it with custom image which is not a product image but image uploaded with custom module to /pub/media folder and has no relation to product?
    – kovinet
    Commented Oct 10, 2018 at 18:14
  • 1
    @kovinet - It works with any image as long as the original image is contained within the pub/media/ folder. Just pass the path of the image to $image->resize('image/path/filename.ext'); Commented Oct 12, 2018 at 11:59
4

I'm afraid you don't need to create new classes for resizing your images, since Magento helpers already have it (see \Magento\Catalog\Helper\Image::resize).

So, you can just do:

$_imageHelper = \Magento\Framework\App\ObjectManager::getInstance()->get('Magento\Catalog\Helper\Image');

echo $_imageHelper->init($product, 'small_image', ['type'=>'small_image'])->keepAspectRatio(true)->resize('65','65')->getUrl();

You can also see an example of this usage at \Magento\VisualMerchandiser\Block\Adminhtml\Category\Merchandiser\Tile::getImageUrl (Magento EE only I guess)

2
  • But your example would only work with product images, right? The question is about custom module with Image field. So there is no $product but only path to the image file in /media.
    – kovinet
    Commented Oct 10, 2018 at 18:09
  • You are right @kovinet. I didn't notice it at that time. However, this thread helped me with product images, and it seems its helping others. But thank you for your comment. As soon I have some time, I'll look for a better answer. ;) Commented Oct 11, 2018 at 21:37
2

I've encountered an issue where the resize method wouldn't crop the image to my dimensions so you need to calculate the crop values from top and bottom or left and right, depending on your original image size. I used the code from @Rakesh and modified it so it checks whether the original image is taller or wider and crops accordingly:

public function resize($image, $width = null, $height = null)
{
    $mediaFolder = self::DIRECTORY;

    $path = $mediaFolder . 'cache';
    if ($width !== null) {
        $path .= '/' . $width . 'x';
        if ($height !== null) {
            $path .= $height ;
        }
    }

    $absolutePath = $this->_mediaDirectory->getAbsolutePath($mediaFolder) . $image;
    $imageResized = $this->_mediaDirectory->getAbsolutePath($path) . $image;

    if (!$this->_fileExists($path . $image) && $this->_fileExists($mediaFolder . $image)) {
        $imageFactory = $this->_imageFactory->create();
        $imageFactory->open($absolutePath);
        $imageFactory->constrainOnly(true);
        $imageFactory->keepAspectRatio(true);
        $imageFactory->keepFrame(false);

        $originalWidth = $imageFactory->getOriginalWidth();
        $originalHeight = $imageFactory->getOriginalHeight();

        $oldAspectRatio = $originalWidth / $originalHeight;
        $newAspectRatio = $width / $height;

        if ($oldAspectRatio > $newAspectRatio) {
            // original image is wider than the desired dimensions
            $imageFactory->resize(null, $height);
            $crop = ($imageFactory->getOriginalWidth() - $width) / 2;
            $imageFactory->crop(0, $crop, $crop, 0);
        } else {
            // it's taller...
            $imageFactory->resize($width, null);
            $crop = ($imageFactory->getOriginalHeight() - $height) / 2;
            $imageFactory->crop($crop, 0, 0, $crop);
        }

        $imageFactory->save($imageResized);

    }

    return $this->_storeManager
            ->getStore()
            ->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA) . $path . $image;
}
-1

@Rakesh -- I have done same but it is not working for me there is an error

Blockquote Error filtering template: Warning: getimagesize(/var/www/html/sitename/pub/media/onecategory/6/7/671471390.jpg): failed to open stream: No such file or directory in /var/www/html/sitename/vendor/magento/framework/Image/Adapter/AbstractAdapter.php on line 304

can you help me in this.

Thank you.

6
  • 1
    Do you find the solution? Because i'm in your situation now. :(
    – fudu
    Commented Aug 14, 2018 at 8:51
  • please check folder or file permission. Commented Aug 14, 2018 at 9:41
  • doesn't have folder Aht_BannerSlider/images/slide_1.jpg in C:/xampp/htdocs/magento/pub/media/Aht_BannerSlider/images/slide_1.jpg, And also i have just give the permission for the pub folder.
    – fudu
    Commented Aug 14, 2018 at 9:46
  • And still doesn't work. :(
    – fudu
    Commented Aug 14, 2018 at 9:56
  • 1
    please check last answer on this page. Commented Aug 14, 2018 at 9:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.