麻烦裁剪和调整图像大小

时间:2014-06-26 12:10:09

标签: php gd crop jcrop

我正在尝试为更大的图片创建缩略图。我使用Jcrop来获取裁剪的坐标,但我无法将其转换为正确裁剪的缩略图。我已经正确地设置了Jcrop,它通过x-y坐标和盒子的大小一起发送,但我无法解决如何从中进行裁剪。

我所拥有的是我服务器上图像的路径,以及4个坐标以及它们创建的方框的宽度和高度(我已根据需要将纵横比锁定为1:1方形缩略图)。然后我通过Ajax将它发送到我的PHP裁剪脚本,但我无法根据设置来裁剪它。

这是我到目前为止所做的:

public function Crop($file, $crop) {

    $height = $width = 180;
    $ratio = $width / $height;
    $pos = strrpos($file, '.');
    $name = substr($file, 0, $pos);
    $ext = strtolower(substr($file, $pos));

    if( ! in_array($ext, array('.gif', '.jpg', '.jpeg', '.png'))) {
        return 'INVALID_EXT';
    }

    // When loading the image we check to see if the first character in file is a slash, and if so remove it as the last character of root is a slash.
    $src = ROOT . (in_array(substr($file, 0, 1), array('/', '\\')) ? substr($file, 1) : $file);
    $srcRes = imagecreatefromstring(file_get_contents($src));
    if( ! $srcRes) {
        return 'INVALID_FILE';
    }
    $srcWidth = imagesx($srcRes);
    $srcHeight = imagesy($srcRes);
    $srcRatio = $srcWidth / $srcHeight;
    $dstRes = imagecreatetruecolor($crop['w'], $crop['h']);

    if($ext == '.gif') {
        $dstBg = imagecolorallocate($dstRes, 0, 0, 0);
        imagecolortransparent($dstRes, $dstBg);
    } elseif($ext == '.png') {
        $dstBg = imagecolorallocate($dstRes, 0, 0, 0);
        imagecolortransparent($dstRes, $dstBg);
        imagealphablending($dstRes, FALSE);
        imagesavealpha($dstRes, TRUE);
    }

    $srcX = 0;
    $srcY = 0;
    if($srcRatio > $ratio) {
        $tmpWidth = $srcHeight * $ratio;
        $tmpHeight = $srcHeight;
        $srcX = ($srcWidth - $tmpWidth) / 2;
        $srcY = 0;
    } else {
        $tmpWidth = $srcWidth;
        $tmpHeight = $srcWidth / $ratio;
        $srcX = 0;
        $srcY = ($srcHeight - $tmpHeight) / 2;
    }

    imagecopyresampled($dstRes, $srcRes, 0, 0, $crop['x'], $crop['y'], $crop['w'], $crop['h'], $tmpWidth, $tmpHeight);

    $dst = ROOT . (in_array(substr($name, 0, 1), array('/', '\\')) ? substr($name, 1) : $name) . '-thumb' . $ext;
    if($ext == '.gif') {
        $try = imagegif($dstRes, $dst);
    } elseif($ext == '.jpg' || $ext == '.jpeg') {
        $try = imagejpeg($dstRes, $dst, 80);
    } elseif($ext == '.png') {
        $try = imagepng($newThumbImageResource, $dst);
    }

    if( ! $try) {
        return 'CREATE_ERR';
    }

    return 'SUCCESS';

}

我已尝试更改imagecopyresampled中的各种内容但无法根据Jcrop发送的内容进行裁剪。如果我使用$srcWidth$srcHeight,它会保持原始图像的宽高比并将其调整为180px的正方形。但它似乎并没有调整它的大小或从正确的地方裁剪它。

有人可以帮我弄清楚我应该在哪里使用哪些数字?我整天都在反对这一切。

<小时/> 的修改

这是代码的其余部分。首先是运行JCrop的JavaScript。在上传Ajax文件后触发它以创建该图像的缩略图:

这是最后调用裁剪器的Ajax函数上传。

