| 541 | |
| 542 | /** |
| 543 | * Changes the size of an image to the given dimensions. |
| 544 | * |
| 545 | * `thumbnailImage` changes the size of an image to the given dimensions and |
| 546 | * removes any associated profiles. The goal is to produce small low cost |
| 547 | * thumbnail images suited for display on the Web. |
| 548 | * |
| 549 | * With the original Imagick thumbnailImage implementation, there is no way to choose a |
| 550 | * resampling filter. This class recreates Imagick’s C implementation and adds this |
| 551 | * additional feature. |
| 552 | * |
| 553 | * @access public |
| 554 | * |
| 555 | * @param integer $columns The number of columns in the output image. 0 = maintain aspect ratio based on $rows. |
| 556 | * @param integer $rows The number of rows in the output image. 0 = maintain aspect ratio based on $columns. |
| 557 | * @param bool $bestfit Treat $columns and $rows as a bounding box in which to fit the image. |
| 558 | * @param bool $fill Fill in the bounding box with the background colour. |
| 559 | * @param integer $filter The resampling filter to use. Refer to the list of filter constants at <http://php.net/manual/en/imagick.constants.php>. |
| 560 | * |
| 561 | * @return bool Indicates whether the operation was performed successfully. |
| 562 | */ |
| 563 | public function thumbnailImage( $columns, $rows, $bestfit = false, $fill = false, $filter = Imagick::FILTER_TRIANGLE ) { |
| 564 | /* |
| 565 | * Sample factor; defined in original ImageMagick thumbnailImage function |
| 566 | * the scale to which the image should be resized using the 'sample' function. |
| 567 | */ |
| 568 | $SampleFactor = 5; |
| 569 | // Filter whitelist. |
| 570 | $filters = array( |
| 571 | Imagick::FILTER_POINT, |
| 572 | Imagick::FILTER_BOX, |
| 573 | Imagick::FILTER_TRIANGLE, |
| 574 | Imagick::FILTER_HERMITE, |
| 575 | Imagick::FILTER_HANNING, |
| 576 | Imagick::FILTER_HAMMING, |
| 577 | Imagick::FILTER_BLACKMAN, |
| 578 | Imagick::FILTER_GAUSSIAN, |
| 579 | Imagick::FILTER_QUADRATIC, |
| 580 | Imagick::FILTER_CUBIC, |
| 581 | Imagick::FILTER_CATROM, |
| 582 | Imagick::FILTER_MITCHELL, |
| 583 | Imagick::FILTER_LANCZOS, |
| 584 | Imagick::FILTER_BESSEL, |
| 585 | Imagick::FILTER_SINC |
| 586 | ); |
| 587 | // Parse parameters given to function. |
| 588 | $columns = (double) $columns; |
| 589 | $rows = (double) $rows; |
| 590 | $bestfit = (bool) $bestfit; |
| 591 | $fill = (bool) $fill; |
| 592 | // We can’t resize to (0,0). |
| 593 | if ( $rows < 1 && $columns < 1 ) { |
| 594 | return false; |
| 595 | } |
| 596 | // Set a default filter if an acceptable one wasn’t passed. |
| 597 | if ( ! in_array( $filter, $filters ) ) { |
| 598 | $filter = Imagick::FILTER_TRIANGLE; |
| 599 | } |
| 600 | // Figure out the output width and height. |
| 601 | $width = (double) $this->image->getImageWidth(); |
| 602 | $height = (double) $this->image->getImageHeight(); |
| 603 | $new_width = $columns; |
| 604 | $new_height = $rows; |
| 605 | $x_factor = $columns / $width; |
| 606 | $y_factor = $rows / $height; |
| 607 | if ( $rows < 1 ) { |
| 608 | $new_height = round( $x_factor * $height ); |
| 609 | } elseif ( $columns < 1 ) { |
| 610 | $new_width = round( $y_factor * $width ); |
| 611 | } |
| 612 | /* |
| 613 | * If bestfit is true, the new_width/new_height of the image will be different than |
| 614 | * the columns/rows parameters; those will define a bounding box in which the image will be fit. |
| 615 | */ |
| 616 | if ( $bestfit && $x_factor > $y_factor ) { |
| 617 | $x_factor = $y_factor; |
| 618 | $new_width = round( $y_factor * $width ); |
| 619 | } elseif ( $bestfit && $y_factor > $x_factor ) { |
| 620 | $y_factor = $x_factor; |
| 621 | $new_height = round( $x_factor * $height ); |
| 622 | } |
| 623 | if ( $new_width < 1 ) { |
| 624 | $new_width = 1; |
| 625 | } |
| 626 | if ( $new_height < 1 ) { |
| 627 | $new_height = 1; |
| 628 | } |
| 629 | /* |
| 630 | * If we’re resizing the image to more than about 1/3 it’s original size |
| 631 | * then just use the resize function. |
| 632 | */ |
| 633 | if ( ( $x_factor * $y_factor ) > 0.1 ) { |
| 634 | $this->image->resizeImage( $new_width, $new_height, $filter, 1 ); |
| 635 | // if we’d be using sample to scale to smaller than 128x128, just use resize |
| 636 | } elseif ( ( ( $SampleFactor * $new_width ) < 128) || ( ( $SampleFactor * $new_height ) < 128 ) ) { |
| 637 | $this->image->resizeImage( $new_width, $new_height, $filter, 1 ); |
| 638 | // otherwise, use sample first, then resize |
| 639 | } else { |
| 640 | $this->image->sampleImage( $SampleFactor * $new_width, $SampleFactor * $new_height ); |
| 641 | $this->image->resizeImage( $new_width, $new_height, $filter, 1 ); |
| 642 | } |
| 643 | // if the alpha channel is not defined, make it opaque |
| 644 | if ( $this->image->getImageAlphaChannel() == Imagick::ALPHACHANNEL_UNDEFINED ) { |
| 645 | $this->image->setImageAlphaChannel( Imagick::ALPHACHANNEL_OPAQUE ); |
| 646 | } |
| 647 | // set the image’s bit depth to 8 bits |
| 648 | $this->image->setImageDepth( 8 ); |
| 649 | // turn off interlacing |
| 650 | $this->image->setInterlaceScheme( Imagick::INTERLACE_NO ); |
| 651 | /* |
| 652 | * In case user wants to fill use extent for it rather than creating a new canvas |
| 653 | * fill out the bounding box. |
| 654 | */ |
| 655 | if ( $bestfit && $fill && ( $new_width != $columns || $new_height != $rows ) ) { |
| 656 | $extent_x = 0; |
| 657 | $extent_y = 0; |
| 658 | if ( $columns > $new_width ) { |
| 659 | $extent_x = ( $columns - $new_width ) / 2; |
| 660 | } |
| 661 | if ( $rows > $new_height ) { |
| 662 | $extent_y = ( $rows - $new_height ) / 2; |
| 663 | } |
| 664 | $this->image->extentImage( $columns, $rows, 0 - $extent_x, $extent_y ); |
| 665 | } |
| 666 | return true; |
| 667 | } |
| 668 | |
| 669 | |
| 670 | /** |
| 671 | * Strip all profiles except color profiles from an image. |
| 672 | * |
| 673 | * @access public |
| 674 | */ |
| 675 | public function strip_profiles() { |
| 676 | foreach ( $this->image->getImageProfiles( '*', true ) as $key => $value ) { |
| 677 | if ( $key != 'icc' && $key != 'icm' ) { |
| 678 | $this->image->removeImageProfile( $key ); |
| 679 | } |
| 680 | } |
| 681 | if ( method_exists( $this, 'deleteImageProperty' ) ) { |
| 682 | $this->image->deleteImageProperty( 'comment' ); |
| 683 | $this->image->deleteImageProperty( 'Thumb::URI' ); |
| 684 | $this->image->deleteImageProperty( 'Thumb::MTime' ); |
| 685 | $this->image->deleteImageProperty( 'Thumb::Size' ); |
| 686 | $this->image->deleteImageProperty( 'Thumb::Mimetype' ); |
| 687 | $this->image->deleteImageProperty( 'software' ); |
| 688 | $this->image->deleteImageProperty( 'Thumb::Image::Width' ); |
| 689 | $this->image->deleteImageProperty( 'Thumb::Image::Height' ); |
| 690 | $this->image->deleteImageProperty( 'Thumb::Document::Pages' ); |
| 691 | } else { |
| 692 | $this->image->setImageProperty( 'comment', '' ); |
| 693 | $this->image->setImageProperty( 'Thumb::URI', '' ); |
| 694 | $this->image->setImageProperty( 'Thumb::MTime', '' ); |
| 695 | $this->image->setImageProperty( 'Thumb::Size', '' ); |
| 696 | $this->image->setImageProperty( 'Thumb::Mimetype', '' ); |
| 697 | $this->image->setImageProperty( 'software', '' ); |
| 698 | $this->image->setImageProperty( 'Thumb::Image::Width', '' ); |
| 699 | $this->image->setImageProperty( 'Thumb::Image::Height', '' ); |
| 700 | $this->image->setImageProperty( 'Thumb::Document::Pages', '' ); |
| 701 | } |
| 702 | } |