How can I make add_image_size() crop from the top?

I have a series of posts, all with featured images, but I need to be able to customise the crop top right corner. In this instance, I need them to be cropped from top right, but it would be useful to also know how to position that point myself.

At present, the add_image_size() function is taking its crop from the centre of the image. Not always pretty!!

Related posts

Leave a Reply

5 comments

  1. Intermediate image generation is extremely rigid. image_resize() keeps it close to code and completely lacks hooks.

    Pretty much only option for this is to hook into wp_generate_attachment_metadata and overwrite WP-generated image with your own (which will need bit of a image_resize() fork).

    I need this for work so I might be able to share some code later.

    Ok, here is rough, but working example. Note that setting up crop in this way requires understanding of imagecopyresampled().

    add_filter('wp_generate_attachment_metadata', 'custom_crop');
    
    function custom_crop($metadata) {
    
        $uploads = wp_upload_dir();
        $file = path_join( $uploads['basedir'], $metadata['file'] ); // original image file
        list( $year, $month ) = explode( '/', $metadata['file'] );
        $target = path_join( $uploads['basedir'], "{$year}/{$month}/".$metadata['sizes']['medium']['file'] ); // intermediate size file
        $image = imagecreatefromjpeg($file); // original image resource
        $image_target = wp_imagecreatetruecolor( 44, 44 ); // blank image to fill
        imagecopyresampled($image_target, $image, 0, 0, 25, 15, 44, 44, 170, 170); // crop original
        imagejpeg($image_target, $target, apply_filters( 'jpeg_quality', 90, 'image_resize' )); // write cropped to file
    
        return $metadata;
    }
    
  2. WordPress codex has the answer, its below.

    Set the image size by cropping the image and defining a crop position:

    add_image_size( 'custom-size', 220, 220, array( 'left', 'top' ) ); // Hard crop left top
    

    When setting a crop position, the first value in the array is the x
    axis crop position, the second is the y axis crop position.

    x_crop_position accepts ‘left’ ‘center’, or ‘right’. y_crop_position
    accepts ‘top’, ‘center’, or ‘bottom’. By default, these values default
    to ‘center’ when using hard crop mode.

    And also codex references a page which shows how crop positions acts.

    http://havecamerawilltravel.com/photographer/wordpress-thumbnail-crop

  3. Alternative solution here: http://pixert.com/blog/cropping-post-featured-thumbnails-from-top-instead-of-center-in-wordpress-with-native-cropping-tool/

    Just add this code to functions.php, then use “Regenerate Thumbnails” plugin (https://wordpress.org/plugins/regenerate-thumbnails/):

    function px_image_resize_dimensions( $payload, $orig_w, $orig_h, $dest_w, $dest_h, $crop ){
    
    // Change this to a conditional that decides whether you want to override the defaults for this image or not.
    if( false )
    return $payload;
    
    if ( $crop ) {
    // crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
    $aspect_ratio = $orig_w / $orig_h;
    $new_w = min($dest_w, $orig_w);
    $new_h = min($dest_h, $orig_h);
    
    if ( !$new_w ) {
    $new_w = intval($new_h * $aspect_ratio);
    }
    
    if ( !$new_h ) {
    $new_h = intval($new_w / $aspect_ratio);
    }
    
    $size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
    
    $crop_w = round($new_w / $size_ratio);
    $crop_h = round($new_h / $size_ratio);
    
    $s_x = 0; // [[ formerly ]] ==> floor( ($orig_w - $crop_w) / 2 );
    $s_y = 0; // [[ formerly ]] ==> floor( ($orig_h - $crop_h) / 2 );
    } else {
    // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
    $crop_w = $orig_w;
    $crop_h = $orig_h;
    
    $s_x = 0;
    $s_y = 0;
    
    list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
    }
    
    // if the resulting image would be the same size or larger we don't want to resize it
    if ( $new_w >= $orig_w && $new_h >= $orig_h )
    return false;
    
    // the return array matches the parameters to imagecopyresampled()
    // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
    return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h );
    
    }
    add_filter( 'image_resize_dimensions', 'px_image_resize_dimensions', 10, 6 );