WordPress 4.7
[autoinstalls/wordpress.git] / wp-admin / includes / image.php
1 <?php
2 /**
3  * File contains all the administration image manipulation functions.
4  *
5  * @package WordPress
6  * @subpackage Administration
7  */
8
9 /**
10  * Crop an Image to a given size.
11  *
12  * @since 2.1.0
13  *
14  * @param string|int $src The source file or Attachment ID.
15  * @param int $src_x The start x position to crop from.
16  * @param int $src_y The start y position to crop from.
17  * @param int $src_w The width to crop.
18  * @param int $src_h The height to crop.
19  * @param int $dst_w The destination width.
20  * @param int $dst_h The destination height.
21  * @param int $src_abs Optional. If the source crop points are absolute.
22  * @param string $dst_file Optional. The destination file to write to.
23  * @return string|WP_Error New filepath on success, WP_Error on failure.
24  */
25 function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs = false, $dst_file = false ) {
26         $src_file = $src;
27         if ( is_numeric( $src ) ) { // Handle int as attachment ID
28                 $src_file = get_attached_file( $src );
29
30                 if ( ! file_exists( $src_file ) ) {
31                         // If the file doesn't exist, attempt a URL fopen on the src link.
32                         // This can occur with certain file replication plugins.
33                         $src = _load_image_to_edit_path( $src, 'full' );
34                 } else {
35                         $src = $src_file;
36                 }
37         }
38
39         $editor = wp_get_image_editor( $src );
40         if ( is_wp_error( $editor ) )
41                 return $editor;
42
43         $src = $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs );
44         if ( is_wp_error( $src ) )
45                 return $src;
46
47         if ( ! $dst_file )
48                 $dst_file = str_replace( basename( $src_file ), 'cropped-' . basename( $src_file ), $src_file );
49
50         /*
51          * The directory containing the original file may no longer exist when
52          * using a replication plugin.
53          */
54         wp_mkdir_p( dirname( $dst_file ) );
55
56         $dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), basename( $dst_file ) );
57
58         $result = $editor->save( $dst_file );
59         if ( is_wp_error( $result ) )
60                 return $result;
61
62         return $dst_file;
63 }
64
65 /**
66  * Generate post thumbnail attachment meta data.
67  *
68  * @since 2.1.0
69  *
70  * @param int $attachment_id Attachment Id to process.
71  * @param string $file Filepath of the Attached image.
72  * @return mixed Metadata for attachment.
73  */
74 function wp_generate_attachment_metadata( $attachment_id, $file ) {
75         $attachment = get_post( $attachment_id );
76
77         $metadata = array();
78         $support = false;
79         $mime_type = get_post_mime_type( $attachment );
80
81         if ( preg_match( '!^image/!', $mime_type ) && file_is_displayable_image( $file ) ) {
82                 $imagesize = getimagesize( $file );
83                 $metadata['width'] = $imagesize[0];
84                 $metadata['height'] = $imagesize[1];
85
86                 // Make the file path relative to the upload dir.
87                 $metadata['file'] = _wp_relative_upload_path($file);
88
89                 // Make thumbnails and other intermediate sizes.
90                 $_wp_additional_image_sizes = wp_get_additional_image_sizes();
91
92                 $sizes = array();
93                 foreach ( get_intermediate_image_sizes() as $s ) {
94                         $sizes[$s] = array( 'width' => '', 'height' => '', 'crop' => false );
95                         if ( isset( $_wp_additional_image_sizes[$s]['width'] ) ) {
96                                 // For theme-added sizes
97                                 $sizes[$s]['width'] = intval( $_wp_additional_image_sizes[$s]['width'] );
98                         } else {
99                                 // For default sizes set in options
100                                 $sizes[$s]['width'] = get_option( "{$s}_size_w" );
101                         }
102
103                         if ( isset( $_wp_additional_image_sizes[$s]['height'] ) ) {
104                                 // For theme-added sizes
105                                 $sizes[$s]['height'] = intval( $_wp_additional_image_sizes[$s]['height'] );
106                         } else {
107                                 // For default sizes set in options
108                                 $sizes[$s]['height'] = get_option( "{$s}_size_h" );
109                         }
110
111                         if ( isset( $_wp_additional_image_sizes[$s]['crop'] ) ) {
112                                 // For theme-added sizes
113                                 $sizes[$s]['crop'] = $_wp_additional_image_sizes[$s]['crop'];
114                         } else {
115                                 // For default sizes set in options
116                                 $sizes[$s]['crop'] = get_option( "{$s}_crop" );
117                         }
118                 }
119
120                 /**
121                  * Filters the image sizes automatically generated when uploading an image.
122                  *
123                  * @since 2.9.0
124                  * @since 4.4.0 Added the `$metadata` argument.
125                  *
126                  * @param array $sizes    An associative array of image sizes.
127                  * @param array $metadata An associative array of image metadata: width, height, file.
128                  */
129                 $sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes, $metadata );
130
131                 if ( $sizes ) {
132                         $editor = wp_get_image_editor( $file );
133
134                         if ( ! is_wp_error( $editor ) )
135                                 $metadata['sizes'] = $editor->multi_resize( $sizes );
136                 } else {
137                         $metadata['sizes'] = array();
138                 }
139
140                 // Fetch additional metadata from EXIF/IPTC.
141                 $image_meta = wp_read_image_metadata( $file );
142                 if ( $image_meta )
143                         $metadata['image_meta'] = $image_meta;
144
145         } elseif ( wp_attachment_is( 'video', $attachment ) ) {
146                 $metadata = wp_read_video_metadata( $file );
147                 $support = current_theme_supports( 'post-thumbnails', 'attachment:video' ) || post_type_supports( 'attachment:video', 'thumbnail' );
148         } elseif ( wp_attachment_is( 'audio', $attachment ) ) {
149                 $metadata = wp_read_audio_metadata( $file );
150                 $support = current_theme_supports( 'post-thumbnails', 'attachment:audio' ) || post_type_supports( 'attachment:audio', 'thumbnail' );
151         }
152
153         if ( $support && ! empty( $metadata['image']['data'] ) ) {
154                 // Check for existing cover.
155                 $hash = md5( $metadata['image']['data'] );
156                 $posts = get_posts( array(
157                         'fields' => 'ids',
158                         'post_type' => 'attachment',
159                         'post_mime_type' => $metadata['image']['mime'],
160                         'post_status' => 'inherit',
161                         'posts_per_page' => 1,
162                         'meta_key' => '_cover_hash',
163                         'meta_value' => $hash
164                 ) );
165                 $exists = reset( $posts );
166
167                 if ( ! empty( $exists ) ) {
168                         update_post_meta( $attachment_id, '_thumbnail_id', $exists );
169                 } else {
170                         $ext = '.jpg';
171                         switch ( $metadata['image']['mime'] ) {
172                         case 'image/gif':
173                                 $ext = '.gif';
174                                 break;
175                         case 'image/png':
176                                 $ext = '.png';
177                                 break;
178                         }
179                         $basename = str_replace( '.', '-', basename( $file ) ) . '-image' . $ext;
180                         $uploaded = wp_upload_bits( $basename, '', $metadata['image']['data'] );
181                         if ( false === $uploaded['error'] ) {
182                                 $image_attachment = array(
183                                         'post_mime_type' => $metadata['image']['mime'],
184                                         'post_type' => 'attachment',
185                                         'post_content' => '',
186                                 );
187                                 /**
188                                  * Filters the parameters for the attachment thumbnail creation.
189                                  *
190                                  * @since 3.9.0
191                                  *
192                                  * @param array $image_attachment An array of parameters to create the thumbnail.
193                                  * @param array $metadata         Current attachment metadata.
194                                  * @param array $uploaded         An array containing the thumbnail path and url.
195                                  */
196                                 $image_attachment = apply_filters( 'attachment_thumbnail_args', $image_attachment, $metadata, $uploaded );
197
198                                 $sub_attachment_id = wp_insert_attachment( $image_attachment, $uploaded['file'] );
199                                 add_post_meta( $sub_attachment_id, '_cover_hash', $hash );
200                                 $attach_data = wp_generate_attachment_metadata( $sub_attachment_id, $uploaded['file'] );
201                                 wp_update_attachment_metadata( $sub_attachment_id, $attach_data );
202                                 update_post_meta( $attachment_id, '_thumbnail_id', $sub_attachment_id );
203                         }
204                 }
205         }
206         // Try to create image thumbnails for PDFs
207         else if ( 'application/pdf' === $mime_type ) {
208                 $fallback_sizes = array(
209                         'thumbnail',
210                         'medium',
211                         'large',
212                 );
213
214                 /**
215                  * Filters the image sizes generated for non-image mime types.
216                  *
217                  * @since 4.7.0
218                  *
219                  * @param array $fallback_sizes An array of image size names.
220                  */
221                 $fallback_sizes = apply_filters( 'fallback_intermediate_image_sizes', $fallback_sizes, $metadata );
222
223                 $sizes = array();
224
225                 foreach ( $fallback_sizes as $s ) {
226                         $sizes[ $s ]['width']  = get_option( "{$s}_size_w" );
227                         $sizes[ $s ]['height'] = get_option( "{$s}_size_h" );
228
229                         // Force thumbnails to be soft crops.
230                         if ( ! 'thumbnail' === $s ) {
231                                 $sizes[ $s ]['crop'] = get_option( "{$s}_crop" );
232                         }
233                 }
234
235                 // Only load PDFs in an image editor if we're processing sizes.
236                 if ( ! empty( $sizes ) ) {
237                         $editor = wp_get_image_editor( $file );
238
239                         if ( ! is_wp_error( $editor ) ) { // No support for this type of file
240                                 $uploaded = $editor->save( $file, 'image/jpeg' );
241                                 unset( $editor );
242
243                                 // Resize based on the full size image, rather than the source.
244                                 if ( ! is_wp_error( $uploaded ) ) {
245                                         $editor = wp_get_image_editor( $uploaded['path'] );
246                                         unset( $uploaded['path'] );
247
248                                         if ( ! is_wp_error( $editor ) ) {
249                                                 $metadata['sizes'] = $editor->multi_resize( $sizes );
250                                                 $metadata['sizes']['full'] = $uploaded;
251                                         }
252                                 }
253                         }
254                 }
255         }
256
257         // Remove the blob of binary data from the array.
258         if ( $metadata ) {
259                 unset( $metadata['image']['data'] );
260         }
261
262         /**
263          * Filters the generated attachment meta data.
264          *
265          * @since 2.1.0
266          *
267          * @param array $metadata      An array of attachment meta data.
268          * @param int   $attachment_id Current attachment ID.
269          */
270         return apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id );
271 }
272
273 /**
274  * Convert a fraction string to a decimal.
275  *
276  * @since 2.5.0
277  *
278  * @param string $str
279  * @return int|float
280  */
281 function wp_exif_frac2dec($str) {
282         @list( $n, $d ) = explode( '/', $str );
283         if ( !empty($d) )
284                 return $n / $d;
285         return $str;
286 }
287
288 /**
289  * Convert the exif date format to a unix timestamp.
290  *
291  * @since 2.5.0
292  *
293  * @param string $str
294  * @return int
295  */
296 function wp_exif_date2ts($str) {
297         @list( $date, $time ) = explode( ' ', trim($str) );
298         @list( $y, $m, $d ) = explode( ':', $date );
299
300         return strtotime( "{$y}-{$m}-{$d} {$time}" );
301 }
302
303 /**
304  * Get extended image metadata, exif or iptc as available.
305  *
306  * Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso
307  * created_timestamp, focal_length, shutter_speed, and title.
308  *
309  * The IPTC metadata that is retrieved is APP13, credit, byline, created date
310  * and time, caption, copyright, and title. Also includes FNumber, Model,
311  * DateTimeDigitized, FocalLength, ISOSpeedRatings, and ExposureTime.
312  *
313  * @todo Try other exif libraries if available.
314  * @since 2.5.0
315  *
316  * @param string $file
317  * @return bool|array False on failure. Image metadata array on success.
318  */
319 function wp_read_image_metadata( $file ) {
320         if ( ! file_exists( $file ) )
321                 return false;
322
323         list( , , $sourceImageType ) = getimagesize( $file );
324
325         /*
326          * EXIF contains a bunch of data we'll probably never need formatted in ways
327          * that are difficult to use. We'll normalize it and just extract the fields
328          * that are likely to be useful. Fractions and numbers are converted to
329          * floats, dates to unix timestamps, and everything else to strings.
330          */
331         $meta = array(
332                 'aperture' => 0,
333                 'credit' => '',
334                 'camera' => '',
335                 'caption' => '',
336                 'created_timestamp' => 0,
337                 'copyright' => '',
338                 'focal_length' => 0,
339                 'iso' => 0,
340                 'shutter_speed' => 0,
341                 'title' => '',
342                 'orientation' => 0,
343                 'keywords' => array(),
344         );
345
346         $iptc = array();
347         /*
348          * Read IPTC first, since it might contain data not available in exif such
349          * as caption, description etc.
350          */
351         if ( is_callable( 'iptcparse' ) ) {
352                 getimagesize( $file, $info );
353
354                 if ( ! empty( $info['APP13'] ) ) {
355                         $iptc = iptcparse( $info['APP13'] );
356
357                         // Headline, "A brief synopsis of the caption."
358                         if ( ! empty( $iptc['2#105'][0] ) ) {
359                                 $meta['title'] = trim( $iptc['2#105'][0] );
360                         /*
361                          * Title, "Many use the Title field to store the filename of the image,
362                          * though the field may be used in many ways."
363                          */
364                         } elseif ( ! empty( $iptc['2#005'][0] ) ) {
365                                 $meta['title'] = trim( $iptc['2#005'][0] );
366                         }
367
368                         if ( ! empty( $iptc['2#120'][0] ) ) { // description / legacy caption
369                                 $caption = trim( $iptc['2#120'][0] );
370
371                                 mbstring_binary_safe_encoding();
372                                 $caption_length = strlen( $caption );
373                                 reset_mbstring_encoding();
374
375                                 if ( empty( $meta['title'] ) && $caption_length < 80 ) {
376                                         // Assume the title is stored in 2:120 if it's short.
377                                         $meta['title'] = $caption;
378                                 }
379
380                                 $meta['caption'] = $caption;
381                         }
382
383                         if ( ! empty( $iptc['2#110'][0] ) ) // credit
384                                 $meta['credit'] = trim( $iptc['2#110'][0] );
385                         elseif ( ! empty( $iptc['2#080'][0] ) ) // creator / legacy byline
386                                 $meta['credit'] = trim( $iptc['2#080'][0] );
387
388                         if ( ! empty( $iptc['2#055'][0] ) && ! empty( $iptc['2#060'][0] ) ) // created date and time
389                                 $meta['created_timestamp'] = strtotime( $iptc['2#055'][0] . ' ' . $iptc['2#060'][0] );
390
391                         if ( ! empty( $iptc['2#116'][0] ) ) // copyright
392                                 $meta['copyright'] = trim( $iptc['2#116'][0] );
393
394                         if ( ! empty( $iptc['2#025'][0] ) ) { // keywords array
395                                 $meta['keywords'] = array_values( $iptc['2#025'] );
396                         }
397                  }
398         }
399
400         /**
401          * Filters the image types to check for exif data.
402          *
403          * @since 2.5.0
404          *
405          * @param array $image_types Image types to check for exif data.
406          */
407         if ( is_callable( 'exif_read_data' ) && in_array( $sourceImageType, apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ) ) ) {
408                 $exif = @exif_read_data( $file );
409
410                 if ( ! empty( $exif['ImageDescription'] ) ) {
411                         mbstring_binary_safe_encoding();
412                         $description_length = strlen( $exif['ImageDescription'] );
413                         reset_mbstring_encoding();
414
415                         if ( empty( $meta['title'] ) && $description_length < 80 ) {
416                                 // Assume the title is stored in ImageDescription
417                                 $meta['title'] = trim( $exif['ImageDescription'] );
418                         }
419
420                         if ( empty( $meta['caption'] ) && ! empty( $exif['COMPUTED']['UserComment'] ) ) {
421                                 $meta['caption'] = trim( $exif['COMPUTED']['UserComment'] );
422                         }
423
424                         if ( empty( $meta['caption'] ) ) {
425                                 $meta['caption'] = trim( $exif['ImageDescription'] );
426                         }
427                 } elseif ( empty( $meta['caption'] ) && ! empty( $exif['Comments'] ) ) {
428                         $meta['caption'] = trim( $exif['Comments'] );
429                 }
430
431                 if ( empty( $meta['credit'] ) ) {
432                         if ( ! empty( $exif['Artist'] ) ) {
433                                 $meta['credit'] = trim( $exif['Artist'] );
434                         } elseif ( ! empty($exif['Author'] ) ) {
435                                 $meta['credit'] = trim( $exif['Author'] );
436                         }
437                 }
438
439                 if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) {
440                         $meta['copyright'] = trim( $exif['Copyright'] );
441                 }
442                 if ( ! empty( $exif['FNumber'] ) ) {
443                         $meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 );
444                 }
445                 if ( ! empty( $exif['Model'] ) ) {
446                         $meta['camera'] = trim( $exif['Model'] );
447                 }
448                 if ( empty( $meta['created_timestamp'] ) && ! empty( $exif['DateTimeDigitized'] ) ) {
449                         $meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] );
450                 }
451                 if ( ! empty( $exif['FocalLength'] ) ) {
452                         $meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
453                 }
454                 if ( ! empty( $exif['ISOSpeedRatings'] ) ) {
455                         $meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings'];
456                         $meta['iso'] = trim( $meta['iso'] );
457                 }
458                 if ( ! empty( $exif['ExposureTime'] ) ) {
459                         $meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
460                 }
461                 if ( ! empty( $exif['Orientation'] ) ) {
462                         $meta['orientation'] = $exif['Orientation'];
463                 }
464         }
465
466         foreach ( array( 'title', 'caption', 'credit', 'copyright', 'camera', 'iso' ) as $key ) {
467                 if ( $meta[ $key ] && ! seems_utf8( $meta[ $key ] ) ) {
468                         $meta[ $key ] = utf8_encode( $meta[ $key ] );
469                 }
470         }
471
472         foreach ( $meta['keywords'] as $key => $keyword ) {
473                 if ( ! seems_utf8( $keyword ) ) {
474                         $meta['keywords'][ $key ] = utf8_encode( $keyword );
475                 }
476         }
477
478         $meta = wp_kses_post_deep( $meta );
479
480         /**
481          * Filters the array of meta data read from an image's exif data.
482          *
483          * @since 2.5.0
484          * @since 4.4.0 The `$iptc` parameter was added.
485          *
486          * @param array  $meta            Image meta data.
487          * @param string $file            Path to image file.
488          * @param int    $sourceImageType Type of image.
489          * @param array  $iptc            IPTC data.
490          */
491         return apply_filters( 'wp_read_image_metadata', $meta, $file, $sourceImageType, $iptc );
492
493 }
494
495 /**
496  * Validate that file is an image.
497  *
498  * @since 2.5.0
499  *
500  * @param string $path File path to test if valid image.
501  * @return bool True if valid image, false if not valid image.
502  */
503 function file_is_valid_image($path) {
504         $size = @getimagesize($path);
505         return !empty($size);
506 }
507
508 /**
509  * Validate that file is suitable for displaying within a web page.
510  *
511  * @since 2.5.0
512  *
513  * @param string $path File path to test.
514  * @return bool True if suitable, false if not suitable.
515  */
516 function file_is_displayable_image($path) {
517         $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP );
518
519         $info = @getimagesize( $path );
520         if ( empty( $info ) ) {
521                 $result = false;
522         } elseif ( ! in_array( $info[2], $displayable_image_types ) ) {
523                 $result = false;
524         } else {
525                 $result = true;
526         }
527
528         /**
529          * Filters whether the current image is displayable in the browser.
530          *
531          * @since 2.5.0
532          *
533          * @param bool   $result Whether the image can be displayed. Default true.
534          * @param string $path   Path to the image.
535          */
536         return apply_filters( 'file_is_displayable_image', $result, $path );
537 }
538
539 /**
540  * Load an image resource for editing.
541  *
542  * @since 2.9.0
543  *
544  * @param string $attachment_id Attachment ID.
545  * @param string $mime_type Image mime type.
546  * @param string $size Optional. Image size, defaults to 'full'.
547  * @return resource|false The resulting image resource on success, false on failure.
548  */
549 function load_image_to_edit( $attachment_id, $mime_type, $size = 'full' ) {
550         $filepath = _load_image_to_edit_path( $attachment_id, $size );
551         if ( empty( $filepath ) )
552                 return false;
553
554         switch ( $mime_type ) {
555                 case 'image/jpeg':
556                         $image = imagecreatefromjpeg($filepath);
557                         break;
558                 case 'image/png':
559                         $image = imagecreatefrompng($filepath);
560                         break;
561                 case 'image/gif':
562                         $image = imagecreatefromgif($filepath);
563                         break;
564                 default:
565                         $image = false;
566                         break;
567         }
568         if ( is_resource($image) ) {
569                 /**
570                  * Filters the current image being loaded for editing.
571                  *
572                  * @since 2.9.0
573                  *
574                  * @param resource $image         Current image.
575                  * @param string   $attachment_id Attachment ID.
576                  * @param string   $size          Image size.
577                  */
578                 $image = apply_filters( 'load_image_to_edit', $image, $attachment_id, $size );
579                 if ( function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
580                         imagealphablending($image, false);
581                         imagesavealpha($image, true);
582                 }
583         }
584         return $image;
585 }
586
587 /**
588  * Retrieve the path or url of an attachment's attached file.
589  *
590  * If the attached file is not present on the local filesystem (usually due to replication plugins),
591  * then the url of the file is returned if url fopen is supported.
592  *
593  * @since 3.4.0
594  * @access private
595  *
596  * @param string $attachment_id Attachment ID.
597  * @param string $size Optional. Image size, defaults to 'full'.
598  * @return string|false File path or url on success, false on failure.
599  */
600 function _load_image_to_edit_path( $attachment_id, $size = 'full' ) {
601         $filepath = get_attached_file( $attachment_id );
602
603         if ( $filepath && file_exists( $filepath ) ) {
604                 if ( 'full' != $size && ( $data = image_get_intermediate_size( $attachment_id, $size ) ) ) {
605                         /**
606                          * Filters the path to the current image.
607                          *
608                          * The filter is evaluated for all image sizes except 'full'.
609                          *
610                          * @since 3.1.0
611                          *
612                          * @param string $path          Path to the current image.
613                          * @param string $attachment_id Attachment ID.
614                          * @param string $size          Size of the image.
615                          */
616                         $filepath = apply_filters( 'load_image_to_edit_filesystempath', path_join( dirname( $filepath ), $data['file'] ), $attachment_id, $size );
617                 }
618         } elseif ( function_exists( 'fopen' ) && true == ini_get( 'allow_url_fopen' ) ) {
619                 /**
620                  * Filters the image URL if not in the local filesystem.
621                  *
622                  * The filter is only evaluated if fopen is enabled on the server.
623                  *
624                  * @since 3.1.0
625                  *
626                  * @param string $image_url     Current image URL.
627                  * @param string $attachment_id Attachment ID.
628                  * @param string $size          Size of the image.
629                  */
630                 $filepath = apply_filters( 'load_image_to_edit_attachmenturl', wp_get_attachment_url( $attachment_id ), $attachment_id, $size );
631         }
632
633         /**
634          * Filters the returned path or URL of the current image.
635          *
636          * @since 2.9.0
637          *
638          * @param string|bool $filepath      File path or URL to current image, or false.
639          * @param string      $attachment_id Attachment ID.
640          * @param string      $size          Size of the image.
641          */
642         return apply_filters( 'load_image_to_edit_path', $filepath, $attachment_id, $size );
643 }
644
645 /**
646  * Copy an existing image file.
647  *
648  * @since 3.4.0
649  * @access private
650  *
651  * @param string $attachment_id Attachment ID.
652  * @return string|false New file path on success, false on failure.
653  */
654 function _copy_image_file( $attachment_id ) {
655         $dst_file = $src_file = get_attached_file( $attachment_id );
656         if ( ! file_exists( $src_file ) )
657                 $src_file = _load_image_to_edit_path( $attachment_id );
658
659         if ( $src_file ) {
660                 $dst_file = str_replace( basename( $dst_file ), 'copy-' . basename( $dst_file ), $dst_file );
661                 $dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), basename( $dst_file ) );
662
663                 /*
664                  * The directory containing the original file may no longer
665                  * exist when using a replication plugin.
666                  */
667                 wp_mkdir_p( dirname( $dst_file ) );
668
669                 if ( ! @copy( $src_file, $dst_file ) )
670                         $dst_file = false;
671         } else {
672                 $dst_file = false;
673         }
674
675         return $dst_file;
676 }