duanlu1279 2012-11-20 16:49
浏览 126
已采纳

PHP调整图像大小并使用imagemagick裁剪

I'm trying to downsize image uploaded by users at the time of upload.
This is no problem but I want to get specific with sizes now.

I'm looking for some advice on an algorithm im struggling to produce that will take any shape image - square or rectangle of any widths/heights and downsize it.

This image needs to be downsized to a target box size (this changes but is stored in a variable)..
So it needs to downsize the image so that both the width and height are larger than the width and height of the target maintaining aspect ratio. but only just..
The target size will be used to crop the image so there is no white space around the edges etc.

I'm looking for just the algorithm behind creating the correct resize based on different dimension images - I can handle the cropping, even resizing in most cases but it fails in a few so i'm reaching out.

I'm not really asking for PHP code more pseudo. Either is fine obviously.

Thanks Kindly.

Current code.. but I've gone through so many iterations this might not work at all anymore.. :P

$image = $image_orig->clone();
$wRatio = $imageprops['width'] / $dimensions[0];   // imageprops = original image dimens.
$hRatio = $imageprops['height'] / $dimensions[1];  // $dimensions[0] = new width
$maxRatio = max($wRatio,$hRatio);                  // $dimensions[1] = new height

var_dump('thumb');

$ratio = ($imageprops['width'] - $dimensions[0]) > ($imageprops['height'] - $dimensions[1]);
$shape = ($imageprops['width'] > $imageprops['height']);
$error = ($imageprops['width'] / $imageprops['height']);

if( $error < 0.95 || $error > 1.05 ) { // its NOT a square
    if($shape){  // longer width
        $scale = $imageprops['height'] / $dimensions[0];
        var_dump('1');

        $height = $imageprops['height'] / $scale;
        $image->scaleImage(0, $height);
    } else {
        $scale = $imageprops['width'] / $dimensions[1];
        var_dump('2');

        $width = $imageprops['width'] / $scale;
        $image->scaleImage($width, 0);


    }
} elseif($ratio) { // is square
    $scale = $imageprops['height'] / $dimensions[1];
    $newWidth = $imageprops['width'] / $scale;
    $extra = 0;

    $height = $dimensions[1]+$extra;
    $image->scaleImage(0, $height);
} else {
    $scale = $imageprops['width'] / $dimensions[0];
    $newHeight = $imageprops['height'] / $scale;
    $extra = 0;

    $width = $dimensions[0]+$extra;
    $image->scaleImage($width, 0);

}


$image_size = $image->getImageGeometry();

$image->cropImage($dimensions[0], $dimensions[1],($image_size['width']-$dimensions[0])/2,($image_size['height']-$dimensions[1])/2);
  • 写回答

2条回答 默认 最新

  • doupaoshu8334 2012-11-20 17:23
    关注

    Notice: I wrote this answer before the original poster edited his question to include things which clarified points which has since changed what I believed the original question was asking.


    So, there are a few concepts and ideas that you can throw around to try and solve what it is you are intending to achieve. (Gravity Cropping, Content Aware Cropping, Content Aware Rescaling etc)

    Because you are always decreasing the size of the original image, you are essentially just looking to "chop" out a section of the image. Very much like this:

    enter image description here

    The issue however, is that you frequently want to make sure that you select the best region of the image so that you don't crop on an irrelevant segment of the image. This is known as content-aware image cropping, and by just searching using "Content Aware Image Crop" you can find a wealth of information.

    Anyway, moving on, depending on your exact use case, you might discover that actually you don't want to chop out anything form the image, and instead you want to "liquid scale and crop" the image, so that you do "Content Aware Resizing". The difference with content aware resizing is that the resizing ignores all aspect ratios of the image and instead looks at neighbouring edges and colors in order to resize the image in a fluidic way.

    So, luckily enough, Imagick comes with it's very own [liquidRescaleImage][3] function.

    You can use it like

    $im->liquidRescaleImage(480, 260, 3, 18);

    Using Liquid Rescale can rescale out quite nicely. Here is an example below which is anything but perfect, but I purposefully have created an example that isn't perfect so you can actually see that liquidRescale changes the composition of the image, rather than just adjusts the aspect ratio.

    Original

    Original

    Content Aware Liquid Rescale (450x350)

    Rescale

    If however, you just want to scale an image, and keep the aspect ratio, you might want to do what sites such as Flickr do, where they make the images longestLength to be equal to a value. (Flickr for example has 6 or so different dimension sizes)

    We resize your photos to more web-friendly dimensions. Each image has a 75x75 and 150x150 square thumbnail and 100-, 240-, 320-, 500-, 640- 800*-, 1024-, 1600*-, and 2048*-pixel versions (that's the length of the longest side), as well as your original file.

    Basic Class that Replicates the Flickr Resize Policies...

    <?php    
    class Scale {        
        public function getImageScale($x, $y, $longestLength, $allowDistort = false) {
            //Set the default NEW values to be the old, in case it doesn't even need scaling
            list($nx, $ny) = array($x, $y);            
                if ($x > $y) {                   
                    if ($longestLength > $x && !$allowDistort) {
                        return array($x, $y);
                    }
                    $r = $x / $longestLength;
                    return array($longestLength, $y / $r);
                } else {
                    if ($longestLength > $x && !$allowDistort) {
                        return array($x, $y);
                    }
                    $r = $y / $longestLength;
                    return array($x / $r, $longestLength);
                }
            return array($nx, $ny);
        }       
    }
    

    And then if you were to pass in the Image Dimensions like this:

    $originalImageX = 480;
    $originalImageY = 260;    
    $scale = new Scale();
    var_dump($scale->getImageScale($originalImageX,$originalImageY,120 ) );    
    
    /* Outputs
       array(2) {
      [0]=>
      int(120)
      [1]=>
      int(65)
    } */
    

    Also, there is this Content Aware Cropping class on Git, that I have previously adapted the base class/Structure previously to use in my own project so I know that it works nicely. I'm not sure on the licencing of this class, but you can obviously take a look at it and slice out what works for you as I have done previously.

    https://gist.github.com/2468935#file_content_aware_image.php

    (And PS. Provide all the information in your questions straight up next time...)

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 一道python难题
  • ¥15 用matlab 设计一个不动点迭代法求解非线性方程组的代码
  • ¥15 牛顿斯科特系数表表示
  • ¥15 arduino 步进电机
  • ¥20 程序进入HardFault_Handler
  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度