the latest from 2am Media

1 Nov

Magento Adaptive Resize/Resize to best fit

BY

Magento’s built in image resizing is a pretty powerful in its own right but there is one function Magento’s image helper lacks and that’s adaptive resizing!

What is Adaptive Resizing?

Adaptive resizing is ideal in a situation such as when your thumbnail images are always uniform in width and height, as no matter the original image orientation it resizes your image down to the closest match and then crops from the centre the desired width and height, for example you can read the phpthumb docs on adaptive resizing.

So some help from phpthumbs source and this post on the Magento forums regarding a crop to square function and I was all set to create my adaptive resize function, with full helper integration.

How to implement adaptive resizing in Magento

First of all copy the following 4 files to your local namespace, remembering never modify the core files. (hacking the core)

magento/lib/Varien/Image.php
magento/lib/Varien/Image/Adapter/Gd2.php
magento/app/code/core/Mage/Catalog/Helper/Image.php
magento/app/code/core/Mage/Catalog/Model/Product/Image.php

and copy to the following locations

magento/app/code/local/Varien/Image.php
magento/app/code/local/Varien/Image/Adapter/Gd2.php
magento/app/code/local/Mage/Catalog/Helper/Image.php
magento/app/code/local/Mage/Catalog/Model/Product/Image.php

now open up magento/app/code/loval/Varien/Image.php and add the following code below the resize() function

/**
* Adaptive resize an image
*
* @param int $width
* @param int $height
* @access public
* @return void
*/
public function adaptiveResize($width, $height = null)
{
return $this->_getAdapter()->adaptiveResize($width, $height);
}

and now edit the magento/app/code/local/Varien/Image/Adapter/Gd2.php file and once again copy the following below the resize() function

 /**
* Change the image size down to a best match then crop from the center
*
* @param int $frameWidth
* @param int $frameHeight
*/
public function adaptiveResize($frameWidth = null, $frameHeight = null)
{
  if (empty($frameWidth) && empty($frameHeight)) {
    throw new Exception('Invalid image dimensions.');
  }
  $widthDistance = $this->_imageSrcWidth - $frameWidth;
  $heightDistance = $this->_imageSrcHeight - $frameHeight;
  if (($frameWidth / $frameHeight) > ($this->_imageSrcWidth / $this->_imageSrcHeight))
  {
    $this->resize($frameWidth, null);
  }
  else
  {
    $this->resize(null, $frameHeight);
  }
  $cropX = 0;
  $cropY = 0;
  if ($this->_imageSrcWidth > $frameWidth)
  {
    $cropX = intval(($this->_imageSrcWidth - $frameWidth) / 2);
  }
  elseif ($this->_imageSrcHeight > $frameHeight)
  {
    $cropY = intval(($this->_imageSrcHeight - $frameHeight) / 2);
  }
  $isAlpha     = false;
  $isTrueColor = false;
  $this->_getTransparency($this->_imageHandler, $this->_fileType, $isAlpha, $isTrueColor);
  if ($isTrueColor)
  {
    $newImage = imagecreatetruecolor($frameWidth, $frameHeight);
  }
  else
  {
    $newImage = imagecreate($frameWidth, $frameHeight);
  }
  $this->_fillBackgroundColor($newImage);
  imagecopyresampled($newImage, $this->_imageHandler, 0, 0, $cropX, $cropY, $frameWidth, $frameHeight, $frameWidth, $frameHeight);
  $this->_imageHandler = $newImage;
  $this->refreshImageDimensions();
}

now that is actually enough to use the resize function by loading the image adapter directly but that would just be cumbersome so lets also extend the image helper class. Open the magento/app/code/local/Mage/Catalog/Helper/Image.php file and add the following below protected $_scheduleResize = false;

protected $_scheduleAdaptiveResize = false;

next add the following code below $this->_scheduleResize = false;

$this->_scheduleAdaptiveResize = false;

and add the following below the resize() function

public function adaptiveResize($width, $height = null)
{
$this->_getModel()->setWidth($width)->setHeight($height);
$this->_scheduleAdaptiveResize = true;
return $this;
}

finally under the following lines in the same file
if ($this->_scheduleResize) {
$this->_getModel()->resize();
}

add the following code

if ($this->_scheduleAdaptiveResize){
$this->_getModel()->adaptiveResize();
}

save the file and finally open our last file to edit magento/app/code/local/Mage/Catalog/Model/Product/Image.php

once again underneath the existing resize function add the following code

public function adaptiveResize()
{
if (is_null($this->getWidth()) && is_null($this->getHeight())) {
return $this;
}
$this->getImageProcessor()->adaptiveResize($this->_width, $this->_height);
return $this;
}

And thats it! You can now use the adaptiveResize function anywhere you can use the resize() function, an example usage would be within you magento/app/design/frontend/default/base/template/catalog/product/list.phtml template, like the following code snippit took from one of our templates:

