3 // functions for media display
5 // scale down the default size of an image so it's a better fit for the editor and theme
6 function image_constrain_size_for_editor($width, $height, $size = 'medium') {
8 if ( is_array($size) ) {
10 $max_height = $size[1];
12 elseif ( $size == 'thumb' || $size == 'thumbnail' ) {
13 $max_width = intval(get_option('thumbnail_size_w'));
14 $max_height = intval(get_option('thumbnail_size_h'));
15 // last chance thumbnail size defaults
16 if ( !$max_width && !$max_height ) {
21 elseif ( $size == 'medium' ) {
22 $max_width = intval(get_option('medium_size_w'));
23 $max_height = intval(get_option('medium_size_h'));
24 // if no width is set, default to the theme content width if available
26 else { // $size == 'full'
27 // we're inserting a full size image into the editor. if it's a really big image we'll scale it down to fit reasonably
28 // within the editor itself, and within the theme's content width if it's known. the user can resize it in the editor
30 if ( !empty($GLOBALS['content_width']) ) {
31 $max_width = $GLOBALS['content_width'];
37 list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size );
39 return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
42 // return a width/height string for use in an <img /> tag. Empty values will be omitted.
43 function image_hwstring($width, $height) {
46 $out .= 'width="'.intval($width).'" ';
48 $out .= 'height="'.intval($height).'" ';
52 // Scale an image to fit a particular size (such as 'thumb' or 'medium'), and return an image URL, height and width.
53 // The URL might be the original image, or it might be a resized version. This function won't create a new resized copy, it will just return an already resized one if it exists.
54 // returns an array($url, $width, $height)
55 function image_downsize($id, $size = 'medium') {
57 if ( !wp_attachment_is_image($id) )
60 $img_url = wp_get_attachment_url($id);
61 $meta = wp_get_attachment_metadata($id);
64 // plugins can use this to provide resize services
65 if ( $out = apply_filters('image_downsize', false, $id, $size) )
68 // try for a new style intermediate size
69 if ( $intermediate = image_get_intermediate_size($id, $size) ) {
70 $img_url = str_replace(basename($img_url), $intermediate['file'], $img_url);
71 $width = $intermediate['width'];
72 $height = $intermediate['height'];
74 elseif ( $size == 'thumbnail' ) {
75 // fall back to the old thumbnail
76 if ( ($thumb_file = wp_get_attachment_thumb_file($id)) && $info = getimagesize($thumb_file) ) {
77 $img_url = str_replace(basename($img_url), basename($thumb_file), $img_url);
82 if ( !$width && !$height && isset($meta['width'], $meta['height']) ) {
83 // any other type: use the real image and constrain it
84 list( $width, $height ) = image_constrain_size_for_editor( $meta['width'], $meta['height'], $size );
88 return array( $img_url, $width, $height );
94 * An <img src /> tag for an image attachment, scaling it down if requested.
96 * {@internal Missing Long Description}}
98 * @uses apply_filters() The 'get_image_tag_class' filter is the IMG element
100 * @uses apply_filters() The 'get_image_tag' filter is the full IMG element with
103 * @param int $id Attachment ID.
104 * @param string $alt Image Description for the alt attribute.
105 * @param string $title Image Description for the title attribute.
106 * @param string $align Part of the class name for aligning the image.
107 * @param string $size Optional. Default is 'medium'.
108 * @return string HTML IMG element for given image attachment
110 function get_image_tag($id, $alt, $title, $align, $size='medium') {
112 list( $img_src, $width, $height ) = image_downsize($id, $size);
113 $hwstring = image_hwstring($width, $height);
115 $class = 'align'.attribute_escape($align).' size-'.attribute_escape($size).' wp-image-'.$id;
116 $class = apply_filters('get_image_tag_class', $class, $id, $align, $size);
118 $html = '<img src="'.attribute_escape($img_src).'" alt="'.attribute_escape($alt).'" title="'.attribute_escape($title).'" '.$hwstring.'class="'.$class.'" />';
120 $html = apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
125 // same as wp_shrink_dimensions, except the max parameters are optional.
126 // if either width or height are empty, no constraint is applied on that dimension.
127 function wp_constrain_dimensions( $current_width, $current_height, $max_width=0, $max_height=0 ) {
128 if ( !$max_width and !$max_height )
129 return array( $current_width, $current_height );
131 $width_ratio = $height_ratio = 1.0;
133 if ( $max_width > 0 && $current_width > $max_width )
134 $width_ratio = $max_width / $current_width;
136 if ( $max_height > 0 && $current_height > $max_height )
137 $height_ratio = $max_height / $current_height;
139 // the smaller ratio is the one we need to fit it to the constraining box
140 $ratio = min( $width_ratio, $height_ratio );
142 return array( intval($current_width * $ratio), intval($current_height * $ratio) );
145 // calculate dimensions and coordinates for a resized image that fits within a specified width and height
146 // if $crop is true, the largest matching central portion of the image will be cropped out and resized to the required size
147 function image_resize_dimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop=false) {
149 if ($orig_w <= 0 || $orig_h <= 0)
151 // at least one of dest_w or dest_h must be specific
152 if ($dest_w <= 0 && $dest_h <= 0)
156 // crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
157 $aspect_ratio = $orig_w / $orig_h;
158 $new_w = min($dest_w, $orig_w);
159 $new_h = min($dest_h, $orig_h);
161 $new_w = intval($new_h * $aspect_ratio);
164 $new_h = intval($new_w / $aspect_ratio);
167 $size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
169 $crop_w = ceil($new_w / $size_ratio);
170 $crop_h = ceil($new_h / $size_ratio);
172 $s_x = floor(($orig_w - $crop_w)/2);
173 $s_y = floor(($orig_h - $crop_h)/2);
176 // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
183 list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
186 // if the resulting image would be the same size or larger we don't want to resize it
187 if ($new_w >= $orig_w && $new_h >= $orig_h)
190 // the return array matches the parameters to imagecopyresampled()
191 // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
192 return array(0, 0, $s_x, $s_y, $new_w, $new_h, $crop_w, $crop_h);
196 // Scale down an image to fit a particular size and save a new copy of the image
197 function image_resize( $file, $max_w, $max_h, $crop=false, $suffix=null, $dest_path=null, $jpeg_quality=90) {
199 $image = wp_load_image( $file );
200 if ( !is_resource( $image ) )
201 return new WP_Error('error_loading_image', $image);
203 list($orig_w, $orig_h, $orig_type) = getimagesize( $file );
204 $dims = image_resize_dimensions($orig_w, $orig_h, $max_w, $max_h, $crop);
207 list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims;
209 $newimage = imagecreatetruecolor( $dst_w, $dst_h);
211 // preserve PNG transparency
212 if ( IMAGETYPE_PNG == $orig_type && function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) {
213 imagealphablending( $newimage, false);
214 imagesavealpha( $newimage, true);
217 imagecopyresampled( $newimage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
219 // we don't need the original in memory anymore
220 imagedestroy( $image );
222 // $suffix will be appended to the destination filename, just before the extension
224 $suffix = "{$dst_w}x{$dst_h}";
226 $info = pathinfo($file);
227 $dir = $info['dirname'];
228 $ext = $info['extension'];
229 $name = basename($file, ".{$ext}");
230 if ( !is_null($dest_path) and $_dest_path = realpath($dest_path) )
232 $destfilename = "{$dir}/{$name}-{$suffix}.{$ext}";
234 if ( $orig_type == IMAGETYPE_GIF ) {
235 if (!imagegif( $newimage, $destfilename ) )
236 return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
238 elseif ( $orig_type == IMAGETYPE_PNG ) {
239 if (!imagepng( $newimage, $destfilename ) )
240 return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
243 // all other formats are converted to jpg
244 $destfilename = "{$dir}/{$name}-{$suffix}.jpg";
245 if (!imagejpeg( $newimage, $destfilename, apply_filters( 'jpeg_quality', $jpeg_quality ) ) )
246 return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
249 imagedestroy( $newimage );
251 // Set correct file permissions
252 $stat = stat( dirname( $destfilename ));
253 $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
254 @ chmod( $destfilename, $perms );
256 return $destfilename;
259 // resize an image to make a thumbnail or intermediate size, and return metadata describing the new copy
260 // returns false if no image was created
261 function image_make_intermediate_size($file, $width, $height, $crop=false) {
262 if ( $width || $height ) {
263 $resized_file = image_resize($file, $width, $height, $crop);
264 if ( !is_wp_error($resized_file) && $resized_file && $info = getimagesize($resized_file) ) {
265 $resized_file = apply_filters('image_make_intermediate_size', $resized_file);
267 'file' => basename( $resized_file ),
269 'height' => $info[1],
276 function image_get_intermediate_size($post_id, $size='thumbnail') {
277 if ( !is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) )
280 // get the best one for a specified set of dimensions
281 if ( is_array($size) && !empty($imagedata['sizes']) ) {
282 foreach ( $imagedata['sizes'] as $_size => $data ) {
283 // already cropped to width or height; so use this size
284 if ( ( $data['width'] == $size[0] && $data['height'] <= $size[1] ) || ( $data['height'] == $size[1] && $data['width'] <= $size[0] ) ) {
285 $file = $data['file'];
286 list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
287 return compact( 'file', 'width', 'height' );
289 // add to lookup table: area => size
290 $areas[$data['width'] * $data['height']] = $_size;
292 if ( !$size || !empty($areas) ) {
293 // find for the smallest image not smaller than the desired size
295 foreach ( $areas as $_size ) {
296 $data = $imagedata['sizes'][$_size];
297 if ( $data['width'] >= $size[0] || $data['height'] >= $size[1] ) {
298 $file = $data['file'];
299 list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
300 return compact( 'file', 'width', 'height' );
306 if ( is_array($size) || empty($size) || empty($imagedata['sizes'][$size]) )
309 $data = $imagedata['sizes'][$size];
310 // include the full filesystem path of the intermediate file
311 if ( empty($data['path']) && !empty($data['file']) ) {
312 $file_url = wp_get_attachment_url($post_id);
313 $data['path'] = path_join( dirname($imagedata['file']), $data['file'] );
314 $data['url'] = path_join( dirname($file_url), $data['file'] );
319 // get an image to represent an attachment - a mime icon for files, thumbnail or intermediate size for images
320 // returns an array (url, width, height), or false if no image is available
321 function wp_get_attachment_image_src($attachment_id, $size='thumbnail', $icon = false) {
323 // get a thumbnail or intermediate image if there is one
324 if ( $image = image_downsize($attachment_id, $size) )
327 if ( $icon && $src = wp_mime_type_icon($attachment_id) ) {
328 $icon_dir = apply_filters( 'icon_dir', includes_url('images/crystal') );
329 $src_file = $icon_dir . '/' . basename($src);
330 @list($width, $height) = getimagesize($src_file);
332 if ( $src && $width && $height )
333 return array( $src, $width, $height );
337 // as per wp_get_attachment_image_src, but returns an <img> tag
338 function wp_get_attachment_image($attachment_id, $size='thumbnail', $icon = false) {
341 $image = wp_get_attachment_image_src($attachment_id, $size, $icon);
343 list($src, $width, $height) = $image;
344 $hwstring = image_hwstring($width, $height);
345 if ( is_array($size) )
346 $size = join('x', $size);
347 $html = '<img src="'.attribute_escape($src).'" '.$hwstring.'class="attachment-'.attribute_escape($size).'" alt="" />';
353 add_shortcode('wp_caption', 'img_caption_shortcode');
354 add_shortcode('caption', 'img_caption_shortcode');
356 function img_caption_shortcode($attr, $content = null) {
358 // Allow plugins/themes to override the default caption template.
359 $output = apply_filters('img_caption_shortcode', '', $attr, $content);
363 extract(shortcode_atts(array(
365 'align' => 'alignnone',
370 if ( 1 > (int) $width || empty($caption) )
373 if ( $id ) $id = 'id="' . $id . '" ';
375 return '<div ' . $id . 'class="wp-caption ' . $align . '" style="width: ' . (10 + (int) $width) . 'px">'
376 . $content . '<p class="wp-caption-text">' . $caption . '</p></div>';
379 add_shortcode('gallery', 'gallery_shortcode');
381 function gallery_shortcode($attr) {
384 // Allow plugins/themes to override the default gallery template.
385 $output = apply_filters('post_gallery', '', $attr);
389 // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
390 if ( isset( $attr['orderby'] ) ) {
391 $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
392 if ( !$attr['orderby'] )
393 unset( $attr['orderby'] );
396 extract(shortcode_atts(array(
398 'orderby' => 'menu_order ID',
402 'captiontag' => 'dd',
404 'size' => 'thumbnail',
408 $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
410 if ( empty($attachments) )
415 foreach ( $attachments as $id => $attachment )
416 $output .= wp_get_attachment_link($id, $size, true) . "\n";
420 $listtag = tag_escape($listtag);
421 $itemtag = tag_escape($itemtag);
422 $captiontag = tag_escape($captiontag);
423 $columns = intval($columns);
424 $itemwidth = $columns > 0 ? floor(100/$columns) : 100;
426 $output = apply_filters('gallery_style', "
427 <style type='text/css'>
435 width: {$itemwidth}%; }
437 border: 2px solid #cfcfcf;
443 <!-- see gallery_shortcode() in wp-includes/media.php -->
444 <div class='gallery'>");
446 foreach ( $attachments as $id => $attachment ) {
447 $link = wp_get_attachment_link($id, $size, true);
448 $output .= "<{$itemtag} class='gallery-item'>";
450 <{$icontag} class='gallery-icon'>
453 if ( $captiontag && trim($attachment->post_excerpt) ) {
455 <{$captiontag} class='gallery-caption'>
456 {$attachment->post_excerpt}
459 $output .= "</{$itemtag}>";
460 if ( $columns > 0 && ++$i % $columns == 0 )
461 $output .= '<br style="clear: both" />';
465 <br style='clear: both;' />
471 function previous_image_link() {
472 adjacent_image_link(true);
475 function next_image_link() {
476 adjacent_image_link(false);
479 function adjacent_image_link($prev = true) {
481 $post = get_post($post);
482 $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') ));
484 foreach ( $attachments as $k => $attachment )
485 if ( $attachment->ID == $post->ID )
488 $k = $prev ? $k - 1 : $k + 1;
490 if ( isset($attachments[$k]) )
491 echo wp_get_attachment_link($attachments[$k]->ID, 'thumbnail', true);
494 function get_attachment_taxonomies($attachment) {
495 if ( is_int( $attachment ) )
496 $attachment = get_post($attachment);
497 else if ( is_array($attachment) )
498 $attachment = (object) $attachment;
500 if ( ! is_object($attachment) )
503 $filename = basename($attachment->guid);
505 $objects = array('attachment');
507 if ( false !== strpos($filename, '.') )
508 $objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1);
509 if ( !empty($attachment->post_mime_type) ) {
510 $objects[] = 'attachment:' . $attachment->post_mime_type;
511 if ( false !== strpos($attachment->post_mime_type, '/') )
512 foreach ( explode('/', $attachment->post_mime_type) as $token )
513 if ( !empty($token) )
514 $objects[] = "attachment:$token";
517 $taxonomies = array();
518 foreach ( $objects as $object )
519 if ( $taxes = get_object_taxonomies($object) )
520 $taxonomies = array_merge($taxonomies, $taxes);
522 return array_unique($taxonomies);