I'm using a modified version of imagefield crop to add a white border around the images.
If I specify a crop area that is outside of the image area then the output image will only contain a stretched version of the area which was within the crop area. ie. specifying negative x or y values would result in the image being stretched. This is using a fixed ratio for the crop area, and a fixed output pixel height and width.

This is how I've made it work without stretching the image:

function imageapi_imagemagick_image_crop(&$image, $x, $y, $width, $height) {
  //Bounds should be < 0 if within the image, and thus no need to add padding!
  $bounds['xo'] = $image->info['width']+$x - ($width); 
  $bounds['yo'] = $image->info['height']+$y - ($height);
  
  //default no border padding
  $border = 0;
  
  //check if we're out of bounds and whether should add padding or not
  if ($bounds['xo'] > 0 || $x < 0 || $bounds['yo'] > 0 || $y < 0) {
    //set x & y should they be out of bounds
    $bounds['x'] = $x<0?abs($x):0;
    $bounds['y'] = $y<0?abs($y):0;
    
    //make the border match the largest culprit
    $border = max($bounds);
    
    //recalculate coordinates:
    $x = $border + $x;
    $y = $border + $y;
  }
  //Add a border 
  $border = ($border>0?'-bordercolor white -border ' . $border . ' ':'');
  
  $image->ops[]  = $border . '-crop '. (int) $width .'x'. (int) $height .'+'. (int) $x .'+'. (int) $y .'!';
  $image->info['width'] = $width;
  $image->info['height'] = $height;
  return TRUE;
}

Note: This simply adds a white border and crops the image correctly if the crop area is out of bounds. I've only tested it minimally, and a fix should probably include setting a custom background color the same way that ImageGD does.

I'm inexperienced with git and therefore not sure on how to make a patch for this. My hope is that someone will pick this up and make a propper fix for it =)

Comments

Dandily’s picture

I use this "scale and crop" patch to add white background to image if its have different aspect ratio then needed (i.e. maximum = "560x380", minimum = "560x380", but image is 690x345).

Add into filefield.module, about 833 line, before:

        // Check for exact dimension requirements (scaling allowed).
        if (strcmp($minimum_dimensions, $maximum_dimensions) == 0 && $info['width']/$max_width != $info['height']/$max_height) {

add

        // scale and crop to fit in exact dimension requirements (with white background)
        if (strcmp($minimum_dimensions, $maximum_dimensions) == 0) {
          if (module_exists('imageapi') && imageapi_default_toolkit()) {
            $res = imageapi_image_open($file->filepath);
            imageapi_image_scale($res, $max_width, $max_height);
            
            if ($max_width != $res->info['width']){ $newx = ($max_width - $res->info['width']) / 2 * -1;} else {$newx = 0;}
            if ($max_height != $res->info['height']){ $newy = ($max_height - $res->info['height']) / 2 * -1;} else {$newy = 0;}
            
            imageapi_image_crop($res, $newx, $newy, $max_width, $max_height);
            imageapi_image_close($res, $file->filepath);
            $info['width'] = $max_width;
            $info['height'] = $max_height;
            $ratio = min($max_width/$info['width'], $max_height/$info['height']);
            $resized = TRUE;
          }
        }