【问题标题】:Trouble cropping and resizing image无法裁剪和调整图像大小
【发布时间】:2014-08-17 06:51:45
【问题描述】:

我正在尝试为更大的图像创建缩略图。我正在使用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 文件上传后触发以创建该图像的缩略图:

这是最后调用cropper的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 时添加了真实大小选项,看起来我们快到了。

对于较小的图像,1000 像素以下的裁剪器似乎工作得很好。但是对于较大的(1000px +),它会产生黑色图像。当我将它与 JCrop 演示脚本一起使用时,它不会这样做,但两者之间的唯一区别是一个是将文件输出到屏幕,另一个是保存它。我看不出任何其他差异,也不知道为什么会发生这种情况。

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

【问题讨论】:

    标签: php gd crop jcrop


    【解决方案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 进行操作。正确的 dest 图像,正确的 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';
    
    }
    

    【讨论】:

    • 这不起作用。它没有调整图像大小,因此裁剪被大量放大。如果我选​​择裁剪 300 x 300,它应该裁剪出来然后将其调整为 180 x 180,但事实并非如此。
    • 那也行不通。左上角与我将其放置在裁剪器上的位置不匹配,并且它也没有以正确的缩放比例裁剪。
    • 我复制了您的代码并将其粘贴进去以确保它是正确的并且仍然得到相同的东西。是否没有任何命令可以输入 4 个坐标(左上、右上、左下、右下)并得到它,然后调整为 180?
    • 另外我想知道这是否是由于图像被缩放? Jcrop 应该能够处理它,但我想知道我做得对吗?
    • 好吧,我不觉得自己很愚蠢。我正在过滤整数,但它正在发送浮点数。我不知道为什么它适用于较小的图像,它们必须发送整数而不是浮点数,或者过滤器将它们四舍五入。不过现在已经整理好了。它正在工作。感谢您的所有帮助。
    【解决方案2】:

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

    只需像这样调用函数:

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

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

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

    【讨论】:

    • 如何使用此脚本指定从何处裁剪?它似乎不接受任何 x,y 参数。
    • 要裁剪,你必须将 $destination_filename 设置为绝对路径,它会自动从主图像的中心裁剪图像。
    • 我不希望它从主图像的中心裁剪,我想指定裁剪位置的坐标。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-03
    相关资源
    最近更新 更多