1 | <?php |
2 | /** |
3 | * WordPress API for media display. |
4 | * |
5 | * @package WordPress |
6 | */ |
7 | |
8 | /** |
9 | * Scale down the default size of an image. |
10 | * |
11 | * This is so that the image is a better fit for the editor and theme. |
12 | * |
13 | * The $size parameter accepts either an array or a string. The supported string |
14 | * values are 'thumb' or 'thumbnail' for the given thumbnail size or defaults at |
15 | * 128 width and 96 height in pixels. Also supported for the string value is |
16 | * 'medium' and 'full'. The 'full' isn't actually supported, but any value other |
17 | * than the supported will result in the content_width size or 500 if that is |
18 | * not set. |
19 | * |
20 | * Finally, there is a filter named, 'editor_max_image_size' that will be called |
21 | * on the calculated array for width and height, respectively. The second |
22 | * parameter will be the value that was in the $size parameter. The returned |
23 | * type for the hook is an array with the width as the first element and the |
24 | * height as the second element. |
25 | * |
26 | * @since 2.5.0 |
27 | * @uses wp_constrain_dimensions() This function passes the widths and the heights. |
28 | * |
29 | * @param int $width Width of the image |
30 | * @param int $height Height of the image |
31 | * @param string|array $size Size of what the result image should be. |
32 | * @return array Width and height of what the result image should resize to. |
33 | */ |
34 | function image_constrain_size_for_editor($width, $height, $size = 'medium') { |
35 | global $content_width, $_wp_additional_image_sizes; |
36 | |
37 | if ( is_array($size) ) { |
38 | $max_width = $size[0]; |
39 | $max_height = $size[1]; |
40 | } |
41 | elseif ( $size == 'thumb' || $size == 'thumbnail' ) { |
42 | $max_width = intval(get_option('thumbnail_size_w')); |
43 | $max_height = intval(get_option('thumbnail_size_h')); |
44 | // last chance thumbnail size defaults |
45 | if ( !$max_width && !$max_height ) { |
46 | $max_width = 128; |
47 | $max_height = 96; |
48 | } |
49 | } |
50 | elseif ( $size == 'medium' ) { |
51 | $max_width = intval(get_option('medium_size_w')); |
52 | $max_height = intval(get_option('medium_size_h')); |
53 | // if no width is set, default to the theme content width if available |
54 | } |
55 | elseif ( $size == 'large' ) { |
56 | // we're inserting a large size image into the editor. if it's a really |
57 | // big image we'll scale it down to fit reasonably within the editor |
58 | // itself, and within the theme's content width if it's known. the user |
59 | // can resize it in the editor if they wish. |
60 | $max_width = intval(get_option('large_size_w')); |
61 | $max_height = intval(get_option('large_size_h')); |
62 | if ( intval($content_width) > 0 ) |
63 | $max_width = min( intval($content_width), $max_width ); |
64 | } elseif ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) && in_array( $size, array_keys( $_wp_additional_image_sizes ) ) ) { |
65 | $max_width = intval( $_wp_additional_image_sizes[$size]['width'] ); |
66 | $max_height = intval( $_wp_additional_image_sizes[$size]['height'] ); |
67 | if ( intval($content_width) > 0 && is_admin() ) // Only in admin. Assume that theme authors know what they're doing. |
68 | $max_width = min( intval($content_width), $max_width ); |
69 | } |
70 | // $size == 'full' has no constraint |
71 | else { |
72 | $max_width = $width; |
73 | $max_height = $height; |
74 | } |
75 | |
76 | list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size ); |
77 | |
78 | return wp_constrain_dimensions( $width, $height, $max_width, $max_height ); |
79 | } |
80 | |
81 | /** |
82 | * Retrieve width and height attributes using given width and height values. |
83 | * |
84 | * Both attributes are required in the sense that both parameters must have a |
85 | * value, but are optional in that if you set them to false or null, then they |
86 | * will not be added to the returned string. |
87 | * |
88 | * You can set the value using a string, but it will only take numeric values. |
89 | * If you wish to put 'px' after the numbers, then it will be stripped out of |
90 | * the return. |
91 | * |
92 | * @since 2.5.0 |
93 | * |
94 | * @param int|string $width Optional. Width attribute value. |
95 | * @param int|string $height Optional. Height attribute value. |
96 | * @return string HTML attributes for width and, or height. |
97 | */ |
98 | function image_hwstring($width, $height) { |
99 | $out = ''; |
100 | if ($width) |
101 | $out .= 'width="'.intval($width).'" '; |
102 | if ($height) |
103 | $out .= 'height="'.intval($height).'" '; |
104 | return $out; |
105 | } |
106 | |
107 | /** |
108 | * Scale an image to fit a particular size (such as 'thumb' or 'medium'). |
109 | * |
110 | * Array with image url, width, height, and whether is intermediate size, in |
111 | * that order is returned on success is returned. $is_intermediate is true if |
112 | * $url is a resized image, false if it is the original. |
113 | * |
114 | * The URL might be the original image, or it might be a resized version. This |
115 | * function won't create a new resized copy, it will just return an already |
116 | * resized one if it exists. |
117 | * |
118 | * A plugin may use the 'image_downsize' filter to hook into and offer image |
119 | * resizing services for images. The hook must return an array with the same |
120 | * elements that are returned in the function. The first element being the URL |
121 | * to the new image that was resized. |
122 | * |
123 | * @since 2.5.0 |
124 | * @uses apply_filters() Calls 'image_downsize' on $id and $size to provide |
125 | * resize services. |
126 | * |
127 | * @param int $id Attachment ID for image. |
128 | * @param string $size Optional, default is 'medium'. Size of image, can be 'thumbnail'. |
129 | * @return bool|array False on failure, array on success. |
130 | */ |
131 | function image_downsize($id, $size = 'medium') { |
132 | |
133 | if ( !wp_attachment_is_image($id) ) |
134 | return false; |
135 | |
136 | $img_url = wp_get_attachment_url($id); |
137 | $meta = wp_get_attachment_metadata($id); |
138 | $width = $height = 0; |
139 | $is_intermediate = false; |
140 | |
141 | // plugins can use this to provide resize services |
142 | if ( $out = apply_filters('image_downsize', false, $id, $size) ) |
143 | return $out; |
144 | |
145 | // try for a new style intermediate size |
146 | if ( $intermediate = image_get_intermediate_size($id, $size) ) { |
147 | $img_url = str_replace(basename($img_url), $intermediate['file'], $img_url); | //Arbitrary file disclosing
|
148 | $width = $intermediate['width']; |
149 | $height = $intermediate['height']; |
150 | $is_intermediate = true; |
151 | } |
152 | elseif ( $size == 'thumbnail' ) { |
153 | // fall back to the old thumbnail |
154 | if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) { |
155 | $img_url = str_replace(basename($img_url), basename($thumb_file), $img_url); | //Arbitrary file disclosing
|
156 | $width = $info[0]; |
157 | $height = $info[1]; |
158 | $is_intermediate = true; |
159 | } |
160 | } |
161 | if ( !$width && !$height && isset($meta['width'], $meta['height']) ) { |
162 | // any other type: use the real image |
163 | $width = $meta['width']; |
164 | $height = $meta['height']; |
165 | } |
166 | |
167 | if ( $img_url) { |
168 | // we have the actual image size, but might need to further constrain it if content_width is narrower |
169 | list( $width, $height ) = image_constrain_size_for_editor( $width, $height, $size ); |
170 | |
171 | return array( $img_url, $width, $height, $is_intermediate ); |
172 | } |
173 | return false; |
174 | |
175 | } |
176 | |
177 | /** |
178 | * Registers a new image size |
179 | */ |
180 | function add_image_size( $name, $width = 0, $height = 0, $crop = FALSE ) { |
181 | global $_wp_additional_image_sizes; |
182 | $_wp_additional_image_sizes[$name] = array( 'width' => absint( $width ), 'height' => absint( $height ), 'crop' => !!$crop ); |
183 | } |
184 | |
185 | /** |
186 | * Registers an image size for the post thumbnail |
187 | */ |
188 | function set_post_thumbnail_size( $width = 0, $height = 0, $crop = FALSE ) { |
189 | add_image_size( 'post-thumbnail', $width, $height, $crop ); |
190 | } |
191 | |
192 | /** |
193 | * An <img src /> tag for an image attachment, scaling it down if requested. |
194 | * |
195 | * The filter 'get_image_tag_class' allows for changing the class name for the |
196 | * image without having to use regular expressions on the HTML content. The |
197 | * parameters are: what WordPress will use for the class, the Attachment ID, |
198 | * image align value, and the size the image should be. |
199 | * |
200 | * The second filter 'get_image_tag' has the HTML content, which can then be |
201 | * further manipulated by a plugin to change all attribute values and even HTML |
202 | * content. |
203 | * |
204 | * @since 2.5.0 |
205 | * |
206 | * @uses apply_filters() The 'get_image_tag_class' filter is the IMG element |
207 | * class attribute. |
208 | * @uses apply_filters() The 'get_image_tag' filter is the full IMG element with |
209 | * all attributes. |
210 | * |
211 | * @param int $id Attachment ID. |
212 | * @param string $alt Image Description for the alt attribute. |
213 | * @param string $title Image Description for the title attribute. |
214 | * @param string $align Part of the class name for aligning the image. |
215 | * @param string $size Optional. Default is 'medium'. |
216 | * @return string HTML IMG element for given image attachment |
217 | */ |
218 | function get_image_tag($id, $alt, $title, $align, $size='medium') { |
219 | |
220 | list( $img_src, $width, $height ) = image_downsize($id, $size); |
221 | $hwstring = image_hwstring($width, $height); |
222 | |
223 | $class = 'align' . esc_attr($align) .' size-' . esc_attr($size) . ' wp-image-' . $id; |
224 | $class = apply_filters('get_image_tag_class', $class, $id, $align, $size); |
225 | |
226 | $html = '<img src="' . esc_attr($img_src) . '" alt="' . esc_attr($alt) . '" title="' . esc_attr($title).'" '.$hwstring.'class="'.$class.'" />'; |
227 | |
228 | $html = apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size ); |
229 | |
230 | return $html; |
231 | } |
232 | |
233 | /** |
234 | * Load an image from a string, if PHP supports it. |
235 | * |
236 | * @since 2.1.0 |
237 | * |
238 | * @param string $file Filename of the image to load. |
239 | * @return resource The resulting image resource on success, Error string on failure. |
240 | */ |
241 | function wp_load_image( $file ) { |
242 | if ( is_numeric( $file ) ) |
243 | $file = get_attached_file( $file ); | //Arbitrary file disclosing
|
244 | |
245 | if ( ! file_exists( $file ) ) |
246 | return sprintf(__('File “%s” doesn’t exist?'), $file); |
247 | |
248 | if ( ! function_exists('imagecreatefromstring') ) |
249 | return __('The GD image library is not installed.'); |
250 | |
251 | // Set artificially high because GD uses uncompressed images in memory |
252 | @ini_set('memory_limit', '256M'); |
253 | $image = imagecreatefromstring( file_get_contents( $file ) ); | //Arbitrary file disclosing
|
254 | |
255 | if ( !is_resource( $image ) ) |
256 | return sprintf(__('File “%s” is not an image.'), $file); |
257 | |
258 | return $image; |
259 | } |
260 | |
261 | /** |
262 | * Calculates the new dimentions for a downsampled image. |
263 | * |
264 | * If either width or height are empty, no constraint is applied on |
265 | * that dimension. |
266 | * |
267 | * @since 2.5.0 |
268 | * |
269 | * @param int $current_width Current width of the image. |
270 | * @param int $current_height Current height of the image. |
271 | * @param int $max_width Optional. Maximum wanted width. |
272 | * @param int $max_height Optional. Maximum wanted height. |
273 | * @return array First item is the width, the second item is the height. |
274 | */ |
275 | function wp_constrain_dimensions( $current_width, $current_height, $max_width=0, $max_height=0 ) { |
276 | if ( !$max_width and !$max_height ) |
277 | return array( $current_width, $current_height ); |
278 | |
279 | $width_ratio = $height_ratio = 1.0; |
280 | $did_width = $did_height = false; |
281 | |
282 | if ( $max_width > 0 && $current_width > 0 && $current_width > $max_width ) { |
283 | $width_ratio = $max_width / $current_width; |
284 | $did_width = true; |
285 | } |
286 | |
287 | if ( $max_height > 0 && $current_height > 0 && $current_height > $max_height ) { |
288 | $height_ratio = $max_height / $current_height; |
289 | $did_height = true; |
290 | } |
291 | |
292 | // Calculate the larger/smaller ratios |
293 | $smaller_ratio = min( $width_ratio, $height_ratio ); |
294 | $larger_ratio = max( $width_ratio, $height_ratio ); |
295 | |
296 | if ( intval( $current_width * $larger_ratio ) > $max_width || intval( $current_height * $larger_ratio ) > $max_height ) |
297 | // The larger ratio is too big. It would result in an overflow. |
298 | $ratio = $smaller_ratio; |
299 | else |
300 | // The larger ratio fits, and is likely to be a more "snug" fit. |
301 | $ratio = $larger_ratio; |
302 | |
303 | $w = intval( $current_width * $ratio ); |
304 | $h = intval( $current_height * $ratio ); |
305 | |
306 | // Sometimes, due to rounding, we'll end up with a result like this: 465x700 in a 177x177 box is 117x176... a pixel short |
307 | // We also have issues with recursive calls resulting in an ever-changing result. Contraining to the result of a constraint should yield the original result. |
308 | // Thus we look for dimensions that are one pixel shy of the max value and bump them up |
309 | if ( $did_width && $w == $max_width - 1 ) |
310 | $w = $max_width; // Round it up |
311 | if ( $did_height && $h == $max_height - 1 ) |
312 | $h = $max_height; // Round it up |
313 | |
314 | return array( $w, $h ); |
315 | } |
316 | |
317 | /** |
318 | * Retrieve calculated resized dimensions for use in imagecopyresampled(). |
319 | * |
320 | * Calculate dimensions and coordinates for a resized image that fits within a |
321 | * specified width and height. If $crop is true, the largest matching central |
322 | * portion of the image will be cropped out and resized to the required size. |
323 | * |
324 | * @since 2.5.0 |
325 | * |
326 | * @param int $orig_w Original width. |
327 | * @param int $orig_h Original height. |
328 | * @param int $dest_w New width. |
329 | * @param int $dest_h New height. |
330 | * @param bool $crop Optional, default is false. Whether to crop image or resize. |
331 | * @return bool|array False, on failure. Returned array matches parameters for imagecopyresampled() PHP function. |
332 | */ |
333 | function image_resize_dimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop = false) { |
334 | |
335 | if ($orig_w <= 0 || $orig_h <= 0) |
336 | return false; |
337 | // at least one of dest_w or dest_h must be specific |
338 | if ($dest_w <= 0 && $dest_h <= 0) |
339 | return false; |
340 | |
341 | if ( $crop ) { |
342 | // crop the largest possible portion of the original image that we can size to $dest_w x $dest_h |
343 | $aspect_ratio = $orig_w / $orig_h; |
344 | $new_w = min($dest_w, $orig_w); |
345 | $new_h = min($dest_h, $orig_h); |
346 | |
347 | if ( !$new_w ) { |
348 | $new_w = intval($new_h * $aspect_ratio); |
349 | } |
350 | |
351 | if ( !$new_h ) { |
352 | $new_h = intval($new_w / $aspect_ratio); |
353 | } |
354 | |
355 | $size_ratio = max($new_w / $orig_w, $new_h / $orig_h); |
356 | |
357 | $crop_w = round($new_w / $size_ratio); |
358 | $crop_h = round($new_h / $size_ratio); |
359 | |
360 | $s_x = floor( ($orig_w - $crop_w) / 2 ); |
361 | $s_y = floor( ($orig_h - $crop_h) / 2 ); |
362 | } else { |
363 | // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box |
364 | $crop_w = $orig_w; |
365 | $crop_h = $orig_h; |
366 | |
367 | $s_x = 0; |
368 | $s_y = 0; |
369 | |
370 | list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h ); |
371 | } |
372 | |
373 | // if the resulting image would be the same size or larger we don't want to resize it |
374 | if ( $new_w >= $orig_w && $new_h >= $orig_h ) |
375 | return false; |
376 | |
377 | // the return array matches the parameters to imagecopyresampled() |
378 | // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h |
379 | return array( 0, 0, (int) $s_x, (int) $s_y, (int) $new_w, (int) $new_h, (int) $crop_w, (int) $crop_h ); |
380 | |
381 | } |
382 | |
383 | /** |
384 | * Scale down an image to fit a particular size and save a new copy of the image. |
385 | * |
386 | * The PNG transparency will be preserved using the function, as well as the |
387 | * image type. If the file going in is PNG, then the resized image is going to |
388 | * be PNG. The only supported image types are PNG, GIF, and JPEG. |
389 | * |
390 | * Some functionality requires API to exist, so some PHP version may lose out |
391 | * support. This is not the fault of WordPress (where functionality is |
392 | * downgraded, not actual defects), but of your PHP version. |
393 | * |
394 | * @since 2.5.0 |
395 | * |
396 | * @param string $file Image file path. |
397 | * @param int $max_w Maximum width to resize to. |
398 | * @param int $max_h Maximum height to resize to. |
399 | * @param bool $crop Optional. Whether to crop image or resize. |
400 | * @param string $suffix Optional. File Suffix. |
401 | * @param string $dest_path Optional. New image file path. |
402 | * @param int $jpeg_quality Optional, default is 90. Image quality percentage. |
403 | * @return mixed WP_Error on failure. String with new destination path. |
404 | */ |
405 | function image_resize( $file, $max_w, $max_h, $crop = false, $suffix = null, $dest_path = null, $jpeg_quality = 90 ) { |
406 | |
407 | $image = wp_load_image( $file ); |
408 | if ( !is_resource( $image ) ) |
409 | return new WP_Error( 'error_loading_image', $image, $file ); |
410 | |
411 | $size = @getimagesize( $file ); |
412 | if ( !$size ) |
413 | return new WP_Error('invalid_image', __('Could not read image size'), $file); |
414 | list($orig_w, $orig_h, $orig_type) = $size; |
415 | |
416 | $dims = image_resize_dimensions($orig_w, $orig_h, $max_w, $max_h, $crop); |
417 | if ( !$dims ) |
418 | return new WP_Error( 'error_getting_dimensions', __('Could not calculate resized image dimensions') ); |
419 | list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims; |
420 | |
421 | $newimage = wp_imagecreatetruecolor( $dst_w, $dst_h ); |
422 | |
423 | imagecopyresampled( $newimage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h); |
424 | |
425 | // convert from full colors to index colors, like original PNG. |
426 | if ( IMAGETYPE_PNG == $orig_type && function_exists('imageistruecolor') && !imageistruecolor( $image ) ) |
427 | imagetruecolortopalette( $newimage, false, imagecolorstotal( $image ) ); |
428 | |
429 | // we don't need the original in memory anymore |
430 | imagedestroy( $image ); |
431 | |
432 | // $suffix will be appended to the destination filename, just before the extension |
433 | if ( !$suffix ) |
434 | $suffix = "{$dst_w}x{$dst_h}"; |
435 | |
436 | $info = pathinfo($file); |
437 | $dir = $info['dirname']; |
438 | $ext = $info['extension']; |
439 | $name = basename($file, ".{$ext}"); | //Arbitrary file disclosing
|
440 | if ( !is_null($dest_path) and $_dest_path = realpath($dest_path) ) |
441 | $dir = $_dest_path; |
442 | $destfilename = "{$dir}/{$name}-{$suffix}.{$ext}"; |
443 | |
444 | if ( IMAGETYPE_GIF == $orig_type ) { |
445 | if ( !imagegif( $newimage, $destfilename ) ) |
446 | return new WP_Error('resize_path_invalid', __( 'Resize path invalid' )); |
447 | } elseif ( IMAGETYPE_PNG == $orig_type ) { |
448 | if ( !imagepng( $newimage, $destfilename ) ) |
449 | return new WP_Error('resize_path_invalid', __( 'Resize path invalid' )); |
450 | } else { |
451 | // all other formats are converted to jpg |
452 | $destfilename = "{$dir}/{$name}-{$suffix}.jpg"; |
453 | if ( !imagejpeg( $newimage, $destfilename, apply_filters( 'jpeg_quality', $jpeg_quality, 'image_resize' ) ) ) |
454 | return new WP_Error('resize_path_invalid', __( 'Resize path invalid' )); |
455 | } |
456 | |
457 | imagedestroy( $newimage ); |
458 | |
459 | // Set correct file permissions |
460 | $stat = stat( dirname( $destfilename )); |
461 | $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits |
462 | @ chmod( $destfilename, $perms ); | //Arbitrary file manipulations
|
463 | |
464 | return $destfilename; |
465 | } |
466 | |
467 | /** |
468 | * Resize an image to make a thumbnail or intermediate size. |
469 | * |
470 | * The returned array has the file size, the image width, and image height. The |
471 | * filter 'image_make_intermediate_size' can be used to hook in and change the |
472 | * values of the returned array. The only parameter is the resized file path. |
473 | * |
474 | * @since 2.5.0 |
475 | * |
476 | * @param string $file File path. |
477 | * @param int $width Image width. |
478 | * @param int $height Image height. |
479 | * @param bool $crop Optional, default is false. Whether to crop image to specified height and width or resize. |
480 | * @return bool|array False, if no image was created. Metadata array on success. |
481 | */ |
482 | function image_make_intermediate_size($file, $width, $height, $crop=false) { |
483 | if ( $width || $height ) { |
484 | $resized_file = image_resize($file, $width, $height, $crop); | //Arbitrary file disclosing
|
485 | if ( !is_wp_error($resized_file) && $resized_file && $info = getimagesize($resized_file) ) { |
486 | $resized_file = apply_filters('image_make_intermediate_size', $resized_file); |
487 | return array( |
488 | 'file' => basename( $resized_file ), |
489 | 'width' => $info[0], |
490 | 'height' => $info[1], |
491 | ); |
492 | } |
493 | } |
494 | return false; |
495 | } |
496 | |
497 | /** |
498 | * Retrieve the image's intermediate size (resized) path, width, and height. |
499 | * |
500 | * The $size parameter can be an array with the width and height respectively. |
501 | * If the size matches the 'sizes' metadata array for width and height, then it |
502 | * will be used. If there is no direct match, then the nearest image size larger |
503 | * than the specified size will be used. If nothing is found, then the function |
504 | * will break out and return false. |
505 | * |
506 | * The metadata 'sizes' is used for compatible sizes that can be used for the |
507 | * parameter $size value. |
508 | * |
509 | * The url path will be given, when the $size parameter is a string. |
510 | * |
511 | * If you are passing an array for the $size, you should consider using |
512 | * add_image_size() so that a cropped version is generated. It's much more |
513 | * efficient than having to find the closest-sized image and then having the |
514 | * browser scale down the image. |
515 | * |
516 | * @since 2.5.0 |
517 | * @see add_image_size() |
518 | * |
519 | * @param int $post_id Attachment ID for image. |
520 | * @param array|string $size Optional, default is 'thumbnail'. Size of image, either array or string. |
521 | * @return bool|array False on failure or array of file path, width, and height on success. |
522 | */ |
523 | function image_get_intermediate_size($post_id, $size='thumbnail') { |
524 | if ( !is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) ) |
525 | return false; |
526 | |
527 | // get the best one for a specified set of dimensions |
528 | if ( is_array($size) && !empty($imagedata['sizes']) ) { |
529 | foreach ( $imagedata['sizes'] as $_size => $data ) { |
530 | // already cropped to width or height; so use this size |
531 | if ( ( $data['width'] == $size[0] && $data['height'] <= $size[1] ) || ( $data['height'] == $size[1] && $data['width'] <= $size[0] ) ) { |
532 | $file = $data['file']; | //Arbitrary file disclosing
|
533 | list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size ); |
534 | return compact( 'file', 'width', 'height' ); |
535 | } |
536 | // add to lookup table: area => size |
537 | $areas[$data['width'] * $data['height']] = $_size; |
538 | } |
539 | if ( !$size || !empty($areas) ) { |
540 | // find for the smallest image not smaller than the desired size |
541 | ksort($areas); |
542 | foreach ( $areas as $_size ) { |
543 | $data = $imagedata['sizes'][$_size]; |
544 | if ( $data['width'] >= $size[0] || $data['height'] >= $size[1] ) { |
545 | // Skip images with unexpectedly divergent aspect ratios (crops) |
546 | // First, we calculate what size the original image would be if constrained to a box the size of the current image in the loop |
547 | $maybe_cropped = image_resize_dimensions($imagedata['width'], $imagedata['height'], $data['width'], $data['height'], false ); |
548 | // If the size doesn't match within one pixel, then it is of a different aspect ratio, so we skip it, unless it's the thumbnail size |
549 | if ( 'thumbnail' != $_size && ( !$maybe_cropped || ( $maybe_cropped[4] != $data['width'] && $maybe_cropped[4] + 1 != $data['width'] ) || ( $maybe_cropped[5] != $data['height'] && $maybe_cropped[5] + 1 != $data['height'] ) ) ) |
550 | continue; |
551 | // If we're still here, then we're going to use this size |
552 | $file = $data['file']; | //Arbitrary file disclosing
|
553 | list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size ); |
554 | return compact( 'file', 'width', 'height' ); |
555 | } |
556 | } |
557 | } |
558 | } |
559 | |
560 | if ( is_array($size) || empty($size) || empty($imagedata['sizes'][$size]) ) |
561 | return false; |
562 | |
563 | $data = $imagedata['sizes'][$size]; |
564 | // include the full filesystem path of the intermediate file |
565 | if ( empty($data['path']) && !empty($data['file']) ) { |
566 | $file_url = wp_get_attachment_url($post_id); |
567 | $data['path'] = path_join( dirname($imagedata['file']), $data['file'] ); | //Arbitrary file disclosing
|
568 | $data['url'] = path_join( dirname($file_url), $data['file'] ); |
569 | } |
570 | return $data; |
571 | } |
572 | |
573 | /** |
574 | * Get the available image sizes |
575 | * @since 3.0.0 |
576 | * @return array Returns a filtered array of image size strings |
577 | */ |
578 | function get_intermediate_image_sizes() { |
579 | global $_wp_additional_image_sizes; |
580 | $image_sizes = array('thumbnail', 'medium', 'large'); // Standard sizes |
581 | if ( isset( $_wp_additional_image_sizes ) && count( $_wp_additional_image_sizes ) ) |
582 | $image_sizes = array_merge( $image_sizes, array_keys( $_wp_additional_image_sizes ) ); |
583 | |
584 | return apply_filters( 'intermediate_image_sizes', $image_sizes ); |
585 | } |
586 | |
587 | /** |
588 | * Retrieve an image to represent an attachment. |
589 | * |
590 | * A mime icon for files, thumbnail or intermediate size for images. |
591 | * |
592 | * @since 2.5.0 |
593 | * |
594 | * @param int $attachment_id Image attachment ID. |
595 | * @param string $size Optional, default is 'thumbnail'. |
596 | * @param bool $icon Optional, default is false. Whether it is an icon. |
597 | * @return bool|array Returns an array (url, width, height), or false, if no image is available. |
598 | */ |
599 | function wp_get_attachment_image_src($attachment_id, $size='thumbnail', $icon = false) { |
600 | |
601 | // get a thumbnail or intermediate image if there is one |
602 | if ( $image = image_downsize($attachment_id, $size) ) |
603 | return $image; |
604 | |
605 | $src = false; |
606 | |
607 | if ( $icon && $src = wp_mime_type_icon($attachment_id) ) { |
608 | $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' ); |
609 | $src_file = $icon_dir . '/' . basename($src); | //Arbitrary file disclosing
|
610 | @list($width, $height) = getimagesize($src_file); |
611 | } |
612 | if ( $src && $width && $height ) |
613 | return array( $src, $width, $height ); |
614 | return false; |
615 | } |
616 | |
617 | /** |
618 | * Get an HTML img element representing an image attachment |
619 | * |
620 | * While $size will accept an array, it is better to register a size with |
621 | * add_image_size() so that a cropped version is generated. It's much more |
622 | * efficient than having to find the closest-sized image and then having the |
623 | * browser scale down the image. |
624 | * |
625 | * @see add_image_size() |
626 | * @uses apply_filters() Calls 'wp_get_attachment_image_attributes' hook on attributes array |
627 | * @uses wp_get_attachment_image_src() Gets attachment file URL and dimensions |
628 | * @since 2.5.0 |
629 | * |
630 | * @param int $attachment_id Image attachment ID. |
631 | * @param string $size Optional, default is 'thumbnail'. |
632 | * @param bool $icon Optional, default is false. Whether it is an icon. |
633 | * @return string HTML img element or empty string on failure. |
634 | */ |
635 | function wp_get_attachment_image($attachment_id, $size = 'thumbnail', $icon = false, $attr = '') { |
636 | |
637 | $html = ''; |
638 | $image = wp_get_attachment_image_src($attachment_id, $size, $icon); |
639 | if ( $image ) { |
640 | list($src, $width, $height) = $image; |
641 | $hwstring = image_hwstring($width, $height); |
642 | if ( is_array($size) ) |
643 | $size = join('x', $size); |
644 | $attachment =& get_post($attachment_id); |
645 | $default_attr = array( |
646 | 'src' => $src, |
647 | 'class' => "attachment-$size", |
648 | 'alt' => trim(strip_tags( get_post_meta($attachment_id, '_wp_attachment_image_alt', true) )), // Use Alt field first |
649 | 'title' => trim(strip_tags( $attachment->post_title )), |
650 | ); |
651 | if ( empty($default_attr['alt']) ) |
652 | $default_attr['alt'] = trim(strip_tags( $attachment->post_excerpt )); // If not, Use the Caption |
653 | if ( empty($default_attr['alt']) ) |
654 | $default_attr['alt'] = trim(strip_tags( $attachment->post_title )); // Finally, use the title |
655 | |
656 | $attr = wp_parse_args($attr, $default_attr); |
657 | $attr = apply_filters( 'wp_get_attachment_image_attributes', $attr, $attachment ); |
658 | $attr = array_map( 'esc_attr', $attr ); |
659 | $html = rtrim("<img $hwstring"); |
660 | foreach ( $attr as $name => $value ) { |
661 | $html .= " $name=" . '"' . $value . '"'; |
662 | } |
663 | $html .= ' />'; |
664 | } |
665 | |
666 | return $html; |
667 | } |
668 | |
669 | /** |
670 | * Adds a 'wp-post-image' class to post thumbnail thumbnails |
671 | * Uses the begin_fetch_post_thumbnail_html and end_fetch_post_thumbnail_html action hooks to |
672 | * dynamically add/remove itself so as to only filter post thumbnail thumbnails |
673 | * |
674 | * @since 2.9.0 |
675 | * @param array $attr Attributes including src, class, alt, title |
676 | * @return array |
677 | */ |
678 | function _wp_post_thumbnail_class_filter( $attr ) { |
679 | $attr['class'] .= ' wp-post-image'; |
680 | return $attr; |
681 | } |
682 | |
683 | /** |
684 | * Adds _wp_post_thumbnail_class_filter to the wp_get_attachment_image_attributes filter |
685 | * |
686 | * @since 2.9.0 |
687 | */ |
688 | function _wp_post_thumbnail_class_filter_add( $attr ) { |
689 | add_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' ); |
690 | } |
691 | |
692 | /** |
693 | * Removes _wp_post_thumbnail_class_filter from the wp_get_attachment_image_attributes filter |
694 | * |
695 | * @since 2.9.0 |
696 | */ |
697 | function _wp_post_thumbnail_class_filter_remove( $attr ) { |
698 | remove_filter( 'wp_get_attachment_image_attributes', '_wp_post_thumbnail_class_filter' ); |
699 | } |
700 | |
701 | add_shortcode('wp_caption', 'img_caption_shortcode'); |
702 | add_shortcode('caption', 'img_caption_shortcode'); |
703 | |
704 | /** |
705 | * The Caption shortcode. |
706 | * |
707 | * Allows a plugin to replace the content that would otherwise be returned. The |
708 | * filter is 'img_caption_shortcode' and passes an empty string, the attr |
709 | * parameter and the content parameter values. |
710 | * |
711 | * The supported attributes for the shortcode are 'id', 'align', 'width', and |
712 | * 'caption'. |
713 | * |
714 | * @since 2.6.0 |
715 | * |
716 | * @param array $attr Attributes attributed to the shortcode. |
717 | * @param string $content Optional. Shortcode content. |
718 | * @return string |
719 | */ |
720 | function img_caption_shortcode($attr, $content = null) { |
721 | |
722 | // Allow plugins/themes to override the default caption template. |
723 | $output = apply_filters('img_caption_shortcode', '', $attr, $content); |
724 | if ( $output != '' ) |
725 | return $output; |
726 | |
727 | extract(shortcode_atts(array( |
728 | 'id' => '', |
729 | 'align' => 'alignnone', |
730 | 'width' => '', |
731 | 'caption' => '' |
732 | ), $attr)); |
733 | |
734 | if ( 1 > (int) $width || empty($caption) ) |
735 | return $content; |
736 | |
737 | if ( $id ) $id = 'id="' . esc_attr($id) . '" '; |
738 | |
739 | return '<div ' . $id . 'class="wp-caption ' . esc_attr($align) . '" style="width: ' . (10 + (int) $width) . 'px">' |
740 | . do_shortcode( $content ) . '<p class="wp-caption-text">' . $caption . '</p></div>'; |
741 | } |
742 | |
743 | add_shortcode('gallery', 'gallery_shortcode'); |
744 | |
745 | /** |
746 | * The Gallery shortcode. |
747 | * |
748 | * This implements the functionality of the Gallery Shortcode for displaying |
749 | * WordPress images on a post. |
750 | * |
751 | * @since 2.5.0 |
752 | * |
753 | * @param array $attr Attributes attributed to the shortcode. |
754 | * @return string HTML content to display gallery. |
755 | */ |
756 | function gallery_shortcode($attr) { |
757 | global $post, $wp_locale; |
758 | |
759 | static $instance = 0; |
760 | $instance++; |
761 | |
762 | // Allow plugins/themes to override the default gallery template. |
763 | $output = apply_filters('post_gallery', '', $attr); |
764 | if ( $output != '' ) |
765 | return $output; |
766 | |
767 | // We're trusting author input, so let's at least make sure it looks like a valid orderby statement |
768 | if ( isset( $attr['orderby'] ) ) { |
769 | $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] ); |
770 | if ( !$attr['orderby'] ) |
771 | unset( $attr['orderby'] ); |
772 | } |
773 | |
774 | extract(shortcode_atts(array( |
775 | 'order' => 'ASC', |
776 | 'orderby' => 'menu_order ID', |
777 | 'id' => $post->ID, |
778 | 'itemtag' => 'dl', |
779 | 'icontag' => 'dt', |
780 | 'captiontag' => 'dd', |
781 | 'columns' => 3, |
782 | 'size' => 'thumbnail', |
783 | 'include' => '', |
784 | 'exclude' => '' |
785 | ), $attr)); |
786 | |
787 | $id = intval($id); |
788 | if ( 'RAND' == $order ) |
789 | $orderby = 'none'; |
790 | |
791 | if ( !empty($include) ) { |
792 | $include = preg_replace( '/[^0-9,]+/', '', $include ); | //Arbitrary code inclusion
|
793 | $_attachments = get_posts( array('include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) ); | //Arbitrary code inclusion
|
794 | |
795 | $attachments = array(); |
796 | foreach ( $_attachments as $key => $val ) { |
797 | $attachments[$val->ID] = $_attachments[$key]; |
798 | } |
799 | } elseif ( !empty($exclude) ) { |
800 | $exclude = preg_replace( '/[^0-9,]+/', '', $exclude ); |
801 | $attachments = get_children( array('post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) ); |
802 | } else { |
803 | $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) ); |
804 | } |
805 | |
806 | if ( empty($attachments) ) |
807 | return ''; |
808 | |
809 | if ( is_feed() ) { |
810 | $output = "\n"; |
811 | foreach ( $attachments as $att_id => $attachment ) |
812 | $output .= wp_get_attachment_link($att_id, $size, true) . "\n"; |
813 | return $output; |
814 | } |
815 | |
816 | $itemtag = tag_escape($itemtag); |
817 | $captiontag = tag_escape($captiontag); |
818 | $columns = intval($columns); |
819 | $itemwidth = $columns > 0 ? floor(100/$columns) : 100; |
820 | $float = is_rtl() ? 'right' : 'left'; |
821 | |
822 | $selector = "gallery-{$instance}"; |
823 | |
824 | $output = apply_filters('gallery_style', " |
825 | <style type='text/css'> |
826 | #{$selector} { |
827 | margin: auto; |
828 | } |
829 | #{$selector} .gallery-item { |
830 | float: {$float}; |
831 | margin-top: 10px; |
832 | text-align: center; |
833 | width: {$itemwidth}%; } |
834 | #{$selector} img { |
835 | border: 2px solid #cfcfcf; |
836 | } |
837 | #{$selector} .gallery-caption { |
838 | margin-left: 0; |
839 | } |
840 | </style> |
841 | <!-- see gallery_shortcode() in wp-includes/media.php --> |
842 | <div id='$selector' class='gallery galleryid-{$id}'>"); |
843 | |
844 | $i = 0; |
845 | foreach ( $attachments as $id => $attachment ) { |
846 | $link = isset($attr['link']) && 'file' == $attr['link'] ? wp_get_attachment_link($id, $size, false, false) : wp_get_attachment_link($id, $size, true, false); | //Arbitrary file disclosing
|
847 | |
848 | $output .= "<{$itemtag} class='gallery-item'>"; |
849 | $output .= " |
850 | <{$icontag} class='gallery-icon'> |
851 | $link |
852 | </{$icontag}>"; |
853 | if ( $captiontag && trim($attachment->post_excerpt) ) { |
854 | $output .= " |
855 | <{$captiontag} class='gallery-caption'> |
856 | " . wptexturize($attachment->post_excerpt) . " |
857 | </{$captiontag}>"; |
858 | } |
859 | $output .= "</{$itemtag}>"; |
860 | if ( $columns > 0 && ++$i % $columns == 0 ) |
861 | $output .= '<br style="clear: both" />'; |
862 | } |
863 | |
864 | $output .= " |
865 | <br style='clear: both;' /> |
866 | </div>\n"; |
867 | |
868 | return $output; |
869 | } |
870 | |
871 | /** |
872 | * Display previous image link that has the same post parent. |
873 | * |
874 | * @since 2.5.0 |
875 | * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string. 0 or 'none' will default to post_title or $text; |
876 | * @param string $text Optional, default is false. If included, link will reflect $text variable. |
877 | * @return string HTML content. |
878 | */ |
879 | function previous_image_link($size = 'thumbnail', $text = false) { |
880 | adjacent_image_link(true, $size, $text); |
881 | } |
882 | |
883 | /** |
884 | * Display next image link that has the same post parent. |
885 | * |
886 | * @since 2.5.0 |
887 | * @param string $size Optional, default is 'thumbnail'. Size of image, either array or string. 0 or 'none' will default to post_title or $text; |
888 | * @param string $text Optional, default is false. If included, link will reflect $text variable. |
889 | * @return string HTML content. |
890 | */ |
891 | function next_image_link($size = 'thumbnail', $text = false) { |
892 | adjacent_image_link(false, $size, $text); |
893 | } |
894 | |
895 | /** |
896 | * Display next or previous image link that has the same post parent. |
897 | * |
898 | * Retrieves the current attachment object from the $post global. |
899 | * |
900 | * @since 2.5.0 |
901 | * |
902 | * @param bool $prev Optional. Default is true to display previous link, true for next. |
903 | */ |
904 | function adjacent_image_link($prev = true, $size = 'thumbnail', $text = false) { |
905 | global $post; |
906 | $post = get_post($post); |
907 | $attachments = array_values(get_children( array('post_parent' => $post->post_parent, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => 'ASC', 'orderby' => 'menu_order ID') )); |
908 | |
909 | foreach ( $attachments as $k => $attachment ) |
910 | if ( $attachment->ID == $post->ID ) |
911 | break; |
912 | |
913 | $k = $prev ? $k - 1 : $k + 1; |
914 | |
915 | if ( isset($attachments[$k]) ) |
916 | echo wp_get_attachment_link($attachments[$k]->ID, $size, true, false, $text); |
917 | } |
918 | |
919 | /** |
920 | * Retrieve taxonomies attached to the attachment. |
921 | * |
922 | * @since 2.5.0 |
923 | * |
924 | * @param int|array|object $attachment Attachment ID, Attachment data array, or Attachment data object. |
925 | * @return array Empty array on failure. List of taxonomies on success. |
926 | */ |
927 | function get_attachment_taxonomies($attachment) { |
928 | if ( is_int( $attachment ) ) |
929 | $attachment = get_post($attachment); |
930 | else if ( is_array($attachment) ) |
931 | $attachment = (object) $attachment; |
932 | |
933 | if ( ! is_object($attachment) ) |
934 | return array(); |
935 | |
936 | $filename = basename($attachment->guid); |
937 | |
938 | $objects = array('attachment'); |
939 | |
940 | if ( false !== strpos($filename, '.') ) |
941 | $objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1); |
942 | if ( !empty($attachment->post_mime_type) ) { |
943 | $objects[] = 'attachment:' . $attachment->post_mime_type; |
944 | if ( false !== strpos($attachment->post_mime_type, '/') ) |
945 | foreach ( explode('/', $attachment->post_mime_type) as $token ) |
946 | if ( !empty($token) ) |
947 | $objects[] = "attachment:$token"; |
948 | } |
949 | |
950 | $taxonomies = array(); |
951 | foreach ( $objects as $object ) |
952 | if ( $taxes = get_object_taxonomies($object) ) |
953 | $taxonomies = array_merge($taxonomies, $taxes); |
954 | |
955 | return array_unique($taxonomies); |
956 | } |
957 | |
958 | /** |
959 | * Check if the installed version of GD supports particular image type |
960 | * |
961 | * @since 2.9.0 |
962 | * |
963 | * @param $mime_type string |
964 | * @return bool |
965 | */ |
966 | function gd_edit_image_support($mime_type) { |
967 | if ( function_exists('imagetypes') ) { |
968 | switch( $mime_type ) { |
969 | case 'image/jpeg': |
970 | return (imagetypes() & IMG_JPG) != 0; |
971 | case 'image/png': |
972 | return (imagetypes() & IMG_PNG) != 0; |
973 | case 'image/gif': |
974 | return (imagetypes() & IMG_GIF) != 0; |
975 | } |
976 | } else { |
977 | switch( $mime_type ) { |
978 | case 'image/jpeg': |
979 | return function_exists('imagecreatefromjpeg'); |
980 | case 'image/png': |
981 | return function_exists('imagecreatefrompng'); |
982 | case 'image/gif': |
983 | return function_exists('imagecreatefromgif'); |
984 | } |
985 | } |
986 | return false; |
987 | } |
988 | |
989 | /** |
990 | * Create new GD image resource with transparency support |
991 | * |
992 | * @since 2.9.0 |
993 | * |
994 | * @param $width |
995 | * @param $height |
996 | * @return image resource |
997 | */ |
998 | function wp_imagecreatetruecolor($width, $height) { |
999 | $img = imagecreatetruecolor($width, $height); |
1000 | if ( is_resource($img) && function_exists('imagealphablending') && function_exists('imagesavealpha') ) { |