SHOW:
|
|
- or go back to the newest paste.
1 | <?php | |
2 | - | /* Original code from: |
2 | + | /* |
3 | - | * http://bradt.ca/archives/image-crop-position-in-wordpress/ |
3 | + | |
4 | * | |
5 | - | * Modified to WordPress Answers: |
5 | + | |
6 | - | * http://wordpress.stackexchange.com/q/51920/12615 |
6 | + | |
7 | */ | |
8 | - | * Check the function bt_image_make_intermediate_size |
8 | + | |
9 | - | * That's where the Thumbnails renaming occurs and all added images must be inserted |
9 | + | |
10 | * bt_add_image_size( 'product-screenshot', 300, 300, array( 'left', 'top' ) ); | |
11 | * bt_add_image_size( 'product-feature', 460, 345, array( 'center', 'top' ) ); | |
12 | */ | |
13 | ||
14 | add_filter( 'intermediate_image_sizes_advanced', 'bt_intermediate_image_sizes_advanced' ); | |
15 | add_filter( 'wp_generate_attachment_metadata', 'bt_generate_attachment_metadata', 10, 2 ); | |
16 | ||
17 | /** | |
18 | * Registers a new image size with cropping positions | |
19 | * | |
20 | * The $crop parameter works as in the 'add_image_size' function taking true or | |
21 | * false values. If set to true, the default cropping position is 'center', 'center'. | |
22 | * | |
23 | * The $crop parameter also takes an array of the format | |
24 | * array( x_crop_position, y_crop_position ) | |
25 | * x_crop_position can be 'left', 'center', 'right' | |
26 | * y_crop_position can be 'top', 'center', 'bottom' | |
27 | * | |
28 | * @param string $name Image size identifier. | |
29 | * @param int $width Image width. | |
30 | * @param int $height Image height. | |
31 | * @param bool|array $crop Optional, default is false. Whether to crop image to specified height and width or resize. An array can specify positioning of the crop area. | |
32 | * @return bool|array False, if no image was created. Metadata array on success. | |
33 | */ | |
34 | function bt_add_image_size( $name, $width = 0, $height = 0, $crop = false ) { | |
35 | global $_wp_additional_image_sizes; | |
36 | $_wp_additional_image_sizes[$name] = array( 'width' => absint( $width ), 'height' => absint( $height ), 'crop' => $crop ); | |
37 | } | |
38 | ||
39 | ||
40 | /** | |
41 | * Returning no sizes (an empty array) will force | |
42 | * wp_generate_attachment_metadata to skip creating intermediate image sizes on | |
43 | * upload, then we can run our own resizing functions by hooking into the | |
44 | * 'wp_generate_attachment_metadata' filter | |
45 | */ | |
46 | function bt_intermediate_image_sizes_advanced( $sizes ) { | |
47 | return array(); | |
48 | } | |
49 | ||
50 | ||
51 | function bt_generate_attachment_metadata( $metadata, $attachment_id ) { | |
52 | $attachment = get_post( $attachment_id ); | |
53 | ||
54 | $uploadPath = wp_upload_dir(); | |
55 | $file = path_join($uploadPath['basedir'], $metadata['file']); | |
56 | ||
57 | if ( !preg_match('!^image/!', get_post_mime_type( $attachment )) || !file_is_displayable_image( $file ) ) return $metadata; | |
58 | ||
59 | global $_wp_additional_image_sizes; | |
60 | ||
61 | foreach ( get_intermediate_image_sizes() as $s ) { | |
62 | $sizes[$s] = array( 'width' => '', 'height' => '', 'crop' => FALSE ); | |
63 | if ( isset( $_wp_additional_image_sizes[$s]['width'] ) ) | |
64 | $sizes[$s]['width'] = intval( $_wp_additional_image_sizes[$s]['width'] ); // For theme-added sizes | |
65 | else | |
66 | $sizes[$s]['width'] = get_option( "{$s}_size_w" ); // For default sizes set in options | |
67 | if ( isset( $_wp_additional_image_sizes[$s]['height'] ) ) | |
68 | $sizes[$s]['height'] = intval( $_wp_additional_image_sizes[$s]['height'] ); // For theme-added sizes | |
69 | else | |
70 | $sizes[$s]['height'] = get_option( "{$s}_size_h" ); // For default sizes set in options | |
71 | if ( isset( $_wp_additional_image_sizes[$s]['crop'] ) ) | |
72 | $sizes[$s]['crop'] = $_wp_additional_image_sizes[$s]['crop']; | |
73 | else | |
74 | $sizes[$s]['crop'] = get_option( "{$s}_crop" ); | |
75 | } | |
76 | ||
77 | foreach ( $sizes as $size => $size_data ) { | |
78 | $resized = bt_image_make_intermediate_size( $file, $size_data['width'], $size_data['height'], $size_data['crop'] ); | |
79 | if ( $resized ) | |
80 | - | $resized = bt_image_make_intermediate_size( $file, $size_data['width'], $size_data['height'], $size_data['crop'], $size ); |
80 | + | |
81 | } | |
82 | ||
83 | return $metadata; | |
84 | } | |
85 | ||
86 | ||
87 | /** | |
88 | * Resize an image to make a thumbnail or intermediate size. | |
89 | * | |
90 | * The returned array has the file size, the image width, and image height. The | |
91 | * filter 'image_make_intermediate_size' can be used to hook in and change the | |
92 | * values of the returned array. The only parameter is the resized file path. | |
93 | * | |
94 | * @param string $file File path. | |
95 | * @param int $width Image width. | |
96 | * @param int $height Image height. | |
97 | * @param bool|array $crop Optional, default is false. Whether to crop image to specified height and width or resize. An array can specify positioning of the crop area. | |
98 | * @return bool|array False, if no image was created. Metadata array on success. | |
99 | */ | |
100 | function bt_image_make_intermediate_size( $file, $width, $height, $crop = false ) { | |
101 | if ( $width || $height ) { | |
102 | - | function bt_image_make_intermediate_size( $file, $width, $height, $crop = false, $size ) { |
102 | + | $resized_file = bt_image_resize( $file, $width, $height, $crop, null, null, 90 ); |
103 | if ( !is_wp_error( $resized_file ) && $resized_file && $info = getimagesize( $resized_file ) ) { | |
104 | - | switch($size) { |
104 | + | |
105 | - | case 'thumbnail': |
105 | + | |
106 | - | $suffix = 't'; |
106 | + | |
107 | - | break; |
107 | + | |
108 | - | case 'medium': |
108 | + | |
109 | - | $suffix = 'm'; |
109 | + | |
110 | - | break; |
110 | + | |
111 | - | case 'large': |
111 | + | |
112 | - | $suffix = 'l'; |
112 | + | |
113 | - | break; |
113 | + | |
114 | - | default: |
114 | + | |
115 | - | $suffix = null; |
115 | + | |
116 | - | break; |
116 | + | |
117 | /** | |
118 | - | $resized_file = bt_image_resize( $file, $width, $height, $crop, $suffix, null, 90 ); |
118 | + | |
119 | * | |
120 | * Calculate dimensions and coordinates for a resized image that fits within a | |
121 | * specified width and height. If $crop is true, the largest matching central | |
122 | * portion of the image will be cropped out and resized to the required size. | |
123 | * | |
124 | * @param int $orig_w Original width. | |
125 | * @param int $orig_h Original height. | |
126 | * @param int $dest_w New width. | |
127 | * @param int $dest_h New height. | |
128 | * @param bool $crop Optional, default is false. Whether to crop image or resize. | |
129 | * @return bool|array False, on failure. Returned array matches parameters for imagecopyresampled() PHP function. | |
130 | */ | |
131 | function bt_image_resize_dimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop = false) { | |
132 | ||
133 | if ($orig_w <= 0 || $orig_h <= 0) | |
134 | return false; | |
135 | // at least one of dest_w or dest_h must be specific | |
136 | if ($dest_w <= 0 && $dest_h <= 0) | |
137 | return false; | |
138 | ||
139 | if ( $crop ) { | |
140 | // crop the largest possible portion of the original image that we can size to $dest_w x $dest_h | |
141 | $aspect_ratio = $orig_w / $orig_h; | |
142 | $new_w = min($dest_w, $orig_w); | |
143 | $new_h = min($dest_h, $orig_h); | |
144 | ||
145 | if ( !$new_w ) { | |
146 | $new_w = intval($new_h * $aspect_ratio); | |
147 | } | |
148 | ||
149 | if ( !$new_h ) { | |
150 | $new_h = intval($new_w / $aspect_ratio); | |
151 | } | |
152 | ||
153 | $size_ratio = max($new_w / $orig_w, $new_h / $orig_h); | |
154 | ||
155 | $crop_w = round($new_w / $size_ratio); | |
156 | $crop_h = round($new_h / $size_ratio); | |
157 | ||
158 | if ( !is_array( $crop ) || count( $crop ) != 2 ) { | |
159 | $crop = apply_filters( 'image_resize_crop_default', array( 'center', 'center' ) ); | |
160 | } | |
161 | ||
162 | switch ( $crop[0] ) { | |
163 | case 'left': $s_x = 0; break; | |
164 | case 'right': $s_x = $orig_w - $crop_w; break; | |
165 | default: $s_x = floor( ( $orig_w - $crop_w ) / 2 ); | |
166 | } | |
167 | ||
168 | switch ( $crop[1] ) { | |
169 | case 'top': $s_y = 0; break; | |
170 | case 'bottom': $s_y = $orig_h - $crop_h; break; | |
171 | default: $s_y = floor( ( $orig_h - $crop_h ) / 2 ); | |
172 | } | |
173 | } else { | |
174 | // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box | |
175 | $crop_w = $orig_w; | |
176 | $crop_h = $orig_h; | |
177 | ||
178 | $s_x = 0; | |
179 | $s_y = 0; | |
180 | ||
181 | list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h ); | |
182 | } | |
183 | ||
184 | // if the resulting image would be the same size or larger we don't want to resize it | |
185 | if ( $new_w >= $orig_w && $new_h >= $orig_h ) | |
186 | return false; | |
187 | ||
188 | // the return array matches the parameters to imagecopyresampled() | |
189 | // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h | |
190 | return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h ); | |
191 | ||
192 | } | |
193 | ||
194 | ||
195 | /** | |
196 | * Scale down an image to fit a particular size and save a new copy of the image. | |
197 | * | |
198 | * The PNG transparency will be preserved using the function, as well as the | |
199 | * image type. If the file going in is PNG, then the resized image is going to | |
200 | * be PNG. The only supported image types are PNG, GIF, and JPEG. | |
201 | * | |
202 | * Some functionality requires API to exist, so some PHP version may lose out | |
203 | * support. This is not the fault of WordPress (where functionality is | |
204 | * downgraded, not actual defects), but of your PHP version. | |
205 | * | |
206 | * @since 2.5.0 | |
207 | * | |
208 | * @param string $file Image file path. | |
209 | * @param int $max_w Maximum width to resize to. | |
210 | * @param int $max_h Maximum height to resize to. | |
211 | * @param bool $crop Optional. Whether to crop image or resize. | |
212 | * @param string $suffix Optional. File Suffix. | |
213 | * @param string $dest_path Optional. New image file path. | |
214 | * @param int $jpeg_quality Optional, default is 90. Image quality percentage. | |
215 | * @return mixed WP_Error on failure. String with new destination path. | |
216 | */ | |
217 | function bt_image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) { | |
218 | ||
219 | $image = wp_load_image( $file ); | |
220 | if ( !is_resource( $image ) ) | |
221 | return new WP_Error( 'error_loading_image', $image, $file ); | |
222 | ||
223 | $size = @getimagesize( $file ); | |
224 | if ( !$size ) | |
225 | return new WP_Error('invalid_image', __('Could not read image size'), $file); | |
226 | list($orig_w, $orig_h, $orig_type) = $size; | |
227 | ||
228 | // Rotate if EXIF 'Orientation' is set | |
229 | // This code is from the reverted patch at | |
230 | // http://core.trac.wordpress.org/changeset/11746/trunk/wp-includes/media.php | |
231 | $rotate = false; | |
232 | if ( is_callable( 'exif_read_data' ) && in_array( $orig_type, apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ) ) ) { | |
233 | $exif = @exif_read_data( $file, null, true ); | |
234 | if ( $exif && isset( $exif['IFD0'] ) && is_array( $exif['IFD0'] ) && isset( $exif['IFD0']['Orientation'] ) ) { | |
235 | if ( 6 == $exif['IFD0']['Orientation'] ) | |
236 | $rotate = 90; | |
237 | elseif ( 8 == $exif['IFD0']['Orientation'] ) | |
238 | $rotate = 270; | |
239 | } | |
240 | } | |
241 | ||
242 | if ( $rotate ) | |
243 | list($max_h,$max_w) = array($max_w,$max_h); | |
244 | ||
245 | $dims = bt_image_resize_dimensions($orig_w, $orig_h, $max_w, $max_h, $crop); | |
246 | if ( !$dims ) | |
247 | return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') ); | |
248 | list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims; | |
249 | ||
250 | $newimage = wp_imagecreatetruecolor( $dst_w, $dst_h ); | |
251 | ||
252 | if ( $rotate ) | |
253 | list($src_y,$src_x) = array($src_x,$src_y); | |
254 | ||
255 | imagecopyresampled( $newimage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); | |
256 | ||
257 | // convert from full colors to index colors, like original PNG. | |
258 | if ( IMAGETYPE_PNG == $orig_type && function_exists('imageistruecolor') && !imageistruecolor( $image ) ) | |
259 | imagetruecolortopalette( $newimage, false, imagecolorstotal( $image ) ); | |
260 | ||
261 | // we don't need the original in memory anymore | |
262 | imagedestroy( $image ); | |
263 | ||
264 | // $suffix will be appended to the destination filename, just before the extension | |
265 | if ( !$suffix ) { | |
266 | if ( $rotate ) | |
267 | $suffix = "{$dst_h}x{$dst_w}"; | |
268 | else | |
269 | $suffix = "{$dst_w}x{$dst_h}"; | |
270 | } | |
271 | ||
272 | $info = pathinfo($file); | |
273 | $dir = $info['dirname']; | |
274 | $ext = $info['extension']; | |
275 | $name = wp_basename($file, ".$ext"); | |
276 | ||
277 | if ( !is_null($dest_path) and $_dest_path = realpath($dest_path) ) | |
278 | $dir = $_dest_path; | |
279 | $destfilename = "{$dir}/{$name}-{$suffix}.{$ext}"; | |
280 | ||
281 | if ( IMAGETYPE_GIF == $orig_type ) { | |
282 | if ( !imagegif( $newimage, $destfilename ) ) | |
283 | return new WP_Error('resize_path_invalid', __( 'Resize path invalid' )); | |
284 | } elseif ( IMAGETYPE_PNG == $orig_type ) { | |
285 | if ( !imagepng( $newimage, $destfilename ) ) | |
286 | return new WP_Error('resize_path_invalid', __( 'Resize path invalid' )); | |
287 | } else { | |
288 | if ( $rotate ) { | |
289 | $newimage = _rotate_image_resource( $newimage, 360 - $rotate ); | |
290 | } | |
291 | ||
292 | // all other formats are converted to jpg | |
293 | $destfilename = "{$dir}/{$name}-{$suffix}.jpg"; | |
294 | $return = imagejpeg( $newimage, $destfilename, apply_filters( 'jpeg_quality', $jpeg_quality, 'image_resize' ) ); | |
295 | if ( !$return ) | |
296 | return new WP_Error('resize_path_invalid', __( 'Resize path invalid' )); | |
297 | } | |
298 | ||
299 | imagedestroy( $newimage ); | |
300 | ||
301 | // Set correct file permissions | |
302 | $stat = stat( dirname( $destfilename )); | |
303 | $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits | |
304 | @ chmod( $destfilename, $perms ); | |
305 | ||
306 | return $destfilename; | |
307 | } |