WordPress.org

Make WordPress Core

Ticket #28474: 28474.2.diff

File 28474.2.diff, 7.0 KB (added by markoheijnen, 6 years ago)
  • src/wp-includes/class-wp-image-editor-gd.php

     
    486486
    487487                return parent::make_image( $filename, $function, $arguments );
    488488        }
     489
     490        public function is_animated() {
     491                if ( null === $this->animated ) {
     492                        if ( 'image/jpg' === $this->mime_type ) {
     493                                $this->animated = false;
     494                        }
     495                        else if ( ! ( $fh = @fopen( $this->file, 'rb' ) ) ) {
     496                                $this->animated = false;
     497                        }
     498                        else {
     499                                $count = 0;
     500                                //an animated gif contains multiple "frames", with each frame having a
     501                                //header made up of:
     502                                // * a static 4-byte sequence (\x00\x21\xF9\x04)
     503                                // * 4 variable bytes
     504                                // * a static 2-byte sequence (\x00\x2C)
     505
     506                                // We read through the file til we reach the end of the file, or we've found
     507                                // at least 2 frame headers
     508                                while( ! feof($fh) && $count < 2 ) {
     509                                        $chunk  = fread( $fh, 1024 * 100 ); //read 100kb at a time
     510                                        $count += preg_match_all( '#\x00\x21\xF9\x04.{4}\x00[\x2C\x21]#s', $chunk, $matches );
     511                                }
     512
     513                                fclose($fh);
     514
     515                                $this->animated = $count > 1;
     516                        }
     517                }
     518
     519                return $this->animated;
     520        }
     521
    489522}
  • src/wp-includes/class-wp-image-editor-imagick.php

     
    139139                        if ( ! $this->image->valid() )
    140140                                return new WP_Error( 'invalid_image', __('File is not an image.'), $this->file);
    141141
     142                        // We need to check to see if image is animated before we set the index, or else it returns false.
     143                        // For animation to be supported, also getImageBlob, writeImages, coalesceImages and optimizeImageLayers are required.
     144                        // While coalesceImages seems to be supported far back, optimizeImageLayers is not.
     145                        if ( method_exists( $this->image, 'coalesceImages' ) ) {
     146                                $this->animated = (bool) ( count( $this->image->coalesceImages() ) - 1);
     147                        }
     148                        else {
     149                                $this->animated = false;
     150                        }
     151
    142152                        // Select the first frame to handle animated images properly
    143153                        if ( is_callable( array( $this->image, 'setIteratorIndex' ) ) )
    144154                                $this->image->setIteratorIndex(0);
     
    250260                }
    251261
    252262                try {
    253                         /**
    254                          * @TODO: Thumbnail is more efficient, given a newer version of Imagemagick.
    255                          * $this->image->thumbnailImage( $dst_w, $dst_h );
    256                          */
    257                         $this->image->scaleImage( $dst_w, $dst_h );
     263                        if ( $this->animated ) {
     264                                $this->image = $this->image->coalesceImages();
     265                        }
     266
     267                        foreach ($this->image as $frame) {
     268                                /**
     269                                 * @TODO: Thumbnail is more efficient, given a newer version of Imagemagick.
     270                                 * $this->image->thumbnailImage( $dst_w, $dst_h );
     271                                 */
     272                                $frame->scaleImage( $dst_w, $dst_h );
     273                        }
     274
     275                        # $this->deconstructImages(); or $this->optimizeImageLayers();
     276                        if ( $this->animated ) {
     277                                $this->image = $this->image->optimizeImageLayers();
     278                        }
    258279                }
    259280                catch ( Exception $e ) {
    260281                        return new WP_Error( 'image_resize_error', $e->getMessage() );
     
    356377                }
    357378
    358379                try {
    359                         $this->image->cropImage( $src_w, $src_h, $src_x, $src_y );
    360                         $this->image->setImagePage( $src_w, $src_h, 0, 0);
     380                        if ( $this->animated ) {
     381                                $this->image = $this->image->coalesceImages();
     382                        }
    361383
    362                         if ( $dst_w || $dst_h ) {
    363                                 // If destination width/height isn't specified, use same as
    364                                 // width/height from source.
    365                                 if ( ! $dst_w )
     384                        foreach ($this->image as $frame) {
     385                                $frame->cropImage( $src_w, $src_h, $src_x, $src_y );
     386                                $frame->setImagePage( $src_w, $src_h, 0, 0);
     387
     388                                if ( $dst_w || $dst_h ) {
     389                                        // If destination width/height isn't specified, use same as
     390                                        // width/height from source.
     391                                        if ( ! $dst_w )
    366392                                        $dst_w = $src_w;
    367                                 if ( ! $dst_h )
    368                                         $dst_h = $src_h;
     393                                        if ( ! $dst_h )
     394                                                $dst_h = $src_h;
    369395
    370                                 $this->image->scaleImage( $dst_w, $dst_h );
    371                                 return $this->update_size();
     396                                        $frame->scaleImage( $dst_w, $dst_h );
     397                                }
    372398                        }
     399
     400                        if ( $this->animated ) {
     401                                $this->image = $this->image->optimizeImageLayers();
     402                        }
    373403                }
    374404                catch ( Exception $e ) {
    375405                        return new WP_Error( 'image_crop_error', $e->getMessage() );
     
    392422                 * (GD rotates counter-clockwise)
    393423                 */
    394424                try {
    395                         $this->image->rotateImage( new ImagickPixel('none'), 360-$angle );
     425                        if ( $this->animated ) {
     426                                $this->image = $this->image->coalesceImages();
     427                        }
    396428
     429                        foreach ($this->image as $frame) {
     430                                $frame->rotateImage( new ImagickPixel('none'), 360-$angle );
     431                        }
     432
     433                        if ( $this->animated ) {
     434                                $this->image = $this->image->optimizeImageLayers();
     435                        }
     436
    397437                        // Since this changes the dimensions of the image, update the size.
    398438                        $result = $this->update_size();
    399439                        if ( is_wp_error( $result ) )
     
    419459         */
    420460        public function flip( $horz, $vert ) {
    421461                try {
    422                         if ( $horz )
    423                                 $this->image->flipImage();
     462                        if ( $this->animated ) {
     463                                $this->image = $this->image->coalesceImages();
     464                        }
    424465
    425                         if ( $vert )
    426                                 $this->image->flopImage();
     466                        foreach ($this->image as $frame) {
     467                                if ( $horz )
     468                                        $frame->flipImage();
     469
     470                                if ( $vert )
     471                                        $frame->flopImage();
     472                        }
     473
     474                        if ( $this->animated ) {
     475                                $this->image = $this->image->optimizeImageLayers();
     476                        }
    427477                }
    428478                catch ( Exception $e ) {
    429479                        return new WP_Error( 'image_flip_error', $e->getMessage() );
     
    477527                        $orig_format = $this->image->getImageFormat();
    478528
    479529                        $this->image->setImageFormat( strtoupper( $this->get_extension( $mime_type ) ) );
    480                         $this->make_image( $filename, array( $image, 'writeImage' ), array( $filename ) );
    481530
     531                        if ( $this->animated ) {
     532                                $this->make_image( $filename, array( $image, 'writeImages' ), array( $filename, true ) );
     533                        } else {
     534                                $this->make_image( $filename, array( $image, 'writeImage' ), array( $filename ) );
     535                        }
     536
    482537                        // Reset original Format
    483538                        $this->image->setImageFormat( $orig_format );
    484539                }
     
    519574
    520575                        // Output stream of image content
    521576                        header( "Content-Type: $mime_type" );
    522                         print $this->image->getImageBlob();
    523577
     578                        if ( $this->animated ) {
     579                                print $this->image->getImagesBlob();
     580                        } else {
     581                                print $this->image->getImageBlob();
     582                        }
     583
    524584                        // Reset Image to original Format
    525585                        $this->image->setImageFormat( $this->get_extension( $this->mime_type ) );
    526586                }
  • src/wp-includes/class-wp-image-editor.php

     
    2020        protected $default_quality = 90;
    2121
    2222        /**
     23         * Whether this is an animated image.
     24         *
     25         * @access protected
     26         * @var bool
     27         */
     28        protected $animated = null;
     29
     30        /**
    2331         * Each instance handles a single file.
    2432         *
    2533         * @param string $file Path to the file to load.
     
    491499
    492500                return $extensions[0];
    493501        }
     502
     503        public function is_animated() {
     504                return $this->animated;
     505        }
     506
    494507}
    495508