$(function () {

    'use strict';
    // Change this to the location of your server-side upload handler:
    var url = '/eshop/library/ajax/ajax.file-upload.php';
    var uploadDir = 'prodimages/';

    $('.listing-image').fileupload({
        url: url,
        dataType: 'json',
        autoUpload: true,
        acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
        maxFileSize: 1000000, // 1 MB
        // Enable image resizing, except for Android and Opera,
        // which actually support image resizing, but fail to
        // send Blob objects via XHR requests:
        disableImageResize: /Android(?!.*Chrome)|Opera/
            .test(window.navigator.userAgent),
        previewMaxWidth: 120,
        previewMaxHeight: 120,
        previewCrop: true,
        paramName: 'files[]',
        formData: {uploadDir: uploadDir}
    })/*.on('fileuploadprocessalways', function (e, data) {
        var index = data.index;
        var file = data.files[index];
        $(this).html(file.preview);
    })*/.on('fileuploadprogressall', function (e, data) {
        var progress = parseInt(data.loaded / data.total * 100, 10);
        $('.listing-progress', this).css(
            'width',
            progress + '%'
        );
    }).on('fileuploaddone', function (e, data) {
        var file = data.result.files[0];
        var html = '<div class="listing-preview">\
            <img src="' + file.thumbnailUrl + '" data-name="' + file.name + '">\
            <div class="listing-preview-delete">Delete</div>\
        </div>';
        $(this).html(html).data('delete-url', file.deleteUrl).css('padding', 0);

        Crop('/' + uploadDir + file.name, $(this).prop('id'));

    });

});

这会通过Ajax将裁剪详细信息发送到上面的PHP脚本。

$(document).on('click', '.crop-btn', function() {

    var data = {
        file: $(this).data('src'),
        crop: jcrop.tellSelect()
    }
    ShowLoadingById('crop-loading');
    AjaxHandler('/eshop/library/ajax/ajax.product-crop-thumb.php', data, 'POST', true);

});

裁剪窗口是一个灯箱,此功能垂直居中,如果图像垂直大于可用空间,则会调整图像大小。

function CentreCrop() {

    var m = ($(window).height() - ($('.crop > div').height() + 60)) / 2;
    $('.crop > div').css('margin-top', m);

    if($('#crop-img').height() > $('.crop > div').height() - 30) {
        $('#crop-img-container').height($('.crop > div').height() - 30);
    }

}

这是存储要裁剪的文件的初始函数,如果它没有运行则调用该工作。

var toBeCropped = [];
var working = false;
function Crop(file, id) {

    toBeCropped.push({path: file, id: id});

    if( ! working) {
        working = true;
        CropWorker();
    }

}

这是我在裁剪完成时运行的功能,以破坏jcrop并清除裁剪灯箱,为下一个要裁剪的图像做好准备。

function CropSuccess() {

    $('.crop').fadeOut(250, function() {

        jcrop.destroy();
        $(this).html('');
        CropWorker();

    });

}

这是实际在灯箱中创建内容并启动jcrop的工作者。

function CropWorker() {

    if(toBeCropped.length > 0) {
        file = toBeCropped.shift();
        html = '<div>\
            <div id="crop-img-container" class="row-fluid">\
                <img id="crop-img" src="' + file.path + '">\
            </div>\
            <div class="row-fluid">\
                <div class="span3 offset9">\
                    <button class="span12 btn crop-btn" data-id="' + file.id + '" data-src="' + file.path + '">Create Thumb</button>\
                </div>\
            </div>\
            <div class="row-fluid loading-screen" id="crop-loading">\
                <div>\
                    <h4>Cropping...</h4>\
                    <img src="/img/loading.gif">\
                </div>\
            </div>\
        </div>';
        $('.crop').html(html);
        $('.crop').fadeIn(250);
        $('#crop-img').load(function() {
            CentreCrop();
            $('#crop-img').Jcrop({
                aspectRatio: 1/1,
                bgColor: 'black',
                bgOpacity: 0.4,
                boxWidth: $('#crop-img').width(), // Only just recently added boxWidth and height to see if that would fix it, no difference with or without.
                boxHeight: $('#crop-img').height(),
                //maxSize: [300,300],
                minSize: [180,180]
            }, function() {
                jcrop = this;
                jcrop.setSelect([0,0,180,180]);
            });
        });
    } else {
        working = false;
    }

}

