<?php
/**
* Simple but effectively resizes images on the fly. Doesn't upsize, just downsizes like how WordPress likes it.
* If the image already exists, it's served. If not, the image is resized to the specified size, saved for
* future use, then served.
*
* @author Benjamin Intal - Gambit Technologies Inc
* @see https://wordpress.stackexchange.com/questions/53344/how-to-generate-thumbnails-when-needed-only/124790#124790
* @see http://codex.wordpress.org/Function_Reference/get_intermediate_image_sizes
*/
if ( ! function_exists( 'func_otf_regen_thumbs_media_downsize' ) ) {
/**
* The downsizer. This only does something if the existing image size doesn't exist yet.
*
* @param $out boolean false
* @param $id int Attachment ID
* @param $size mixed The size name, or an array containing the width & height
*
* @return mixed False if the custom downsize failed, or an array of the image if successful
*/
function func_otf_regen_thumbs_media_downsize( $out, $id, $size ) {
// Gather all the different image sizes of WP (thumbnail, medium, large) and,
// all the theme/plugin-introduced sizes.
global $_gambit_otf_regen_thumbs_all_image_sizes;
if ( ! isset( $_gambit_otf_regen_thumbs_all_image_sizes ) ) {
global $_wp_additional_image_sizes;
$_gambit_otf_regen_thumbs_all_image_sizes = array();
$interimSizes = get_intermediate_image_sizes();
foreach ( $interimSizes as $sizeName ) {
if ( in_array( $sizeName, array( 'thumbnail', 'medium', 'large' ) ) ) {
$_gambit_otf_regen_thumbs_all_image_sizes[$sizeName]['width'] = get_option( $sizeName . '_size_w' );
$_gambit_otf_regen_thumbs_all_image_sizes[$sizeName]['height'] = get_option( $sizeName . '_size_h' );
$_gambit_otf_regen_thumbs_all_image_sizes[$sizeName]['crop'] = (bool) get_option( $sizeName . '_crop' );
} elseif ( isset( $_wp_additional_image_sizes[$sizeName] ) ) {
$_gambit_otf_regen_thumbs_all_image_sizes[$sizeName] = $_wp_additional_image_sizes[$sizeName];
}
}
}
// This now contains all the data that we have for all the image sizes
$allSizes = $_gambit_otf_regen_thumbs_all_image_sizes;
// If image size exists let WP serve it like normally
$imagedata = wp_get_attachment_metadata( $id );
// Image attachment doesn't exist
if ( ! is_array( $imagedata ) ) {
return false;
}
// If the size given is a string / a name of a size
if ( is_string( $size ) ) {
// If WP doesn't know about the image size name, then we can't really do any resizing of our own
if ( empty( $allSizes[$size] ) ) {
return false;
}
$att_url = wp_get_attachment_url( $id );
if ( $att_url ) {
$check_file = wp_check_filetype( $att_url );
if ( in_array( $check_file['ext'], array( 'jpg', 'png', 'jpeg', 'gif', 'bmp', 'tif' ), true ) ) {
// If the size has already been previously created, use it
if ( ! empty( $imagedata['sizes'][$size] ) && ! empty( $allSizes[$size] ) ) {
// But only if the size remained the same
if ( $allSizes[$size]['width'] == $imagedata['sizes'][$size]['width']
&& $allSizes[$size]['height'] == $imagedata['sizes'][$size]['height'] ) {
return false;
}
// Or if the size is different and we found out before that the size really was different
if ( ! empty( $imagedata['sizes'][$size]['width_query'] )
&& ! empty( $imagedata['sizes'][$size]['height_query'] ) ) {
if ( $imagedata['sizes'][$size]['width_query'] == $allSizes[$size]['width']
&& $imagedata['sizes'][$size]['height_query'] == $allSizes[$size]['height'] ) {
return false;
}
}
}
// Resize the image
$resized = image_make_intermediate_size(
get_attached_file( $id ),
$allSizes[$size]['width'],
$allSizes[$size]['height'],
$allSizes[$size]['crop']
);
// Resize somehow failed
if ( ! $resized ) {
return false;
}
// Save the new size in WP
$imagedata['sizes'][$size] = $resized;
// Save some additional info so that we'll know next time whether we've resized this before
$imagedata['sizes'][$size]['width_query'] = $allSizes[$size]['width'];
$imagedata['sizes'][$size]['height_query'] = $allSizes[$size]['height'];
wp_update_attachment_metadata( $id, $imagedata );
// Serve the resized image
return array( dirname( $att_url ) . '/' . $resized['file'], $resized['width'], $resized['height'], true );
}
}
// If the size given is a custom array size
} else if ( is_array( $size ) ) {
$att_url = wp_get_attachment_url( $id );
if ( $att_url ) {
$check_file = wp_check_filetype( $att_url );
if ( in_array( $check_file['ext'], array( 'jpg', 'png', 'jpeg', 'gif', 'bmp', 'tif' ), true ) ) {
$imagePath = get_attached_file( $id );
$crop = array_key_exists( 2, $size ) ? $size[2] : true;
$new_width = $size[0];
$new_height = $size[1];
// If crop is false, calculate new image dimensions
if ( ! $crop ) {
if ( class_exists( 'Jetpack' ) && Jetpack::is_module_active( 'photon' ) ) {
add_filter( 'jetpack_photon_override_image_downsize', '__return_true' );
$trueData = wp_get_attachment_image_src( $id, 'large' );
} else {
$trueData = wp_get_attachment_image_src( $id, 'large' );
}
if ( $trueData[1] > $trueData[2] ) {
// Width > height
$ratio = $trueData[1] / $size[0];
$new_height = round( $trueData[2] / $ratio );
$new_width = $size[0];
} else {
// Height > width
$ratio = $trueData[2] / $size[1];
$new_height = $size[1];
$new_width = round( $trueData[1] / $ratio );
}
}
// This would be the path of our resized image if the dimensions existed
$imageExt = pathinfo( $imagePath, PATHINFO_EXTENSION );
$imagePath = preg_replace( '/^(.*)\.' . $imageExt . '$/', sprintf( '$1-%sx%s.%s', $new_width, $new_height, $imageExt ), $imagePath );
// If it already exists, serve it
if ( file_exists( $imagePath ) ) {
return array( dirname( $att_url ) . '/' . basename( $imagePath ), $new_width, $new_height, $crop );
}
// If not, resize the image...
$resized = image_make_intermediate_size(
get_attached_file( $id ),
$size[0],
$size[1],
$crop
);
$imagedata = wp_get_attachment_metadata( $id );
// Resize somehow failed
if ( $imagedata['width'] < $new_width && $imagedata['height'] < $new_height ) {
return array( $att_url, $imagedata['width'], $imagedata['height'], false );
}
// Resize somehow failed
if ( ! $resized ) {
return false;
}
// Get attachment meta so we can add new size
// Save the new size in WP so that it can also perform actions on it
$imagedata['sizes'][$size[0] . 'x' . $size[1]] = $resized;
wp_update_attachment_metadata( $id, $imagedata );
// Then serve it
return array( dirname( $att_url ) . '/' . $resized['file'], $resized['width'], $resized['height'], $crop );
}
}
}
return false;
}
add_filter( 'image_downsize', 'func_otf_regen_thumbs_media_downsize', 10, 3 );
}