Wordpress 2.5.1
[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() && $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 // return an <img src /> tag for the given image attachment, scaling it down if requested
94 function get_image_tag($id, $alt, $title, $align, $size='medium') {
95
96         list( $img_src, $width, $height ) = image_downsize($id, $size);
97         $hwstring = image_hwstring($width, $height);
98
99         $html = '<img src="'.attribute_escape($img_src).'" alt="'.attribute_escape($alt).'" title="'.attribute_escape($title).'" '.$hwstring.'class="align'.attribute_escape($align).' size-'.attribute_escape($size).' wp-image-'.$id.'" />';
100
101         $url = '';
102         $html = apply_filters( 'image_send_to_editor', $html, $id, $alt, $title, $align, $url, $size );
103
104         return $html;
105 }
106
107 // same as wp_shrink_dimensions, except the max parameters are optional.
108 // if either width or height are empty, no constraint is applied on that dimension.
109 function wp_constrain_dimensions( $current_width, $current_height, $max_width=0, $max_height=0 ) {
110         if ( !$max_width and !$max_height )
111                 return array( $current_width, $current_height );
112
113         $width_ratio = $height_ratio = 1.0;
114
115         if ( $max_width > 0 && $current_width > $max_width )
116                 $width_ratio = $max_width / $current_width;
117
118         if ( $max_height > 0 && $current_height > $max_height )
119                 $height_ratio = $max_height / $current_height;
120
121         // the smaller ratio is the one we need to fit it to the constraining box
122         $ratio = min( $width_ratio, $height_ratio );
123
124         return array( intval($current_width * $ratio), intval($current_height * $ratio) );
125 }
126
127 // calculate dimensions and coordinates for a resized image that fits within a specified width and height
128 // if $crop is true, the largest matching central portion of the image will be cropped out and resized to the required size
129 function image_resize_dimensions($orig_w, $orig_h, $dest_w, $dest_h, $crop=false) {
130
131         if ($orig_w <= 0 || $orig_h <= 0)
132                 return false;
133         // at least one of dest_w or dest_h must be specific
134         if ($dest_w <= 0 && $dest_h <= 0)
135                 return false;
136
137         if ( $crop ) {
138                 // crop the largest possible portion of the original image that we can size to $dest_w x $dest_h
139                 $aspect_ratio = $orig_w / $orig_h;
140                 $new_w = min($dest_w, $orig_w);
141                 $new_h = min($dest_h, $orig_h);
142                 if (!$new_w) {
143                         $new_w = intval($new_h * $aspect_ratio);
144                 }
145                 if (!$new_h) {
146                         $new_h = intval($new_w / $aspect_ratio);
147                 }
148
149                 $size_ratio = max($new_w / $orig_w, $new_h / $orig_h);
150
151                 $crop_w = ceil($new_w / $size_ratio);
152                 $crop_h = ceil($new_h / $size_ratio);
153
154                 $s_x = floor(($orig_w - $crop_w)/2);
155                 $s_y = floor(($orig_h - $crop_h)/2);
156         }
157         else {
158                 // don't crop, just resize using $dest_w x $dest_h as a maximum bounding box
159                 $crop_w = $orig_w;
160                 $crop_h = $orig_h;
161
162                 $s_x = 0;
163                 $s_y = 0;
164
165                 list( $new_w, $new_h ) = wp_constrain_dimensions( $orig_w, $orig_h, $dest_w, $dest_h );
166         }
167
168         // if the resulting image would be the same size or larger we don't want to resize it
169         if ($new_w >= $orig_w && $new_h >= $orig_h)
170                 return false;
171
172         // the return array matches the parameters to imagecopyresampled()
173         // int dst_x, int dst_y, int src_x, int src_y, int dst_w, int dst_h, int src_w, int src_h
174         return array(0, 0, $s_x, $s_y, $new_w, $new_h, $crop_w, $crop_h);
175
176 }
177
178 // Scale down an image to fit a particular size and save a new copy of the image
179 function image_resize( $file, $max_w, $max_h, $crop=false, $suffix=null, $dest_path=null, $jpeg_quality=90) {
180
181         $image = wp_load_image( $file );
182         if ( !is_resource( $image ) )
183                 return new WP_Error('error_loading_image', $image);
184
185         list($orig_w, $orig_h, $orig_type) = getimagesize( $file );
186         $dims = image_resize_dimensions($orig_w, $orig_h, $max_w, $max_h, $crop);
187         if (!$dims)
188                 return $dims;
189         list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $dims;
190
191         $newimage = imagecreatetruecolor( $dst_w, $dst_h);
192
193         // preserve PNG transparency
194         if ( IMAGETYPE_PNG == $orig_type && function_exists( 'imagealphablending' ) && function_exists( 'imagesavealpha' ) ) {
195                 imagealphablending( $newimage, false);
196                 imagesavealpha( $newimage, true);
197         }
198
199         imagecopyresampled( $newimage, $image, $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h);
200
201         // we don't need the original in memory anymore
202         imagedestroy( $image );
203
204         // $suffix will be appended to the destination filename, just before the extension
205         if ( !$suffix )
206                 $suffix = "{$dst_w}x{$dst_h}";
207
208         $info = pathinfo($file);
209         $dir = $info['dirname'];
210         $ext = $info['extension'];
211         $name = basename($file, ".{$ext}");
212         if ( !is_null($dest_path) and $_dest_path = realpath($dest_path) )
213                 $dir = $_dest_path;
214         $destfilename = "{$dir}/{$name}-{$suffix}.{$ext}";
215
216         if ( $orig_type == IMAGETYPE_GIF ) {
217                 if (!imagegif( $newimage, $destfilename ) )
218                         return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
219         }
220         elseif ( $orig_type == IMAGETYPE_PNG ) {
221                 if (!imagepng( $newimage, $destfilename ) )
222                         return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
223         }
224         else {
225                 // all other formats are converted to jpg
226                 $destfilename = "{$dir}/{$name}-{$suffix}.jpg";
227                 if (!imagejpeg( $newimage, $destfilename, apply_filters( 'jpeg_quality', $jpeg_quality ) ) )
228                         return new WP_Error('resize_path_invalid', __( 'Resize path invalid' ));
229         }
230
231         imagedestroy( $newimage );
232
233         // Set correct file permissions
234         $stat = stat( dirname( $destfilename ));
235         $perms = $stat['mode'] & 0000666; //same permissions as parent folder, strip off the executable bits
236         @ chmod( $destfilename, $perms );
237
238         return $destfilename;
239 }
240
241 // resize an image to make a thumbnail or intermediate size, and return metadata describing the new copy
242 // returns false if no image was created
243 function image_make_intermediate_size($file, $width, $height, $crop=false) {
244         if ( $width || $height ) {
245                 $resized_file = image_resize($file, $width, $height, $crop);
246                 if ( !is_wp_error($resized_file) && $resized_file && $info = getimagesize($resized_file) ) {
247                         $resized_file = apply_filters('image_make_intermediate_size', $resized_file);
248                         return array(
249                                 'file' => basename( $resized_file ),
250                                 'width' => $info[0],
251                                 'height' => $info[1],
252                         );
253                 }
254         }
255         return false;
256 }
257
258 function image_get_intermediate_size($post_id, $size='thumbnail') {
259         if ( !$imagedata = wp_get_attachment_metadata( $post_id ) )
260                 return false;
261
262         // get the best one for a specified set of dimensions
263         if ( is_array($size) && !empty($imagedata['sizes']) ) {
264                 foreach ( $imagedata['sizes'] as $_size => $data ) {
265                         // already cropped to width or height; so use this size
266                         if ( ( $data['width'] == $size[0] && $data['height'] <= $size[1] ) || ( $data['height'] == $size[1] && $data['width'] <= $size[0] ) ) {
267                                 $file = $data['file'];
268                                 list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
269                                 return compact( 'file', 'width', 'height' );
270                         }
271                         // add to lookup table: area => size
272                         $areas[$data['width'] * $data['height']] = $_size;
273                 }
274                 if ( !$size || !empty($areas) ) {
275                         // find for the smallest image not smaller than the desired size
276                         ksort($areas);
277                         foreach ( $areas as $_size ) {
278                                 $data = $imagedata['sizes'][$_size];
279                                 if ( $data['width'] >= $size[0] || $data['height'] >= $size[1] ) {
280                                         $file = $data['file'];
281                                         list($width, $height) = image_constrain_size_for_editor( $data['width'], $data['height'], $size );
282                                         return compact( 'file', 'width', 'height' );
283                                 }
284                         }
285                 }
286         }
287
288         if ( is_array($size) || empty($size) || empty($imagedata['sizes'][$size]) )
289                 return false;
290                 
291         $data = $imagedata['sizes'][$size];
292         // include the full filesystem path of the intermediate file
293         if ( empty($data['path']) && !empty($data['file']) ) {
294                 $file_url = wp_get_attachment_url($post_id);
295                 $data['path'] = path_join( dirname($imagedata['file']), $data['file'] );
296                 $data['url'] = path_join( dirname($file_url), $data['file'] );
297         }
298         return $data;
299 }
300
301 // get an image to represent an attachment - a mime icon for files, thumbnail or intermediate size for images
302 // returns an array (url, width, height), or false if no image is available
303 function wp_get_attachment_image_src($attachment_id, $size='thumbnail', $icon = false) {
304         
305         // get a thumbnail or intermediate image if there is one
306         if ( $image = image_downsize($attachment_id, $size) )
307                 return $image;
308
309         if ( $icon && $src = wp_mime_type_icon($attachment_id) ) {
310                 $icon_dir = apply_filters( 'icon_dir', ABSPATH . WPINC . '/images/crystal' );
311                 $src_file = $icon_dir . '/' . basename($src);
312                 @list($width, $height) = getimagesize($src_file);
313         }
314         if ( $src && $width && $height )
315                 return array( $src, $width, $height );
316         return false;
317 }
318
319 // as per wp_get_attachment_image_src, but returns an <img> tag
320 function wp_get_attachment_image($attachment_id, $size='thumbnail', $icon = false) {
321
322         $html = '';
323         $image = wp_get_attachment_image_src($attachment_id, $size, $icon);
324         if ( $image ) {
325                 list($src, $width, $height) = $image;
326                 $hwstring = image_hwstring($width, $height);
327                 if ( is_array($size) )
328                         $size = join('x', $size);
329                 $html = '<img src="'.attribute_escape($src).'" '.$hwstring.'class="attachment-'.attribute_escape($size).'" alt="" />';
330         }
331         
332         return $html;
333 }
334
335 add_shortcode('gallery', 'gallery_shortcode');
336
337 function gallery_shortcode($attr) {
338         global $post;
339
340         // Allow plugins/themes to override the default gallery template.
341         $output = apply_filters('post_gallery', '', $attr);
342         if ( $output != '' )
343                 return $output;
344
345         // We're trusting author input, so let's at least make sure it looks like a valid orderby statement
346         if ( isset( $attr['orderby'] ) ) {
347                 $attr['orderby'] = sanitize_sql_orderby( $attr['orderby'] );
348                 if ( !$attr['orderby'] )
349                         unset( $attr['orderby'] );
350         }
351
352         extract(shortcode_atts(array(
353                 'orderby'    => 'menu_order ASC, ID ASC',
354                 'id'         => $post->ID,
355                 'itemtag'    => 'dl',
356                 'icontag'    => 'dt',
357                 'captiontag' => 'dd',
358                 'columns'    => 3,
359                 'size'       => 'thumbnail',
360         ), $attr));
361
362         $id = intval($id);
363         $attachments = get_children("post_parent=$id&post_type=attachment&post_mime_type=image&orderby={$orderby}");
364
365         if ( empty($attachments) )
366                 return '';
367
368         if ( is_feed() ) {
369                 $output = "\n";
370                 foreach ( $attachments as $id => $attachment )
371                         $output .= wp_get_attachment_link($id, $size, true) . "\n";
372                 return $output;
373         }
374
375         $listtag = tag_escape($listtag);
376         $itemtag = tag_escape($itemtag);
377         $captiontag = tag_escape($captiontag);
378         $columns = intval($columns);
379         $itemwidth = $columns > 0 ? floor(100/$columns) : 100;
380         
381         $output = apply_filters('gallery_style', "
382                 <style type='text/css'>
383                         .gallery {
384                                 margin: auto;
385                         }
386                         .gallery-item {
387                                 float: left;
388                                 margin-top: 10px;
389                                 text-align: center;
390                                 width: {$itemwidth}%;                   }
391                         .gallery img {
392                                 border: 2px solid #cfcfcf;
393                         }
394                         .gallery-caption {
395                                 margin-left: 0;
396                         }
397                 </style>
398                 <!-- see gallery_shortcode() in wp-includes/media.php -->
399                 <div class='gallery'>");
400
401         foreach ( $attachments as $id => $attachment ) {
402                 $link = wp_get_attachment_link($id, $size, true);
403                 $output .= "<{$itemtag} class='gallery-item'>";
404                 $output .= "
405                         <{$icontag} class='gallery-icon'>
406                                 $link
407                         </{$icontag}>";
408                 if ( $captiontag && trim($attachment->post_excerpt) ) {
409                         $output .= "
410                                 <{$captiontag} class='gallery-caption'>
411                                 {$attachment->post_excerpt}
412                                 </{$captiontag}>";
413                 }
414                 $output .= "</{$itemtag}>";
415                 if ( $columns > 0 && ++$i % $columns == 0 )
416                         $output .= '<br style="clear: both" />';
417         }
418
419         $output .= "
420                         <br style='clear: both;' />
421                 </div>\n";
422
423         return $output;
424 }
425
426 function previous_image_link() {
427         adjacent_image_link(true);
428 }
429
430 function next_image_link() {
431         adjacent_image_link(false);
432 }
433
434 function adjacent_image_link($prev = true) {
435         global $post;
436         $post = get_post($post);
437         $attachments = array_values(get_children("post_parent=$post->post_parent&post_type=attachment&post_mime_type=image&orderby=menu_order ASC, ID ASC"));
438
439         foreach ( $attachments as $k => $attachment )
440                 if ( $attachment->ID == $post->ID )
441                         break;
442
443         $k = $prev ? $k - 1 : $k + 1;
444
445         if ( isset($attachments[$k]) )
446                 echo wp_get_attachment_link($attachments[$k]->ID, 'thumbnail', true);
447 }
448
449 function get_attachment_taxonomies($attachment) {
450         if ( is_int( $attachment ) )
451                 $attachment = get_post($attachment);
452         else if ( is_array($attachment) )
453                 $attachment = (object) $attachment;
454
455         if ( ! is_object($attachment) )
456                 return array();
457
458         $filename = basename($attachment->guid);
459
460         $objects = array('attachment');
461
462         if ( false !== strpos($filename, '.') )
463                 $objects[] = 'attachment:' . substr($filename, strrpos($filename, '.') + 1);
464         if ( !empty($attachment->post_mime_type) ) {
465                 $objects[] = 'attachment:' . $attachment->post_mime_type;
466                 if ( false !== strpos($attachment->post_mime_type, '/') )
467                         foreach ( explode('/', $attachment->post_mime_type) as $token )
468                                 if ( !empty($token) )
469                                         $objects[] = "attachment:$token";
470         }
471
472         $taxonomies = array();
473         foreach ( $objects as $object )
474                 if ( $taxes = get_object_taxonomies($object) )
475                         $taxonomies = array_merge($taxonomies, $taxes);
476
477         return array_unique($taxonomies);
478 }
479
480 ?>