更新

问题的一部分似乎是图像调整大小。我正在改变图像大小以适应屏幕,我虽然JCrop会照顾我,但似乎你必须告诉JCrop图像的原始尺寸。我在初始化JCrop时添加了真正的大小选项,似乎我们几乎就在那里。

对于较小的图像,那些1000px以下的裁剪器看起来效果很好。但对于较大的(1000px +),它会产生黑色图像。当我将它与JCrop演示脚本一起使用时,它不会这样做,但两者之间的唯一区别是一个是将文件输出到屏幕而另一个是保存它。我无法看到任何其他差异或弄清楚为什么会发生这种情况。

更新2 如果我通过Ajax运行代码,它似乎只会受到影响。如果我运行完全相同的功能只是发布到页面并在顶部运行它,无论原始图像的大小或我绘制的框的大小,每次都会完美地创建缩略图。

2 个答案:

答案 0 :(得分:1)

在您的代码$crop['w']中,$crop['h']代表来源;

$tmpWidth$tmpHeight用于目的地;

所以你应该根据imagecopyresampled函数(http://php.net//manual/fr/function.imagecopyresampled.php)切换它们。

imagecopyresampled($dstRes, $srcRes, 0, 0, $crop['x'], $crop['y'], $tmpWidth, $tmpHeight, $crop['w'], $crop['h']);

编辑2

您的目标图片不应使用$crop数据设置,但要符合您想要的尺寸:

$dstRes = imagecreatetruecolor(180, 180);

我不确定$tmpWidth$tmpHeight的价值是多少,但它们应该都是180,因为它的大小是你想要的:

imagecopyresampled($dstRes, $srcRes, 0, 0, $crop['x'], $crop['y'], 180, 180, $crop['w'], $crop['h']);

编辑3

好的,最后一次尝试,我为jcrop提供了一个有效的代码,但是我没有在一个函数中使用它,它仍然以相同的方式工作。我逐行检查了你的代码,这就是我所拥有的。我删除了有关比率的所有内容,Jcrop管理它,无需使用PHP。适当的目标图像,恰当的imagecopyresampled,对我来说很好看:/

public function Crop($file, $crop) {

    $height = $width = 180;

    // your file type checking
    $pos = strrpos($file, '.');
    $name = substr($file, 0, $pos);
    $ext = strtolower(substr($file, $pos));

    if( ! in_array($ext, array('.gif', '.jpg', '.jpeg', '.png'))) {
        return 'INVALID_EXT';
    }

    // source image
    $src = ROOT . (in_array(substr($file, 0, 1), array('/', '\\')) ? substr($file, 1) : $file);
    $srcRes = imagecreatefromstring(file_get_contents($src));
    if( ! $srcRes) {
        return 'INVALID_FILE';
    }

    // destination image
    $dstRes = imagecreatetruecolor($width, $height);

    // file type transparence
    if($ext == '.gif') {
        $dstBg = imagecolorallocate($dstRes, 0, 0, 0);
        imagecolortransparent($dstRes, $dstBg);
    } elseif($ext == '.png') {
        $dstBg = imagecolorallocate($dstRes, 0, 0, 0);
        imagecolortransparent($dstRes, $dstBg);
        imagealphablending($dstRes, FALSE);
        imagesavealpha($dstRes, TRUE);
    }

    // bool imagecopyresampled ( resource $dst_image , resource $src_image , int $dst_x , int $dst_y , int $src_x , int $src_y , int $dst_w , int $dst_h , int $src_w , int $src_h )
    imagecopyresampled($dstRes, $srcRes, 0, 0, $crop['x'], $crop['y'], $width, $height, $crop['w'], $crop['h']);

    $dst = ROOT . (in_array(substr($name, 0, 1), array('/', '\\')) ? substr($name, 1) : $name) . '-thumb' . $ext;
    if($ext == '.gif') {
        $try = imagegif($dstRes, $dst);
    } elseif($ext == '.jpg' || $ext == '.jpeg') {
        $try = imagejpeg($dstRes, $dst, 80);
    } elseif($ext == '.png') {
        $try = imagepng($newThumbImageResource, $dst);
    }

    if( ! $try) {
        return 'CREATE_ERR';
    }

    return 'SUCCESS';

}

答案 1 :(得分:0)

尝试在调整图像大小时使用此功能

只需调用这个函数:

    resize_image($source_image, $destination_filename, 200, 200);

此功能还包括裁剪功能。您可以通过在其中传递true或false($ crop = true / false)来启用或禁用crop参数。

function resize_image($source_image, $destination_filename, $width, $height, $quality = 100, $crop = true)
{ 
        if( ! $image_data = getimagesize( $source_image ) )
        {
            return false;
        }

        switch( $image_data['mime'] )
        {
            case 'image/gif':
            $get_func = 'imagecreatefromgif';
            $suffix = ".gif";
            break;
            case 'image/jpeg';
            $get_func = 'imagecreatefromjpeg';
            $suffix = ".jpg";
            break;
            case 'image/png':
            $get_func = 'imagecreatefrompng';
            $suffix = ".png";
            break;
        }

        $img_original = call_user_func( $get_func, $source_image );
        $old_width = $image_data[0];
        $old_height = $image_data[1];
        $new_width = $width;
        $new_height = $height;
        $src_x = 0;
        $src_y = 0;
        $current_ratio = round( $old_width / $old_height, 2 );
        $desired_ratio_after = round( $width / $height, 2 );
        $desired_ratio_before = round( $height / $width, 2 );

        if( $old_width < $width || $old_height < $height )
        {
            /**
            * The desired image size is bigger than the original image.
            * Best not to do anything at all really.
            */
            return false;
        }


        /**
        * If the crop option is left on, it will take an image and best fit it
        * so it will always come out the exact specified size.
        */
        if( $crop )
        {
            /**
            * create empty image of the specified size
            */
            $new_image = imagecreatetruecolor( $width, $height );

            /**
            * Landscape Image
            */
            if( $current_ratio > $desired_ratio_after )
            {
                $new_width = $old_width * $height / $old_height;
            }

            /**
            * Nearly square ratio image.
            */
            if( $current_ratio > $desired_ratio_before && $current_ratio < $desired_ratio_after )
            {
                if( $old_width > $old_height )
                {
                    $new_height = ma(angry) $width, $height );
                    $new_width = $old_width * $new_height / $old_height;
                }
                else
                {
                    $new_height = $old_height * $width / $old_width;
                }
            }

            /**
            * Portrait sized image
            */
            if( $current_ratio < $desired_ratio_before )
            {
                $new_height = $old_height * $width / $old_width;
            }

            /**
            * Find out the ratio of the original photo to it's new, thumbnail-based size
            * for both the width and the height. It's used to find out where to crop.
            */
            $width_ratio = $old_width / $new_width;
            $height_ratio = $old_height / $new_height;

            /**
            * Calculate where to crop based on the center of the image
            */
            $src_x = floor( ( ( $new_width - $width ) / 2 ) * $width_ratio );
            $src_y = round( ( ( $new_height - $height ) / 2 ) * $height_ratio );
        }
        /**
        * Don't crop the image, just resize it proportionally
        */
        else
        {
            if( $old_width > $old_height )
            {
                $ratio = ma(angry) $old_width, $old_height ) / ma(angry) $width, $height );
            }else{
                $ratio = ma(angry) $old_width, $old_height ) / min( $width, $height );
            }

            $new_width = $old_width / $ratio;
            $new_height = $old_height / $ratio;

            $new_image = imagecreatetruecolor( $new_width, $new_height );
        }

        /**
        * Where all the real magic happens
        */
        imagecopyresampled( $new_image, $img_original, 0, 0, $src_x, $src_y, $new_width, $new_height, $old_width, $old_height );

        /**
        * Save it as a JPG File with our $destination_filename param.
        */
        imagejpeg( $new_image, $destination_filename, $quality );

        /**
        * Destroy the evidence!
        */
        imagedestroy( $new_image );
        imagedestroy( $img_original );

        /**
        * Return true because it worked and we're happy. Let the dancing commence!
        */
        return true;
}