| | 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 | } |