I know, I know... I promised it long time ago but I decided to take some time off from coding, not even mentioning nerve-wracking Magento(; But I'm back in business now so here is your short guide on how to crop your images. You can use it for almost everything but it's great for designs with square (ish) products images.
Before we start - there's one thing worth mentioning. I haven't figured out a way to extend Varien classes so if you know any - leave a comment below - otherwise you'll have to keep an eye on Image.php and Gd2.php while upgrading. But anyway... first thing you want to do is to create a file structure matching the image on your right hand side. Remember that everything in Magento tends to complain and die unexpectedly because of case sensitivity, so if you want to use your own names keep the uppercase in the same places I did. Whenever you're ready, launch your IDE and proceed with making your hands dirty(; or, alternatively, grab the whole package from here and dig through the code on your own.
class Criography_ExtendedProductImage_Model_Product_Image extends Mage_Catalog_Model_Product_Image
{
protected $_cropDims;
/**
* Set filenames for base file and new file
*
* @param string $file
* @return Mage_Catalog_Model_Product_Image
*/
public function setBaseFile($file)
{
$this->_isBaseFilePlaceholder = false;
if (($file) && (0 !== strpos($file, '/', 0))) {
$file = '/' . $file;
}
$baseDir = Mage::getSingleton('catalog/product_media_config')->getBaseMediaPath();
if ('/no_selection' == $file) {
$file = null;
}
if ($file) {
if ((!file_exists($baseDir . $file)) || !$this->_checkMemory($baseDir . $file)) {
$file = null;
}
}
if (!$file) {
// check if placeholder defined in config
$isConfigPlaceholder = Mage::getStoreConfig("catalog/placeholder/{$this->getDestinationSubdir()}_placeholder");
$configPlaceholder = '/placeholder/' . $isConfigPlaceholder;
if ($isConfigPlaceholder && file_exists($baseDir . $configPlaceholder)) {
$file = $configPlaceholder;
}
else {
// replace file with skin or default skin placeholder
$skinBaseDir = Mage::getDesign()->getSkinBaseDir();
$skinPlaceholder = "/images/catalog/product/placeholder/{$this->getDestinationSubdir()}.jpg";
$file = $skinPlaceholder;
if (file_exists($skinBaseDir . $file)) {
$baseDir = $skinBaseDir;
}
else {
$baseDir = Mage::getDesign()->getSkinBaseDir(array('_theme' => 'default'));
}
}
$this->_isBaseFilePlaceholder = true;
}
$baseFile = $baseDir . $file;
if ((!$file) || (!file_exists($baseFile))) {
throw new Exception(Mage::helper('catalog')->__('Image file not found'));
}
$this->_baseFile = $baseFile;
// build new filename (most important params)
$path = array(
Mage::getSingleton('catalog/product_media_config')->getBaseMediaPath(),
'cache',
Mage::app()->getStore()->getId(),
$path[] = $this->getDestinationSubdir()
);
if((!empty($this->_width)) || (!empty($this->_height)))
$path[] = "{$this->_width}x{$this->_height}";
if(!empty($this->_cropDims))
$path[] = "{$this->_cropDims[0]}x{$this->_cropDims[1]}";
// add misk params as a hash
$miscParams = array(
($this->_keepAspectRatio ? '' : 'non') . 'proportional',
($this->_keepFrame ? '' : 'no') . 'frame',
($this->_keepTransparency ? '' : 'no') . 'transparency',
($this->_constrainOnly ? 'do' : 'not') . 'constrainonly',
$this->_rgbToString($this->_backgroundColor),
'angle' . $this->_angle,
'quality' . $this->_quality
);
// if has watermark add watermark params to hash
if ($this->getWatermarkFile()) {
$miscParams[] = $this->getWatermarkFile();
$miscParams[] = $this->getWatermarkImageOpacity();
$miscParams[] = $this->getWatermarkPosition();
$miscParams[] = $this->getWatermarkWidth();
$miscParams[] = $this->getWatermarkHeigth();
}
$path[] = md5(implode('_', $miscParams));
// append prepared filename
$this->_newFile = implode('/', $path) . $file; // the $file contains heading slash
return $this;
}
/**
* Convert array of 3 items (decimal r, g, b) to string of their hex values
*
* @param array $rgbArray
* @return string
*/
private function _rgbToString($rgbArray)
{
$result = array();
foreach ($rgbArray as $value) {
if (null === $value) {
$result[] = 'null';
}
else {
$result[] = sprintf('%02s', dechex($value));
}
}
return implode($result);
}
/**
* @return Mage_Catalog_Model_Product_Image
*/
public function frontCrop(){
$this->getImageProcessor()->frontCrop($this->_cropDims[0], $this->_cropDims[1]);
return $this;
}
public function setCropDims($width, $height){
$this->_cropDims = array($width, $height);
return $this;
}
}
class Criography_ExtendedProductImage_Helper_Image extends Mage_Catalog_Helper_Image
{
protected $_cropDims = array(0,0);
protected $_scheduleCrop = false;
/**
* Reset all previos data
*/
protected function _reset()
{
$this->_model = null;
$this->_scheduleResize = false;
$this->_scheduleRotate = false;
$this->_scheduleCrop = false;
$this->_angle = null;
$this->_cropDims = array(0,0);
$this->_watermark = null;
$this->_watermarkPosition = null;
$this->_watermarkSize = null;
$this->_watermarkImageOpacity = null;
$this->_product = null;
$this->_imageFile = null;
return $this;
}
public function frontCrop($width=0, $height=0){
$this->setCropDims($width, $height);
$this->_getModel()->setCropDims($width, $height);
$this->_scheduleCrop = true;
return $this;
}
protected function setCropDims($width, $height){
$this->_cropDims = array($width, $height);
return $this;
}
protected function getCropDims(){
return $this->_cropDims;
}
public function __toString()
{
try {
if( $this->getImageFile() ) {
$this->_getModel()->setBaseFile( $this->getImageFile() );
} else {
$this->_getModel()->setBaseFile( $this->getProduct()->getData($this->_getModel()->getDestinationSubdir()) );
}
if( $this->_getModel()->isCached() ) {
return $this->_getModel()->getUrl();
} else {
if( $this->_scheduleRotate ) {
$this->_getModel()->rotate( $this->getAngle() );
}
if ($this->_scheduleResize) {
$this->_getModel()->resize();
}
if( $this->_scheduleCrop ) {
$this->_getModel()->frontCrop( $this->getCropDims() );
}
if( $this->getWatermark() ) {
$this->_getModel()->setWatermark($this->getWatermark());
}
$url = $this->_getModel()->saveFile()->getUrl();
}
} catch( Exception $e ) {
$url = Mage::getDesign()->getSkinUrl($this->getPlaceholder());
}
return $url;
}
}
<?xml version="1.0"?>
<config>
<modules>
<Criography_ExtendedProductImage>
<version>0.1.0</version>
<depends>
<Mage_Catalog />
</depends>
</Criography_ExtendedProductImage>
</modules>
<frontend>
<routers>
<extendedproductimage>
<use>standard</use>
<args>
<module>Criography_ExtendedProductImage</module>
<frontName>extendedproductimage</frontName>
</args>
</extendedproductimage>
</routers>
</frontend>
<global>
<helpers>
<catalog>
<rewrite>
<image>Criography_ExtendedProductImage_Helper_Image</image>
</rewrite>
</catalog>
</helpers>
<models>
<catalog>
<rewrite>
<product_image>Criography_ExtendedProductImage_Model_Product_Image</product_image>
</rewrite>
</catalog>
</models>
</global>
</config><?xml version="1.0"?>
<config>
<modules>
<Criography_ExtendedProductImage>
<active>true</active>
<codePool>local</codePool>
</Criography_ExtendedProductImage>
</modules>
</config>
public function frontCrop($width=0, $height=0){
$this->_getAdapter()->frontCrop($width, $height);
}public function frontCrop($width=0, $height=0){
if($width>10){
$canvasDims = array($width, $height==0 ? $width : $height);
$canvas = imagecreatetruecolor($canvasDims[0], $canvasDims[1]);
//calculate new dimensions
if ($this->_imageSrcWidth/$this->_imageSrcHeight > $canvasDims[0]/$canvasDims[1]) {
$targetDims[1] = $canvasDims[1];
$targetDims[0] = round($this->_imageSrcWidth * $targetDims[1] / $this->_imageSrcHeight);
} else {
$targetDims[0] = $canvasDims[0];
$targetDims[1] = round($this->_imageSrcHeight * $targetDims[0] / $this->_imageSrcWidth);
}
$posArray = array('src'=>array( -(($targetDims[0]-$canvasDims[0])/2), -(($targetDims[1]-$canvasDims[1])/2) ),
'target'=>array( (($targetDims[0]-$canvasDims[0])/2), (($targetDims[1]-$canvasDims[1])/2) )
);
if ($this->_fileType == IMAGETYPE_PNG) $this->_saveAlpha($canvas);
imagecopyresampled(
$canvas,
$this->_imageHandler,
$posArray['src'][0],
$posArray['src'][1],
$posArray['target'][0],
$posArray['target'][1],
$targetDims[0],
$targetDims[1],
$this->_imageSrcWidth,
$this->_imageSrcHeight
);
}else{
return;
}
$this->_imageHandler = $canvas;
$this->refreshImageDimensions();
}<img src="<?php echo $this->helper('catalog/image')->init($this->getProduct(), 'image', $_image->getFile())->frontCrop(100,90); ?>" />As you can see it's not some fancy crop algorithm - it always starts from the centre and allows for single (square) or double (width, height) arguments but it is exactly what I was after. If you want to make something more sophisticated, feel free - I'd actually appreciate if you leave a comment or send me an email(: Oh, and it does work in 1.3.4 and 1.4rc!

Le Glitter - Magento E-Commerce
private function _rgbToString($rgbArray)toprotected function _rgbToString($rgbArray)The signature must have been changed since 1.4. Thank you Marek for this wonderful contribution!