Wordpress 2.6.2
[autoinstalls/wordpress.git] / wp-includes / media.php
1 <?php
2
3 // functions for media display
4
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') {
7
8         if ( is_array($size) ) {
9                 $max_width = $size[0];
10                 $max_height = $size[1];
11         }
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 ) {
17                         $max_width = 128;
18                         $max_height = 96;
19                 }
20         }
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
25         }
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
29                 // if they wish.
30                 if ( !empty($GLOBALS['content_width']) ) {
31                         $max_width = $GLOBALS['content_width'];
32                 }
33                 else
34                         $max_width = 500;
35         }
36
37         list( $max_width, $max_height ) = apply_filters( 'editor_max_image_size', array( $max_width, $max_height ), $size );
38
39         return wp_constrain_dimensions( $width, $height, $max_width, $max_height );
40 }
41
42 // return a width/height string for use in an <img /> tag.  Empty values will be omitted.
43 function image_hwstring($width, $height) {
44         $out = '';
45         if ($width)
46                 $out .= 'width="'.intval($width).'" ';
47         if ($height)
48                 $out .= 'height="'.intval($height).'" ';
49         return $out;
50 }
51
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') {
56
57         if ( !wp_attachment_is_image($id) )
58                 return false;
59
60         $img_url = wp_get_attachment_url($id);
61         $meta = wp_get_attachment_metadata($id);
62         $width = $height = 0;
63
64         // plugins can use this to provide resize services
65         if ( $out = apply_filters('image_downsize', false, $id, $size) )
66                 return $out;
67
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'];
73         }
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);
78                         $width = $info[0];
79                         $height = $info[1];
80                 }
81         }
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 );
85         }
86
87         if ( $img_url)
88                 return array( $img_url, $width, $height );
89         return false;
90
91 }
92
93 /**
94  * An <img src /> tag for an image attachment, scaling it down if requested.
95  *
96  * {@internal Missing Long Description}}
97  *
98  * @uses apply_filters() The 'get_image_tag_class' filter is the IMG element
99  *              class attribute.
100  * @uses apply_filters() The 'get_image_tag' filter is the full IMG element with
101  *              all attributes.
102  *
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
109  */
110 function get_image_tag($id, $alt, $title, $align, $size='medium') {
111
112         list( $img_src, $width, $height ) = image_downsize($id, $size);
113         $hwstring = image_hwstring($width, $height);
114
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);
117
118         $html = '<img src="'.attribute_escape($img_src).'" alt="'.attribute_escape($alt).'" title="'.attribute_escape($title).'" '.$hwstring.'class="'.$class.'" />';
119
120         $html = apply_filters( 'get_image_tag', $html, $id, $alt, $title, $align, $size );
121
122         return $html;
123 }
124
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 );
130
131         $width_ratio = $height_ratio = 1.0;
132
133         if ( $max_width > 0 && $current_width > $max_width )
134                 $width_ratio = $max_width / $current_width;
135
136         if ( $max_height > 0 && $current_height > $max_height )
137                 $height_ratio = $max_height / $current_height;
138
139         // the smaller ratio is the one we need to fit it to the constraining box
140         $ratio = min( $width_ratio, $height_ratio );
141
142         return array( intval($current_width * $ratio), intval($current_height * $ratio) );
143 }
144
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) {
148
149         if ($orig_w <= 0 || $orig_h <= 0)
150                 return false;
151         // at least one of dest_w or dest_h must be specific
152         if ($dest_w <= 0 && $dest_h <= 0)
153                 return false;
154
155         if ( $crop ) {
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);
160                 if (!$new_w) {
161                         $new_w = intval($new_h * $aspect_ratio);
162                 }
163                 if (!$new_h) {
164                         $new_h = intval($new_w / $aspect_ratio);
165                 }
166
167                 $size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
168
169                 $crop_w = ceil($new_w / $size_ratio);
170                 $crop_h = ceil($new_h / $size_ratio);
171
172                 $s_x = floor(($orig_w - $crop_w)/2);
173                 $s_y = floor(($orig_h - $crop_h)/2);
174         }
175         else {
176                 // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
177                 $crop_w = $orig_w;
178                 $crop_h = $orig_h;
179
180                 $s_x = 0;
181                 $s_y = 0;
182
183                 list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
184         }
185
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)
188                 return false;
189
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);
193
194 }
195
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) {
198
199         $image = wp_load_image( $file );
200         if ( !is_resource( $image ) )
201                 return new WP_Error('error_loading_image', $image);
202
203         list($orig_w, $orig_h, $orig_type) = getimagesize( $file );
204         $dims = image_resize_dimensions($orig_w, $orig_h, $max_w, $max_h, $crop);
205         if (!$dims)
206                 return $dims;
207         list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims;
208
209         $newimage = imagecreatetruecolor( $dst_w, $dst_h);
210
211         // preserve PNG transparency
212         if ( IMAGETYPE_PNG == $orig_type && function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) {
213                 imagealphablending( $newimage, false);
214                 imagesavealpha( $newimage, true);
215         }
216
217         imagecopyresampled( $newimage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
218
219         // we don't need the original in memory anymore
220         imagedestroy( $image );
221
222         // $suffix will be appended to the destination filename, just before the extension
223         if ( !$suffix )
224                 $suffix = "{$dst_w}x{$dst_h}";
225
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) )
231                 $dir = $_dest_path;
232         $destfilename = "{$dir}/{$name}-{$suffix}.{$ext}";
233
234         if ( $orig_type == IMAGETYPE_GIF ) {
235                 if (!imagegif( $newimage, $destfilename ) )
236                         return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
237         }
238         elseif ( $orig_type == IMAGETYPE_PNG ) {
239                 if (!imagepng( $newimage, $destfilename ) )
240                         return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
241         }
242         else {
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' ));
247         }
248
249         imagedestroy( $newimage );
250
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 );
255
256         return $destfilename;
257 }
258
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);
266                         return array(
267                                 'file' => basename( $resized_file ),
268                                 'width' => $info[0],
269                                 'height' => $info[1],
270                         );
271                 }
272         }
273         return false;
274 }
275
276 function image_get_intermediate_size($post_id, $size='thumbnail') {
277         if ( !is_array( $imagedata = wp_get_attachment_metadata( $post_id ) ) )
278                 return false;
279
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' );
288                         }
289                         // add to lookup table: area => size
290                         $areas[$data['width'] * $data['height']] = $_size;
291                 }
292                 if ( !$size || !empty($areas) ) {
293                         // find for the smallest image not smaller than the desired size
294                         ksort($areas);
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' );
301                                 }
302                         }
303                 }
304         }
305
306         if ( is_array($size) || empty($size) || empty($imagedata['sizes'][$size]) )
307                 return false;
308                 
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'] );
315         }
316         return $data;
317 }
318
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) {
322         
323         // get a thumbnail or intermediate image if there is one
324         if ( $image = image_downsize($attachment_id, $size) )
325                 return $image;
326
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);
331         }
332         if ( $src && $width && $height )
333                 return array( $src, $width, $height );
334         return false;
335 }
336
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) {
339
340         $html = '';
341         $image = wp_get_attachment_image_src($attachment_id, $size, $icon);
342         if ( $image ) {
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="" />';
348         }
349         
350         return $html;
351 }
352
353 add_shortcode('wp_caption', 'img_caption_shortcode');
354 add_shortcode('caption', 'img_caption_shortcode');
355
356 function img_caption_shortcode($attr, $content = null) {
357
358         // Allow plugins/themes to override the default caption template.
359         $output = apply_filters('img_caption_shortcode', '', $attr, $content);
360         if ( $output != '' )
361                 return $output;
362
363         extract(shortcode_atts(array(
364                 'id'    => '',
365                 'align' => 'alignnone',
366                 'width' => '',
367                 'caption' => ''
368         ), $attr));
369         
370         if ( 1 > (int) $width || empty($caption) )
371                 return $content;
372         
373         if ( $id ) $id = 'id="' . $id . '" ';
374         
375         return '<div ' . $id . 'class="wp-caption ' . $align . '" style="width: ' . (10 + (int) $width) . 'px">'
376         . $content . '<p class="wp-caption-text">' . $caption . '</p></div>';
377 }
378
379 add_shortcode('gallery', 'gallery_shortcode');
380
381 function gallery_shortcode($attr) {
382         global $post;
383
384         // Allow plugins/themes to override the default gallery template.
385         $output = apply_filters('post_gallery', '', $attr);
386         if ( $output != '' )
387                 return $output;
388
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'] );
394         }
395
396         extract(shortcode_atts(array(
397                 'order'      => 'ASC',
398                 'orderby'    => 'menu_order ID',
399                 'id'         => $post->ID,
400                 'itemtag'    => 'dl',
401                 'icontag'    => 'dt',
402                 'captiontag' => 'dd',
403                 'columns'    => 3,
404                 'size'       => 'thumbnail',
405         ), $attr));
406
407         $id = intval($id);
408         $attachments = get_children( array('post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby) );
409
410         if ( empty($attachments) )
411                 return '';
412
413         if ( is_feed() ) {
414                 $output = "\n";
415                 foreach ( $attachments as $id => $attachment )
416                         $output .= wp_get_attachment_link($id, $size, true) . "\n";
417                 return $output;
418         }
419
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;
425         
426         $output = apply_filters('gallery_style', "
427                 <style type='text/css'>
428                         .gallery {
429                                 margin: auto;
430                         }
431                         .gallery-item {
432                                 float: left;
433                                 margin-top: 10px;
434                                 text-align: center;
435                                 width: {$itemwidth}%;                   }
436                         .gallery img {
437                                 border: 2px solid #cfcfcf;
438                         }
439                         .gallery-caption {
440                                 margin-left: 0;
441                         }
442                 </style>
443                 <!-- see gallery_shortcode() in wp-includes/media.php -->
444                 <div class='gallery'>");
445
446         foreach ( $attachments as $id => $attachment ) {
447                 $link = wp_get_attachment_link($id, $size, true);
448                 $output .= "<{$itemtag} class='gallery-item'>";
449                 $output .= "
450                         <{$icontag} class='gallery-icon'>
451                                 $link
452                         </{$icontag}>";
453                 if ( $captiontag && trim($attachment->post_excerpt) ) {
454                         $output .= "
455                                 <{$captiontag} class='gallery-caption'>
456                                 {$attachment->post_excerpt}
457                                 </{$captiontag}>";
458                 }
459                 $output .= "</{$itemtag}>";
460                 if ( $columns > 0 && ++$i % $columns == 0 )
461                         $output .= '<br style="clear: both" />';
462         }
463
464         $output .= "
465                         <br style='clear: both;' />
466                 </div>\n";
467
468         return $output;
469 }
470
471 function previous_image_link() {
472         adjacent_image_link(true);
473 }
474
475 function next_image_link() {
476         adjacent_image_link(false);
477 }
478
479 function adjacent_image_link($prev = true) {
480         global $post;
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') ));
483
484         foreach ( $attachments as $k => $attachment )
485                 if ( $attachment->ID == $post->ID )
486                         break;
487
488         $k = $prev ? $k - 1 : $k + 1;
489
490         if ( isset($attachments[$k]) )
491                 echo wp_get_attachment_link($attachments[$k]->ID, 'thumbnail', true);
492 }
493
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;
499
500         if ( ! is_object($attachment) )
501                 return array();
502
503         $filename = basename($attachment->guid);
504
505         $objects = array('attachment');
506
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";
515         }
516
517         $taxonomies = array();
518         foreach ( $objects as $object )
519                 if ( $taxes = get_object_taxonomies($object) )
520                         $taxonomies = array_merge($taxonomies, $taxes);
521
522         return array_unique($taxonomies);
523 }
524
525 ?>