<img src="<?php echo $this->helper('catalog/image')->init($_product, 'small_image')->constrainOnly(TRUE)->keepAspectRatio(TRUE)->keepFrame(FALSE)->adaptiveResize(172,229); ?>" width="172" height="229" alt="<?php echo $this->stripTags($this->getImageLabel($_product, 'small_image'), null, true) ?>" />

You can see a working example of this adaptive resize code on our clients website Peachy Cheeks, which specialises in raunchy underwear.

If you have any improvements or suggestions leave a comment and we will update the code accordingly!

15 Responses to “Magento Adaptive Resize/Resize to best fit”

  1. Bart Popenoe

    Nice instructions! Just what I’d been looking for.

    It doesn’t seem to be working for me though. Is there something that needs to be done in the Admin (other than flushing the cache) in order to get Magento to use the files in the app/code/local directory?

  2. Bart Popenoe

    To anyone looking to implement this, pay close attention to the last block of code:

    <img src="helper(‘catalog/image’)->init($_product, ‘small_image’)->constrainOnly(TRUE)->keepAspectRatio(TRUE)->keepFrame(FALSE)->adaptiveResize(172,229); ?>” width=”172″ height=”229″ alt=”stripTags($this->getImageLabel($_product, ‘small_image’), null, true) ?>” />

    You’ll want to make sure that you include the “->keepFrame(FALSE)” in your image call or your image likely won’t fill the entire frame. With the correct specs in the image call, works like a champ.

    Cheers.

  3. Slith

    Thanks for the tip, while I got this to work my dev station locally, when I upload to my host (simplehelix) I’m getting the following error:

    Call to undefined method Mage_Catalog_Helper_Image::adaptiveResize() in /home/mycompany/domains/mydomain.com/public_html/app/design/frontend/default/mytheme/template/catalog/product/list.phtml on line 57

    line 57:

    <a href="getProductUrl() ?>” title=”stripTags($this->getImageLabel($_product, ‘image’), null, true) ?>” class=”product-image”><img src="helper(‘catalog/image’)->init($_product, ‘image’)->constrainOnly(TRUE)->keepAspectRatio(TRUE)->keepFrame(FALSE)->adaptiveResize(140,190); ?>” width=”140″ height=”190″ />

    ….not sure what I’m missing. I’m currently running Magento ver. 1.4.1.0. any help is appreciated.

  4. Slith

    I figured out the problem! And I think Bart’s problem might be related. I had Compilation enabled so it was not recognizing changes in app/code/local/Mage/Catalog/Helper/Image.php

    Make sure Compilation is disabled in System > Tools > Compilation!

  5. Mage

    I just saved around 5-6h of work.Thank you! It works perfectly!!!

  6. Bart Popenoe

    One thing to be careful for: you need to make sure that you’re scaling the image down when you use adaptive resizing. If either of the original image dimensions are smaller than the adaptive resize parameters, you’ll get a fatal error.

  7. Valentin

    Worked perfectly for me THANK YOU SO MUCH!
    the only thing I missed is whether there is a possibility to choose not ot pick the center of the image but the top part of it. Anyone has an idea?

  8. Marcos

    Simple and elegant solution
    Congratulations and thanks a lot.

  9. Salvatore

    Great! Thank you very much!

  10. Paul

    Hi!
    The thumbnails don’t show up. Only the Magento default image.

    Am I missing something?

  11. Matt

    This worked great on 1.7, thank you.

  12. matt

    You set these but do nothing with them

    $widthDistance = $this->_imageSrcWidth – $frameWidth;
    $heightDistance = $this->_imageSrcHeight – $frameHeight;

  13. Leon

    Original author here,

    Apologies for not responding to most of the comments, this is an old blog post of which I never realised gained so much traction!

    Super news though for everyone who struggled to get it to work, I have actually updated the original code and bundled it into a package to be easily installable! Simply download & extract into your Magento install director.

    You can download and check out the Module at

    https://github.com/wearefarm/magento-adaptive-resize

  14. andy

    i want to properly resize categories’ images, in my template/catalog/category/view.phtml i need to modify this code, but i dont know how to call the adaptiveResize function

    helper(‘catalog/output’);
    $_category = $this->getCurrentCategory();
    $_imgHtml = ”;
    if ($_imgUrl = $_category->getImageUrl()) {
    $_imgHtml = ‘htmlEscape($_category->getName()).’” title=”‘.$this->htmlEscape($_category->getName()).’” />’;
    $_imgHtml = $_helper->categoryAttribute($_category, $_imgHtml, ‘image’);
    }
    ?>

  15. digitalbod

    Many thanks for a helpful tool it works great but apart from one thing and i am sure it must be me or something but i cannot get the main product image to resize, everything else works a charm, category views, new products, related products honestly everything.

    Any chance you could help

Like what you see?

If you've got a web design or internet marketing project in mind and you think we're the team for you, pop in for a coffee and a chat...

Get in touch →