Search code examples
cakephpuploader

CakePHP Uploader: Change resize values depending on image dimension


I am trying to implement Miles Johnsons excellent Uploader Component into my app. But here is the problem: Depending on the dimensions of the uploaded image, I need to change the resize dimensions.

I tried to modify the transformation in the callback:

    public $actsAs = array(
        'Uploader.Attachment' => array(
            'image' => array(
                'nameCallback' => 'formatName',
                'tempDir' => TMP,
                'uploadDir' => UPLOADDIR,
                'finalPath' => '/img/photos/',
                'overwrite' => false,
                'stopSave' => true,
                'allowEmpty' => false,
                'transforms' => array(
                    array(
                        'class' => 'exif',
                        'self' => true
                    ),
                    'image_sized' => array(
                        'class' => 'resize',
                        'nameCallback' => 'transformSizedNameCallback',
                        'width' => 1680,
                        'height' => 980,
                        'aspect' => true  
                    )
                )
            )
        ),
        'Uploader.FileValidation' => array(
            'image' => array(
                'extension' => array(
                    'value' => array('jpg', 'png', 'jpeg'),
                    'error' => 'Nicht unterstütztes Dateiformat - bitte JPG- oder PNG-Datei hochladen.'
                ),
                'minHeight' => array(
                    'value' => 980,
                    'error' => 'Das Bild muss mindestens 980 Pixel hoch sein.'
                ),
                'minWidth' => array(
                    'value' => 980,
                    'error' => 'Das Bild muss mindestens 980 Pixel breit sein.'
                ),
                'required' => array(
                    'value' => true,
                    'error' => 'Bitte wählen Sie ein Bild aus.'
                )
            )
        )
    );

    public function beforeTransform($options) {
        if($options['dbColumn'] == 'image_sized') {
            if($height > $width) {
                $options['width'] = 980;
                $options['height'] = 1680;
            }
        }
        return $options;
    }

I am able to pinpoint the correct transform, but how do I access the dimensions of the image to be transformed inside of beforeTransform? Where do I get $width and $height from?


Solution

  • I'm not familiar with it, but from looking at the code it seems like the only option you have at that point is using the dbColumn value to access the currently processed field data, something like

    $file = $this->data[$this->alias][$options['dbColumn']];
    

    Of course this requires the dbColumn value to match the input field name! If that's not the case, then you'll need an additional option that holds the field name and use that one instead.

    Now $file is just the raw data, most probably a file upload array. Assuming a single file, check tmp_name for its dimensions, either by yourself, or utilize the Transite\File class which can handle file upload arrays and exposes a method for retrieving the dimensions of a possible image:

    $transitFile = new File($file);
    $dimensions = $transitFile->dimensions();
    

    https://github.com/milesj/transit/blob/1.5.1/src/Transit/File.php#L121

    So finally you could do something like this:

    public function beforeTransform($options) {
        if($options['dbColumn'] == 'image_sized') {
            $file = $this->data[$this->alias][$options['dbColumn']];
            $transitFile = new \Transit\File($file);
            $dimensions = $transitFile->dimensions();
    
            if($dimensions === null) {
                // not an image or something else gone wrong,
                // maybe throw an exception or wave your arms and call for help
            } elseif($dimensions['height'] > $dimensions['width']) {
                $options['width'] = 980;
                $options['height'] = 1680;
            }
        }
        return $options;
    }
    

    Please not that this is all untested example code.