[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-admin/includes/ -> image-edit.php (source)

   1  <?php
   2  /**
   3   * WordPress Image Editor
   4   *
   5   * @package WordPress
   6   * @subpackage Administration
   7   */
   8  
   9  /**
  10   * Loads the WP image-editing interface.
  11   *
  12   * @since 2.9.0
  13   *
  14   * @param int         $post_id Post ID.
  15   * @param bool|object $msg     Optional. Message to display for image editor updates or errors.
  16   *                             Default false.
  17   */
  18  function wp_image_editor( $post_id, $msg = false ) {
  19      $nonce     = wp_create_nonce( "image_editor-$post_id" );
  20      $meta      = wp_get_attachment_metadata( $post_id );
  21      $thumb     = image_get_intermediate_size( $post_id, 'thumbnail' );
  22      $sub_sizes = isset( $meta['sizes'] ) && is_array( $meta['sizes'] );
  23      $note      = '';
  24  
  25      if ( isset( $meta['width'], $meta['height'] ) ) {
  26          $big = max( $meta['width'], $meta['height'] );
  27      } else {
  28          die( __( 'Image data does not exist. Please re-upload the image.' ) );
  29      }
  30  
  31      $sizer = $big > 400 ? 400 / $big : 1;
  32  
  33      $backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
  34      $can_restore  = false;
  35      if ( ! empty( $backup_sizes ) && isset( $backup_sizes['full-orig'], $meta['file'] ) ) {
  36          $can_restore = $backup_sizes['full-orig']['file'] != wp_basename( $meta['file'] );
  37      }
  38  
  39      if ( $msg ) {
  40          if ( isset( $msg->error ) ) {
  41              $note = "<div class='error'><p>$msg->error</p></div>";
  42          } elseif ( isset( $msg->msg ) ) {
  43              $note = "<div class='updated'><p>$msg->msg</p></div>";
  44          }
  45      }
  46  
  47      ?>
  48      <div class="imgedit-wrap wp-clearfix">
  49      <div id="imgedit-panel-<?php echo $post_id; ?>">
  50  
  51      <div class="imgedit-settings">
  52      <div class="imgedit-group">
  53      <div class="imgedit-group-top">
  54          <h2><?php _e( 'Scale Image' ); ?></h2>
  55          <button type="button" class="dashicons dashicons-editor-help imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" aria-expanded="false"><span class="screen-reader-text"><?php esc_html_e( 'Scale Image Help' ); ?></span></button>
  56          <div class="imgedit-help">
  57          <p><?php _e( 'You can proportionally scale the original image. For best results, scaling should be done before you crop, flip, or rotate. Images can only be scaled down, not up.' ); ?></p>
  58          </div>
  59          <?php if ( isset( $meta['width'], $meta['height'] ) ) : ?>
  60          <p>
  61              <?php
  62              printf(
  63                  /* translators: %s: Image width and height in pixels. */
  64                  __( 'Original dimensions %s' ),
  65                  $meta['width'] . ' &times; ' . $meta['height']
  66              );
  67              ?>
  68          </p>
  69          <?php endif ?>
  70          <div class="imgedit-submit">
  71  
  72          <fieldset class="imgedit-scale">
  73          <legend><?php _e( 'New dimensions:' ); ?></legend>
  74          <div class="nowrap">
  75          <label for="imgedit-scale-width-<?php echo $post_id; ?>" class="screen-reader-text"><?php _e( 'scale width' ); ?></label>
  76          <input type="text" id="imgedit-scale-width-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1, this)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1, this)" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
  77          <span class="imgedit-separator" aria-hidden="true">&times;</span>
  78          <label for="imgedit-scale-height-<?php echo $post_id; ?>" class="screen-reader-text"><?php _e( 'scale height' ); ?></label>
  79          <input type="text" id="imgedit-scale-height-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0, this)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0, this)" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
  80          <span class="imgedit-scale-warn" id="imgedit-scale-warn-<?php echo $post_id; ?>">!</span>
  81          <input id="imgedit-scale-button" type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'scale')" class="button button-primary" value="<?php esc_attr_e( 'Scale' ); ?>" />
  82          </div>
  83          </fieldset>
  84  
  85          </div>
  86      </div>
  87      </div>
  88  
  89      <?php if ( $can_restore ) { ?>
  90  
  91      <div class="imgedit-group">
  92      <div class="imgedit-group-top">
  93          <h2><button type="button" onclick="imageEdit.toggleHelp(this);" class="button-link"><?php _e( 'Restore Original Image' ); ?> <span class="dashicons dashicons-arrow-down imgedit-help-toggle"></span></button></h2>
  94          <div class="imgedit-help">
  95          <p>
  96              <?php
  97              _e( 'Discard any changes and restore the original image.' );
  98  
  99              if ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) {
 100                  echo ' ' . __( 'Previously edited copies of the image will not be deleted.' );
 101              }
 102              ?>
 103          </p>
 104          <div class="imgedit-submit">
 105          <input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'restore')" class="button button-primary" value="<?php esc_attr_e( 'Restore image' ); ?>" <?php echo $can_restore; ?> />
 106          </div>
 107          </div>
 108      </div>
 109      </div>
 110  
 111      <?php } ?>
 112  
 113      <div class="imgedit-group">
 114      <div class="imgedit-group-top">
 115          <h2><?php _e( 'Image Crop' ); ?></h2>
 116          <button type="button" class="dashicons dashicons-editor-help imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" aria-expanded="false"><span class="screen-reader-text"><?php esc_html_e( 'Image Crop Help' ); ?></span></button>
 117  
 118          <div class="imgedit-help">
 119          <p><?php _e( 'To crop the image, click on it and drag to make your selection.' ); ?></p>
 120  
 121          <p><strong><?php _e( 'Crop Aspect Ratio' ); ?></strong><br />
 122          <?php _e( 'The aspect ratio is the relationship between the width and height. You can preserve the aspect ratio by holding down the shift key while resizing your selection. Use the input box to specify the aspect ratio, e.g. 1:1 (square), 4:3, 16:9, etc.' ); ?></p>
 123  
 124          <p><strong><?php _e( 'Crop Selection' ); ?></strong><br />
 125          <?php _e( 'Once you have made your selection, you can adjust it by entering the size in pixels. The minimum selection size is the thumbnail size as set in the Media settings.' ); ?></p>
 126          </div>
 127      </div>
 128  
 129      <fieldset class="imgedit-crop-ratio">
 130          <legend><?php _e( 'Aspect ratio:' ); ?></legend>
 131          <div class="nowrap">
 132          <label for="imgedit-crop-width-<?php echo $post_id; ?>" class="screen-reader-text"><?php _e( 'crop ratio width' ); ?></label>
 133          <input type="text" id="imgedit-crop-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 0, this)" onblur="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 0, this)" />
 134          <span class="imgedit-separator" aria-hidden="true">:</span>
 135          <label for="imgedit-crop-height-<?php echo $post_id; ?>" class="screen-reader-text"><?php _e( 'crop ratio height' ); ?></label>
 136          <input type="text" id="imgedit-crop-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 1, this)" onblur="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 1, this)" />
 137          </div>
 138      </fieldset>
 139  
 140      <fieldset id="imgedit-crop-sel-<?php echo $post_id; ?>" class="imgedit-crop-sel">
 141          <legend><?php _e( 'Selection:' ); ?></legend>
 142          <div class="nowrap">
 143          <label for="imgedit-sel-width-<?php echo $post_id; ?>" class="screen-reader-text"><?php _e( 'selection width' ); ?></label>
 144          <input type="text" id="imgedit-sel-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>, this)" onblur="imageEdit.setNumSelection(<?php echo $post_id; ?>, this)" />
 145          <span class="imgedit-separator" aria-hidden="true">&times;</span>
 146          <label for="imgedit-sel-height-<?php echo $post_id; ?>" class="screen-reader-text"><?php _e( 'selection height' ); ?></label>
 147          <input type="text" id="imgedit-sel-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>, this)" onblur="imageEdit.setNumSelection(<?php echo $post_id; ?>, this)" />
 148          </div>
 149      </fieldset>
 150  
 151      </div>
 152  
 153      <?php
 154      if ( $thumb && $sub_sizes ) {
 155          $thumb_img = wp_constrain_dimensions( $thumb['width'], $thumb['height'], 160, 120 );
 156          ?>
 157  
 158      <div class="imgedit-group imgedit-applyto">
 159      <div class="imgedit-group-top">
 160          <h2><?php _e( 'Thumbnail Settings' ); ?></h2>
 161          <button type="button" class="dashicons dashicons-editor-help imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" aria-expanded="false"><span class="screen-reader-text"><?php esc_html_e( 'Thumbnail Settings Help' ); ?></span></button>
 162          <p class="imgedit-help"><?php _e( 'You can edit the image while preserving the thumbnail. For example, you may wish to have a square thumbnail that displays just a section of the image.' ); ?></p>
 163      </div>
 164  
 165      <figure class="imgedit-thumbnail-preview">
 166          <img src="<?php echo $thumb['url']; ?>" width="<?php echo $thumb_img[0]; ?>" height="<?php echo $thumb_img[1]; ?>" class="imgedit-size-preview" alt="" draggable="false" />
 167          <figcaption class="imgedit-thumbnail-preview-caption"><?php _e( 'Current thumbnail' ); ?></figcaption>
 168      </figure>
 169  
 170      <div id="imgedit-save-target-<?php echo $post_id; ?>" class="imgedit-save-target">
 171      <fieldset>
 172          <legend><?php _e( 'Apply changes to:' ); ?></legend>
 173  
 174          <span class="imgedit-label">
 175              <input type="radio" id="imgedit-target-all" name="imgedit-target-<?php echo $post_id; ?>" value="all" checked="checked" />
 176              <label for="imgedit-target-all"><?php _e( 'All image sizes' ); ?></label>
 177          </span>
 178  
 179          <span class="imgedit-label">
 180              <input type="radio" id="imgedit-target-thumbnail" name="imgedit-target-<?php echo $post_id; ?>" value="thumbnail" />
 181              <label for="imgedit-target-thumbnail"><?php _e( 'Thumbnail' ); ?></label>
 182          </span>
 183  
 184          <span class="imgedit-label">
 185              <input type="radio" id="imgedit-target-nothumb" name="imgedit-target-<?php echo $post_id; ?>" value="nothumb" />
 186              <label for="imgedit-target-nothumb"><?php _e( 'All sizes except thumbnail' ); ?></label>
 187          </span>
 188      </fieldset>
 189      </div>
 190      </div>
 191  
 192      <?php } ?>
 193  
 194      </div>
 195  
 196      <div class="imgedit-panel-content wp-clearfix">
 197          <?php echo $note; ?>
 198          <div class="imgedit-menu wp-clearfix">
 199              <button type="button" onclick="imageEdit.handleCropToolClick( <?php echo "$post_id, '$nonce'"; ?>, this )" class="imgedit-crop button disabled" disabled><span class="screen-reader-text"><?php esc_html_e( 'Crop' ); ?></span></button>
 200              <?php
 201  
 202              // On some setups GD library does not provide imagerotate() - Ticket #11536
 203              if ( wp_image_editor_supports(
 204                  array(
 205                      'mime_type' => get_post_mime_type( $post_id ),
 206                      'methods'   => array( 'rotate' ),
 207                  )
 208              ) ) {
 209                  $note_no_rotate = '';
 210                  ?>
 211                  <button type="button" class="imgedit-rleft button" onclick="imageEdit.rotate( 90, <?php echo "$post_id, '$nonce'"; ?>, this)"><span class="screen-reader-text"><?php esc_html_e( 'Rotate counter-clockwise' ); ?></span></button>
 212                  <button type="button" class="imgedit-rright button" onclick="imageEdit.rotate(-90, <?php echo "$post_id, '$nonce'"; ?>, this)"><span class="screen-reader-text"><?php esc_html_e( 'Rotate clockwise' ); ?></span></button>
 213                  <?php
 214              } else {
 215                  $note_no_rotate = '<p class="note-no-rotate"><em>' . __( 'Image rotation is not supported by your web host.' ) . '</em></p>';
 216                  ?>
 217                  <button type="button" class="imgedit-rleft button disabled" disabled></button>
 218                  <button type="button" class="imgedit-rright button disabled" disabled></button>
 219              <?php } ?>
 220  
 221              <button type="button" onclick="imageEdit.flip(1, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-flipv button"><span class="screen-reader-text"><?php esc_html_e( 'Flip vertically' ); ?></span></button>
 222              <button type="button" onclick="imageEdit.flip(2, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-fliph button"><span class="screen-reader-text"><?php esc_html_e( 'Flip horizontally' ); ?></span></button>
 223  
 224              <button type="button" id="image-undo-<?php echo $post_id; ?>" onclick="imageEdit.undo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-undo button disabled" disabled><span class="screen-reader-text"><?php esc_html_e( 'Undo' ); ?></span></button>
 225              <button type="button" id="image-redo-<?php echo $post_id; ?>" onclick="imageEdit.redo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-redo button disabled" disabled><span class="screen-reader-text"><?php esc_html_e( 'Redo' ); ?></span></button>
 226              <?php echo $note_no_rotate; ?>
 227          </div>
 228  
 229          <input type="hidden" id="imgedit-sizer-<?php echo $post_id; ?>" value="<?php echo $sizer; ?>" />
 230          <input type="hidden" id="imgedit-history-<?php echo $post_id; ?>" value="" />
 231          <input type="hidden" id="imgedit-undone-<?php echo $post_id; ?>" value="0" />
 232          <input type="hidden" id="imgedit-selection-<?php echo $post_id; ?>" value="" />
 233          <input type="hidden" id="imgedit-x-<?php echo $post_id; ?>" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
 234          <input type="hidden" id="imgedit-y-<?php echo $post_id; ?>" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
 235  
 236          <div id="imgedit-crop-<?php echo $post_id; ?>" class="imgedit-crop-wrap">
 237          <img id="image-preview-<?php echo $post_id; ?>" onload="imageEdit.imgLoaded('<?php echo $post_id; ?>')" src="<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>?action=imgedit-preview&amp;_ajax_nonce=<?php echo $nonce; ?>&amp;postid=<?php echo $post_id; ?>&amp;rand=<?php echo rand( 1, 99999 ); ?>" alt="" />
 238          </div>
 239  
 240          <div class="imgedit-submit">
 241              <input type="button" onclick="imageEdit.close(<?php echo $post_id; ?>, 1)" class="button imgedit-cancel-btn" value="<?php esc_attr_e( 'Cancel' ); ?>" />
 242              <input type="button" onclick="imageEdit.save(<?php echo "$post_id, '$nonce'"; ?>)" disabled="disabled" class="button button-primary imgedit-submit-btn" value="<?php esc_attr_e( 'Save' ); ?>" />
 243          </div>
 244      </div>
 245  
 246      </div>
 247      <div class="imgedit-wait" id="imgedit-wait-<?php echo $post_id; ?>"></div>
 248      <div class="hidden" id="imgedit-leaving-<?php echo $post_id; ?>"><?php _e( "There are unsaved changes that will be lost. 'OK' to continue, 'Cancel' to return to the Image Editor." ); ?></div>
 249      </div>
 250      <?php
 251  }
 252  
 253  /**
 254   * Streams image in WP_Image_Editor to browser.
 255   *
 256   * @since 2.9.0
 257   *
 258   * @param WP_Image_Editor $image         The image editor instance.
 259   * @param string          $mime_type     The mime type of the image.
 260   * @param int             $attachment_id The image's attachment post ID.
 261   * @return bool True on success, false on failure.
 262   */
 263  function wp_stream_image( $image, $mime_type, $attachment_id ) {
 264      if ( $image instanceof WP_Image_Editor ) {
 265  
 266          /**
 267           * Filters the WP_Image_Editor instance for the image to be streamed to the browser.
 268           *
 269           * @since 3.5.0
 270           *
 271           * @param WP_Image_Editor $image         The image editor instance.
 272           * @param int             $attachment_id The attachment post ID.
 273           */
 274          $image = apply_filters( 'image_editor_save_pre', $image, $attachment_id );
 275  
 276          if ( is_wp_error( $image->stream( $mime_type ) ) ) {
 277              return false;
 278          }
 279  
 280          return true;
 281      } else {
 282          /* translators: 1: $image, 2: WP_Image_Editor */
 283          _deprecated_argument( __FUNCTION__, '3.5.0', sprintf( __( '%1$s needs to be a %2$s object.' ), '$image', 'WP_Image_Editor' ) );
 284  
 285          /**
 286           * Filters the GD image resource to be streamed to the browser.
 287           *
 288           * @since 2.9.0
 289           * @deprecated 3.5.0 Use image_editor_save_pre instead.
 290           *
 291           * @param resource $image         Image resource to be streamed.
 292           * @param int      $attachment_id The attachment post ID.
 293           */
 294          $image = apply_filters( 'image_save_pre', $image, $attachment_id );
 295  
 296          switch ( $mime_type ) {
 297              case 'image/jpeg':
 298                  header( 'Content-Type: image/jpeg' );
 299                  return imagejpeg( $image, null, 90 );
 300              case 'image/png':
 301                  header( 'Content-Type: image/png' );
 302                  return imagepng( $image );
 303              case 'image/gif':
 304                  header( 'Content-Type: image/gif' );
 305                  return imagegif( $image );
 306              default:
 307                  return false;
 308          }
 309      }
 310  }
 311  
 312  /**
 313   * Saves image to file.
 314   *
 315   * @since 2.9.0
 316   *
 317   * @param string $filename
 318   * @param WP_Image_Editor $image
 319   * @param string $mime_type
 320   * @param int $post_id
 321   * @return bool
 322   */
 323  function wp_save_image_file( $filename, $image, $mime_type, $post_id ) {
 324      if ( $image instanceof WP_Image_Editor ) {
 325  
 326          /** This filter is documented in wp-admin/includes/image-edit.php */
 327          $image = apply_filters( 'image_editor_save_pre', $image, $post_id );
 328  
 329          /**
 330           * Filters whether to skip saving the image file.
 331           *
 332           * Returning a non-null value will short-circuit the save method,
 333           * returning that value instead.
 334           *
 335           * @since 3.5.0
 336           *
 337           * @param mixed           $override  Value to return instead of saving. Default null.
 338           * @param string          $filename  Name of the file to be saved.
 339           * @param WP_Image_Editor $image     WP_Image_Editor instance.
 340           * @param string          $mime_type Image mime type.
 341           * @param int             $post_id   Post ID.
 342           */
 343          $saved = apply_filters( 'wp_save_image_editor_file', null, $filename, $image, $mime_type, $post_id );
 344  
 345          if ( null !== $saved ) {
 346              return $saved;
 347          }
 348  
 349          return $image->save( $filename, $mime_type );
 350      } else {
 351          /* translators: 1: $image, 2: WP_Image_Editor */
 352          _deprecated_argument( __FUNCTION__, '3.5.0', sprintf( __( '%1$s needs to be a %2$s object.' ), '$image', 'WP_Image_Editor' ) );
 353  
 354          /** This filter is documented in wp-admin/includes/image-edit.php */
 355          $image = apply_filters( 'image_save_pre', $image, $post_id );
 356  
 357          /**
 358           * Filters whether to skip saving the image file.
 359           *
 360           * Returning a non-null value will short-circuit the save method,
 361           * returning that value instead.
 362           *
 363           * @since 2.9.0
 364           * @deprecated 3.5.0 Use wp_save_image_editor_file instead.
 365           *
 366           * @param mixed           $override  Value to return instead of saving. Default null.
 367           * @param string          $filename  Name of the file to be saved.
 368           * @param WP_Image_Editor $image     WP_Image_Editor instance.
 369           * @param string          $mime_type Image mime type.
 370           * @param int             $post_id   Post ID.
 371           */
 372          $saved = apply_filters( 'wp_save_image_file', null, $filename, $image, $mime_type, $post_id );
 373  
 374          if ( null !== $saved ) {
 375              return $saved;
 376          }
 377  
 378          switch ( $mime_type ) {
 379              case 'image/jpeg':
 380                  /** This filter is documented in wp-includes/class-wp-image-editor.php */
 381                  return imagejpeg( $image, $filename, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
 382              case 'image/png':
 383                  return imagepng( $image, $filename );
 384              case 'image/gif':
 385                  return imagegif( $image, $filename );
 386              default:
 387                  return false;
 388          }
 389      }
 390  }
 391  
 392  /**
 393   * Image preview ratio. Internal use only.
 394   *
 395   * @since 2.9.0
 396   *
 397   * @ignore
 398   * @param int $w Image width in pixels.
 399   * @param int $h Image height in pixels.
 400   * @return float|int Image preview ratio.
 401   */
 402  function _image_get_preview_ratio( $w, $h ) {
 403      $max = max( $w, $h );
 404      return $max > 400 ? ( 400 / $max ) : 1;
 405  }
 406  
 407  /**
 408   * Returns an image resource. Internal use only.
 409   *
 410   * @since 2.9.0
 411   * @deprecated 3.5.0 Use WP_Image_Editor::rotate()
 412   * @see WP_Image_Editor::rotate()
 413   *
 414   * @ignore
 415   * @param resource  $img   Image resource.
 416   * @param float|int $angle Image rotation angle, in degrees.
 417   * @return resource|false GD image resource, false otherwise.
 418   */
 419  function _rotate_image_resource( $img, $angle ) {
 420      _deprecated_function( __FUNCTION__, '3.5.0', 'WP_Image_Editor::rotate()' );
 421      if ( function_exists( 'imagerotate' ) ) {
 422          $rotated = imagerotate( $img, $angle, 0 );
 423          if ( is_resource( $rotated ) ) {
 424              imagedestroy( $img );
 425              $img = $rotated;
 426          }
 427      }
 428      return $img;
 429  }
 430  
 431  /**
 432   * Flips an image resource. Internal use only.
 433   *
 434   * @since 2.9.0
 435   * @deprecated 3.5.0 Use WP_Image_Editor::flip()
 436   * @see WP_Image_Editor::flip()
 437   *
 438   * @ignore
 439   * @param resource $img  Image resource.
 440   * @param bool     $horz Whether to flip horizontally.
 441   * @param bool     $vert Whether to flip vertically.
 442   * @return resource (maybe) flipped image resource.
 443   */
 444  function _flip_image_resource( $img, $horz, $vert ) {
 445      _deprecated_function( __FUNCTION__, '3.5.0', 'WP_Image_Editor::flip()' );
 446      $w   = imagesx( $img );
 447      $h   = imagesy( $img );
 448      $dst = wp_imagecreatetruecolor( $w, $h );
 449      if ( is_resource( $dst ) ) {
 450          $sx = $vert ? ( $w - 1 ) : 0;
 451          $sy = $horz ? ( $h - 1 ) : 0;
 452          $sw = $vert ? -$w : $w;
 453          $sh = $horz ? -$h : $h;
 454  
 455          if ( imagecopyresampled( $dst, $img, 0, 0, $sx, $sy, $w, $h, $sw, $sh ) ) {
 456              imagedestroy( $img );
 457              $img = $dst;
 458          }
 459      }
 460      return $img;
 461  }
 462  
 463  /**
 464   * Crops an image resource. Internal use only.
 465   *
 466   * @since 2.9.0
 467   *
 468   * @ignore
 469   * @param resource $img Image resource.
 470   * @param float    $x   Source point x-coordinate.
 471   * @param float    $y   Source point y-cooredinate.
 472   * @param float    $w   Source width.
 473   * @param float    $h   Source height.
 474   * @return resource (maybe) cropped image resource.
 475   */
 476  function _crop_image_resource( $img, $x, $y, $w, $h ) {
 477      $dst = wp_imagecreatetruecolor( $w, $h );
 478      if ( is_resource( $dst ) ) {
 479          if ( imagecopy( $dst, $img, 0, 0, $x, $y, $w, $h ) ) {
 480              imagedestroy( $img );
 481              $img = $dst;
 482          }
 483      }
 484      return $img;
 485  }
 486  
 487  /**
 488   * Performs group of changes on Editor specified.
 489   *
 490   * @since 2.9.0
 491   *
 492   * @param WP_Image_Editor $image   WP_Image_Editor instance.
 493   * @param array           $changes Array of change operations.
 494   * @return WP_Image_Editor WP_Image_Editor instance with changes applied.
 495   */
 496  function image_edit_apply_changes( $image, $changes ) {
 497      if ( is_resource( $image ) ) {
 498          /* translators: 1: $image, 2: WP_Image_Editor */
 499          _deprecated_argument( __FUNCTION__, '3.5.0', sprintf( __( '%1$s needs to be a %2$s object.' ), '$image', 'WP_Image_Editor' ) );
 500      }
 501  
 502      if ( ! is_array( $changes ) ) {
 503          return $image;
 504      }
 505  
 506      // Expand change operations.
 507      foreach ( $changes as $key => $obj ) {
 508          if ( isset( $obj->r ) ) {
 509              $obj->type  = 'rotate';
 510              $obj->angle = $obj->r;
 511              unset( $obj->r );
 512          } elseif ( isset( $obj->f ) ) {
 513              $obj->type = 'flip';
 514              $obj->axis = $obj->f;
 515              unset( $obj->f );
 516          } elseif ( isset( $obj->c ) ) {
 517              $obj->type = 'crop';
 518              $obj->sel  = $obj->c;
 519              unset( $obj->c );
 520          }
 521          $changes[ $key ] = $obj;
 522      }
 523  
 524      // Combine operations.
 525      if ( count( $changes ) > 1 ) {
 526          $filtered = array( $changes[0] );
 527          for ( $i = 0, $j = 1, $c = count( $changes ); $j < $c; $j++ ) {
 528              $combined = false;
 529              if ( $filtered[ $i ]->type == $changes[ $j ]->type ) {
 530                  switch ( $filtered[ $i ]->type ) {
 531                      case 'rotate':
 532                          $filtered[ $i ]->angle += $changes[ $j ]->angle;
 533                          $combined               = true;
 534                          break;
 535                      case 'flip':
 536                          $filtered[ $i ]->axis ^= $changes[ $j ]->axis;
 537                          $combined              = true;
 538                          break;
 539                  }
 540              }
 541              if ( ! $combined ) {
 542                  $filtered[ ++$i ] = $changes[ $j ];
 543              }
 544          }
 545          $changes = $filtered;
 546          unset( $filtered );
 547      }
 548  
 549      // Image resource before applying the changes.
 550      if ( $image instanceof WP_Image_Editor ) {
 551  
 552          /**
 553           * Filters the WP_Image_Editor instance before applying changes to the image.
 554           *
 555           * @since 3.5.0
 556           *
 557           * @param WP_Image_Editor $image   WP_Image_Editor instance.
 558           * @param array           $changes Array of change operations.
 559           */
 560          $image = apply_filters( 'wp_image_editor_before_change', $image, $changes );
 561      } elseif ( is_resource( $image ) ) {
 562  
 563          /**
 564           * Filters the GD image resource before applying changes to the image.
 565           *
 566           * @since 2.9.0
 567           * @deprecated 3.5.0 Use wp_image_editor_before_change instead.
 568           *
 569           * @param resource $image   GD image resource.
 570           * @param array    $changes Array of change operations.
 571           */
 572          $image = apply_filters( 'image_edit_before_change', $image, $changes );
 573      }
 574  
 575      foreach ( $changes as $operation ) {
 576          switch ( $operation->type ) {
 577              case 'rotate':
 578                  if ( $operation->angle != 0 ) {
 579                      if ( $image instanceof WP_Image_Editor ) {
 580                          $image->rotate( $operation->angle );
 581                      } else {
 582                          $image = _rotate_image_resource( $image, $operation->angle );
 583                      }
 584                  }
 585                  break;
 586              case 'flip':
 587                  if ( $operation->axis != 0 ) {
 588                      if ( $image instanceof WP_Image_Editor ) {
 589                          $image->flip( ( $operation->axis & 1 ) != 0, ( $operation->axis & 2 ) != 0 );
 590                      } else {
 591                          $image = _flip_image_resource( $image, ( $operation->axis & 1 ) != 0, ( $operation->axis & 2 ) != 0 );
 592                      }
 593                  }
 594                  break;
 595              case 'crop':
 596                  $sel = $operation->sel;
 597  
 598                  if ( $image instanceof WP_Image_Editor ) {
 599                      $size = $image->get_size();
 600                      $w    = $size['width'];
 601                      $h    = $size['height'];
 602  
 603                      $scale = 1 / _image_get_preview_ratio( $w, $h ); // discard preview scaling
 604                      $image->crop( $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
 605                  } else {
 606                      $scale = 1 / _image_get_preview_ratio( imagesx( $image ), imagesy( $image ) ); // discard preview scaling
 607                      $image = _crop_image_resource( $image, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
 608                  }
 609                  break;
 610          }
 611      }
 612  
 613      return $image;
 614  }
 615  
 616  
 617  /**
 618   * Streams image in post to browser, along with enqueued changes
 619   * in $_REQUEST['history']
 620   *
 621   * @since 2.9.0
 622   *
 623   * @param int $post_id
 624   * @return bool
 625   */
 626  function stream_preview_image( $post_id ) {
 627      $post = get_post( $post_id );
 628  
 629      wp_raise_memory_limit( 'admin' );
 630  
 631      $img = wp_get_image_editor( _load_image_to_edit_path( $post_id ) );
 632  
 633      if ( is_wp_error( $img ) ) {
 634          return false;
 635      }
 636  
 637      $changes = ! empty( $_REQUEST['history'] ) ? json_decode( wp_unslash( $_REQUEST['history'] ) ) : null;
 638      if ( $changes ) {
 639          $img = image_edit_apply_changes( $img, $changes );
 640      }
 641  
 642      // Scale the image.
 643      $size = $img->get_size();
 644      $w    = $size['width'];
 645      $h    = $size['height'];
 646  
 647      $ratio = _image_get_preview_ratio( $w, $h );
 648      $w2    = max( 1, $w * $ratio );
 649      $h2    = max( 1, $h * $ratio );
 650  
 651      if ( is_wp_error( $img->resize( $w2, $h2 ) ) ) {
 652          return false;
 653      }
 654  
 655      return wp_stream_image( $img, $post->post_mime_type, $post_id );
 656  }
 657  
 658  /**
 659   * Restores the metadata for a given attachment.
 660   *
 661   * @since 2.9.0
 662   *
 663   * @param int $post_id Attachment post ID.
 664   * @return stdClass Image restoration message object.
 665   */
 666  function wp_restore_image( $post_id ) {
 667      $meta             = wp_get_attachment_metadata( $post_id );
 668      $file             = get_attached_file( $post_id );
 669      $backup_sizes     = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
 670      $old_backup_sizes = $backup_sizes;
 671      $restored         = false;
 672      $msg              = new stdClass;
 673  
 674      if ( ! is_array( $backup_sizes ) ) {
 675          $msg->error = __( 'Cannot load image metadata.' );
 676          return $msg;
 677      }
 678  
 679      $parts         = pathinfo( $file );
 680      $suffix        = time() . rand( 100, 999 );
 681      $default_sizes = get_intermediate_image_sizes();
 682  
 683      if ( isset( $backup_sizes['full-orig'] ) && is_array( $backup_sizes['full-orig'] ) ) {
 684          $data = $backup_sizes['full-orig'];
 685  
 686          if ( $parts['basename'] != $data['file'] ) {
 687              if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE ) {
 688  
 689                  // Delete only if it's an edited image.
 690                  if ( preg_match( '/-e[0-9]{13}\./', $parts['basename'] ) ) {
 691                      wp_delete_file( $file );
 692                  }
 693              } elseif ( isset( $meta['width'], $meta['height'] ) ) {
 694                  $backup_sizes[ "full-$suffix" ] = array(
 695                      'width'  => $meta['width'],
 696                      'height' => $meta['height'],
 697                      'file'   => $parts['basename'],
 698                  );
 699              }
 700          }
 701  
 702          $restored_file = path_join( $parts['dirname'], $data['file'] );
 703          $restored      = update_attached_file( $post_id, $restored_file );
 704  
 705          $meta['file']   = _wp_relative_upload_path( $restored_file );
 706          $meta['width']  = $data['width'];
 707          $meta['height'] = $data['height'];
 708      }
 709  
 710      foreach ( $default_sizes as $default_size ) {
 711          if ( isset( $backup_sizes[ "$default_size-orig" ] ) ) {
 712              $data = $backup_sizes[ "$default_size-orig" ];
 713              if ( isset( $meta['sizes'][ $default_size ] ) && $meta['sizes'][ $default_size ]['file'] != $data['file'] ) {
 714                  if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE ) {
 715  
 716                      // Delete only if it's an edited image.
 717                      if ( preg_match( '/-e[0-9]{13}-/', $meta['sizes'][ $default_size ]['file'] ) ) {
 718                          $delete_file = path_join( $parts['dirname'], $meta['sizes'][ $default_size ]['file'] );
 719                          wp_delete_file( $delete_file );
 720                      }
 721                  } else {
 722                      $backup_sizes[ "$default_size-{$suffix}" ] = $meta['sizes'][ $default_size ];
 723                  }
 724              }
 725  
 726              $meta['sizes'][ $default_size ] = $data;
 727          } else {
 728              unset( $meta['sizes'][ $default_size ] );
 729          }
 730      }
 731  
 732      if ( ! wp_update_attachment_metadata( $post_id, $meta ) ||
 733          ( $old_backup_sizes !== $backup_sizes && ! update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes ) ) ) {
 734  
 735          $msg->error = __( 'Cannot save image metadata.' );
 736          return $msg;
 737      }
 738  
 739      if ( ! $restored ) {
 740          $msg->error = __( 'Image metadata is inconsistent.' );
 741      } else {
 742          $msg->msg = __( 'Image restored successfully.' );
 743      }
 744  
 745      return $msg;
 746  }
 747  
 748  /**
 749   * Saves image to post along with enqueued changes
 750   * in $_REQUEST['history']
 751   *
 752   * @since 2.9.0
 753   *
 754   * @param int $post_id
 755   * @return \stdClass
 756   */
 757  function wp_save_image( $post_id ) {
 758      $_wp_additional_image_sizes = wp_get_additional_image_sizes();
 759  
 760      $return  = new stdClass;
 761      $success = false;
 762      $delete  = false;
 763      $scaled  = false;
 764      $nocrop  = false;
 765      $post    = get_post( $post_id );
 766  
 767      $img = wp_get_image_editor( _load_image_to_edit_path( $post_id, 'full' ) );
 768      if ( is_wp_error( $img ) ) {
 769          $return->error = esc_js( __( 'Unable to create new image.' ) );
 770          return $return;
 771      }
 772  
 773      $fwidth  = ! empty( $_REQUEST['fwidth'] ) ? intval( $_REQUEST['fwidth'] ) : 0;
 774      $fheight = ! empty( $_REQUEST['fheight'] ) ? intval( $_REQUEST['fheight'] ) : 0;
 775      $target  = ! empty( $_REQUEST['target'] ) ? preg_replace( '/[^a-z0-9_-]+/i', '', $_REQUEST['target'] ) : '';
 776      $scale   = ! empty( $_REQUEST['do'] ) && 'scale' == $_REQUEST['do'];
 777  
 778      if ( $scale && $fwidth > 0 && $fheight > 0 ) {
 779          $size = $img->get_size();
 780          $sX   = $size['width'];
 781          $sY   = $size['height'];
 782  
 783          // Check if it has roughly the same w / h ratio.
 784          $diff = round( $sX / $sY, 2 ) - round( $fwidth / $fheight, 2 );
 785          if ( -0.1 < $diff && $diff < 0.1 ) {
 786              // Scale the full size image.
 787              if ( $img->resize( $fwidth, $fheight ) ) {
 788                  $scaled = true;
 789              }
 790          }
 791  
 792          if ( ! $scaled ) {
 793              $return->error = esc_js( __( 'Error while saving the scaled image. Please reload the page and try again.' ) );
 794              return $return;
 795          }
 796      } elseif ( ! empty( $_REQUEST['history'] ) ) {
 797          $changes = json_decode( wp_unslash( $_REQUEST['history'] ) );
 798          if ( $changes ) {
 799              $img = image_edit_apply_changes( $img, $changes );
 800          }
 801      } else {
 802          $return->error = esc_js( __( 'Nothing to save, the image has not changed.' ) );
 803          return $return;
 804      }
 805  
 806      $meta         = wp_get_attachment_metadata( $post_id );
 807      $backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true );
 808  
 809      if ( ! is_array( $meta ) ) {
 810          $return->error = esc_js( __( 'Image data does not exist. Please re-upload the image.' ) );
 811          return $return;
 812      }
 813  
 814      if ( ! is_array( $backup_sizes ) ) {
 815          $backup_sizes = array();
 816      }
 817  
 818      // Generate new filename.
 819      $path = get_attached_file( $post_id );
 820  
 821      $basename = pathinfo( $path, PATHINFO_BASENAME );
 822      $dirname  = pathinfo( $path, PATHINFO_DIRNAME );
 823      $ext      = pathinfo( $path, PATHINFO_EXTENSION );
 824      $filename = pathinfo( $path, PATHINFO_FILENAME );
 825      $suffix   = time() . rand( 100, 999 );
 826  
 827      if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE &&
 828          isset( $backup_sizes['full-orig'] ) && $backup_sizes['full-orig']['file'] != $basename ) {
 829  
 830          if ( 'thumbnail' == $target ) {
 831              $new_path = "{$dirname}/{$filename}-temp.{$ext}";
 832          } else {
 833              $new_path = $path;
 834          }
 835      } else {
 836          while ( true ) {
 837              $filename     = preg_replace( '/-e([0-9]+)$/', '', $filename );
 838              $filename    .= "-e{$suffix}";
 839              $new_filename = "{$filename}.{$ext}";
 840              $new_path     = "{$dirname}/$new_filename";
 841              if ( file_exists( $new_path ) ) {
 842                  $suffix++;
 843              } else {
 844                  break;
 845              }
 846          }
 847      }
 848  
 849      // Save the full-size file, also needed to create sub-sizes.
 850      if ( ! wp_save_image_file( $new_path, $img, $post->post_mime_type, $post_id ) ) {
 851          $return->error = esc_js( __( 'Unable to save the image.' ) );
 852          return $return;
 853      }
 854  
 855      if ( 'nothumb' === $target || 'all' === $target || 'full' === $target || $scaled ) {
 856          $tag = false;
 857          if ( isset( $backup_sizes['full-orig'] ) ) {
 858              if ( ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) && $backup_sizes['full-orig']['file'] !== $basename ) {
 859                  $tag = "full-$suffix";
 860              }
 861          } else {
 862              $tag = 'full-orig';
 863          }
 864  
 865          if ( $tag ) {
 866              $backup_sizes[ $tag ] = array(
 867                  'width'  => $meta['width'],
 868                  'height' => $meta['height'],
 869                  'file'   => $basename,
 870              );
 871          }
 872          $success = ( $path === $new_path ) || update_attached_file( $post_id, $new_path );
 873  
 874          $meta['file'] = _wp_relative_upload_path( $new_path );
 875  
 876          $size           = $img->get_size();
 877          $meta['width']  = $size['width'];
 878          $meta['height'] = $size['height'];
 879  
 880          if ( $success && ( 'nothumb' == $target || 'all' == $target ) ) {
 881              $sizes = get_intermediate_image_sizes();
 882              if ( 'nothumb' == $target ) {
 883                  $sizes = array_diff( $sizes, array( 'thumbnail' ) );
 884              }
 885          }
 886  
 887          $return->fw = $meta['width'];
 888          $return->fh = $meta['height'];
 889      } elseif ( 'thumbnail' == $target ) {
 890          $sizes   = array( 'thumbnail' );
 891          $success = true;
 892          $delete  = true;
 893          $nocrop  = true;
 894      }
 895  
 896      /*
 897       * We need to remove any existing resized image files because
 898       * a new crop or rotate could generate different sizes (and hence, filenames),
 899       * keeping the new resized images from overwriting the existing image files.
 900       * https://core.trac.wordpress.org/ticket/32171
 901       */
 902      if ( defined( 'IMAGE_EDIT_OVERWRITE' ) && IMAGE_EDIT_OVERWRITE && ! empty( $meta['sizes'] ) ) {
 903          foreach ( $meta['sizes'] as $size ) {
 904              if ( ! empty( $size['file'] ) && preg_match( '/-e[0-9]{13}-/', $size['file'] ) ) {
 905                  $delete_file = path_join( $dirname, $size['file'] );
 906                  wp_delete_file( $delete_file );
 907              }
 908          }
 909      }
 910  
 911      if ( isset( $sizes ) ) {
 912          $_sizes = array();
 913  
 914          foreach ( $sizes as $size ) {
 915              $tag = false;
 916              if ( isset( $meta['sizes'][ $size ] ) ) {
 917                  if ( isset( $backup_sizes[ "$size-orig" ] ) ) {
 918                      if ( ( ! defined( 'IMAGE_EDIT_OVERWRITE' ) || ! IMAGE_EDIT_OVERWRITE ) && $backup_sizes[ "$size-orig" ]['file'] != $meta['sizes'][ $size ]['file'] ) {
 919                          $tag = "$size-$suffix";
 920                      }
 921                  } else {
 922                      $tag = "$size-orig";
 923                  }
 924  
 925                  if ( $tag ) {
 926                      $backup_sizes[ $tag ] = $meta['sizes'][ $size ];
 927                  }
 928              }
 929  
 930              if ( isset( $_wp_additional_image_sizes[ $size ] ) ) {
 931                  $width  = intval( $_wp_additional_image_sizes[ $size ]['width'] );
 932                  $height = intval( $_wp_additional_image_sizes[ $size ]['height'] );
 933                  $crop   = ( $nocrop ) ? false : $_wp_additional_image_sizes[ $size ]['crop'];
 934              } else {
 935                  $height = get_option( "{$size}_size_h" );
 936                  $width  = get_option( "{$size}_size_w" );
 937                  $crop   = ( $nocrop ) ? false : get_option( "{$size}_crop" );
 938              }
 939  
 940              $_sizes[ $size ] = array(
 941                  'width'  => $width,
 942                  'height' => $height,
 943                  'crop'   => $crop,
 944              );
 945          }
 946  
 947          $meta['sizes'] = array_merge( $meta['sizes'], $img->multi_resize( $_sizes ) );
 948      }
 949  
 950      unset( $img );
 951  
 952      if ( $success ) {
 953          wp_update_attachment_metadata( $post_id, $meta );
 954          update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes );
 955  
 956          if ( $target == 'thumbnail' || $target == 'all' || $target == 'full' ) {
 957              // Check if it's an image edit from attachment edit screen
 958              if ( ! empty( $_REQUEST['context'] ) && 'edit-attachment' == $_REQUEST['context'] ) {
 959                  $thumb_url         = wp_get_attachment_image_src( $post_id, array( 900, 600 ), true );
 960                  $return->thumbnail = $thumb_url[0];
 961              } else {
 962                  $file_url = wp_get_attachment_url( $post_id );
 963                  if ( ! empty( $meta['sizes']['thumbnail'] ) ) {
 964                      $thumb             = $meta['sizes']['thumbnail'];
 965                      $return->thumbnail = path_join( dirname( $file_url ), $thumb['file'] );
 966                  } else {
 967                      $return->thumbnail = "$file_url?w=128&h=128";
 968                  }
 969              }
 970          }
 971      } else {
 972          $delete = true;
 973      }
 974  
 975      if ( $delete ) {
 976          wp_delete_file( $new_path );
 977      }
 978  
 979      $return->msg = esc_js( __( 'Image saved' ) );
 980      return $return;
 981  }


Generated: Wed Sep 18 01:00:03 2019 Cross-referenced by PHPXref 0.7.1