上传前在浏览器中裁剪图像[关闭]

Posted

技术标签:

【中文标题】上传前在浏览器中裁剪图像[关闭]【英文标题】:Cropping images in the browser BEFORE the upload [closed] 【发布时间】:2012-09-25 13:02:47 【问题描述】:

我发现的许多库,比如 Jcrop,实际上并没有进行裁剪,它只创建了一个图像裁剪 UI。然后,它取决于执行实际裁剪的服务器。

如何在不使用任何服务器端代码的情况下,通过使用一些 html5 功能 使图像在 客户端 进行裁剪。

如果有,是否有一些例子或提示?

【问题讨论】:

可能的重复项:1. javascript crop image client-side (正是您要问的;但是,最佳答案说无法做到,但这是错误的)。 2.Copy and crop images in Javascript(用例略有不同,但最佳答案正是您想要的) github.com/foliotek/croppie 【参考方案1】:

Pixastic 库执行exactly what you want。但是,它仅适用于支持画布的浏览器。对于那些较旧的浏览器,您需要:

    提供服务器端回退,或 告诉用户您很抱歉,但他需要使用更现代的浏览器。

当然,选项 #2 对用户不是很友好。但是,如果您的意图是提供纯客户端工具和/或您不支持后备后端裁剪器(例如,您可能正在编写浏览器扩展程序或离线 Chrome 应用程序,或者您负担不起提供图像处理库的不错的托管服务提供商),那么将您的用户群限制在现代浏览器上可能是公平的。

编辑:如果你不想学习 Pixastic,我在 jsFiddle here 上添加了一个非常简单的裁剪器。应该可以对drawCroppedImage函数与Jcrop进行修改集成和使用。

【讨论】:

嗨@apsillers,感谢您的回答。您确定 this demo 正在裁剪和调整图像大小吗?我的意思是在裁剪操作之后,我无法下载裁剪后的图像,但我只能下载原始图像。 裁剪后的图像被绘制到画布上。您使用toDataURL 从画布中获取base64 编码的图像数据。如果您在裁剪后在 URL 栏中输入 javascript:window.open($("#demoimage")[0].toDataURL()),您将看到裁剪后的图像本身。 (注意:如果您在地址栏中粘贴该代码,您的浏览器可能会删除开头的javascript: 部分;请务必重新添加。) 您在寻找github.com/jseidelin/pixastic吗? 不幸的是,Pixastic 项目似乎已经死了【参考方案2】:

是的,可以做到。 它基于锚标签的新 html5“下载”属性。 流程应该是这样的:

    加载图片 将图像绘制到画布中并指定裁剪边界 从画布中获取图像数据并使其成为 dom 中锚标记的href 属性 将下载属性 (download="desired-file-name") 添加到该 a 元素 而已。用户所要做的就是单击您的“下载链接”,图像将被下载到他的电脑上。

有机会我会回来做一个演示的。

更新 这是我承诺的the live demo。它采用jsfiddle logo 并裁剪每个边距的 5px。 代码如下所示:

var img = new Image();
img.onload = function()
    var cropMarginWidth = 5,
        canvas = $('<canvas/>')
                    .attr(
                         width: img.width - 2 * cropMarginWidth,
                         height: img.height - 2 * cropMarginWidth
                     )
                    .hide()
                    .appendTo('body'),
        ctx = canvas.get(0).getContext('2d'),
        a = $('<a download="cropped-image" title="click to download the image" />'),
        cropCoords = 
            topLeft : 
                x : cropMarginWidth,
                y : cropMarginWidth 
            ,
            bottomRight :
                x : img.width - cropMarginWidth,
                y : img.height - cropMarginWidth
            
        ;

    ctx.drawImage(img, cropCoords.topLeft.x, cropCoords.topLeft.y, cropCoords.bottomRight.x, cropCoords.bottomRight.y, 0, 0, img.width, img.height);
    var base64ImageData = canvas.get(0).toDataURL();


    a
        .attr('href', base64ImageData)
        .text('cropped image')
        .appendTo('body');

    a
        .clone()
        .attr('href', img.src)
        .text('original image')
        .attr('download','original-image')
        .appendTo('body');

    canvas.remove();

img.src = 'some-image-src';

更新二 忘了提:当然有一个缺点:(。 由于同源策略也适用于图像,如果您想访问图像的数据(通过画布方法toDataUrl)。 因此,您仍然需要一个服务器端代理来为您的图像提供服务,就好像它托管在您的域上一样。

更新 III 虽然我不能为此提供现场演示(出于安全原因),但这里有一个解决同源策略的 php 示例代码:

文件proxy.php

$imgData = getimagesize($_GET['img']);
header("Content-type: " . $imgData['mime']);
echo file_get_contents($_GET['img']);  

这种方式,而不是直接从它的原点加载外部图像:

img.src = 'http://some-domain.com/imagefile.png';

您可以通过代理加载它:

img.src = 'proxy.php?img=' + encodeURIComponent('http://some-domain.com/imagefile.png');  

这是一个将图像数据(base64)保存到实际图像中的示例 php 代码:

文件save-image.php

$data = preg_replace('/data:image\/(png|jpg|jpeg|gif|bmp);base64/','',$_POST['data']);
$data = base64_decode($data);
$img = imagecreatefromstring($data);

$path = 'path-to-saved-images/';
// generate random name
$name  = substr(md5(time()),10);
$ext = 'png';
$imageName = $path.$name.'.'.$ext;

// write the image to disk
imagepng($img,  $imageName);
imagedestroy($img);
// return the image path
echo $imageName;

然后您所要做的就是将图像数据发布到此文件,它会将图像保存到光盘并返回现有图像文件名。

当然,这一切可能感觉有点复杂,但我想告诉你,你想要达到的目标是可能的。

【讨论】:

+1 有演示会很棒。我也会尝试这样做。但奇怪的是网上还没有这样的例子。 我做到了,谢谢。您认为在您的示例中使用github.com/tapmodo/Jcrop 以将图像上传到服务器上是否合理/可行?阅读您的Update II似乎我不能。我说的对吗? 是的,可以做到。如果您有图像数据,您所要做的就是将其发布到将其写入图像文件的服务器端页面。唯一棘手的部分(甚至不是那么棘手)是使用 proxy.ex 代理外部图像:而不是 http://domain.com/image.png 使用 proxy.php?img=http://domain.com/image.png。我不知道我是否可以为此做一个演示,但你应该知道这是完全可行的:) 您的示例给出了错误:SecurityError: The operation is insecure。 (img.onload())【参考方案3】:

如果你仍然使用 JCrop,你只需要这个 php 函数来裁剪文件:

$img_src = imagecreatefromjpeg($src);
$img_dest = imagecreatetruecolor($new_w,$new_h);
imagecopyresampled($img_dest,$img_src,0,0,$x,$y,$new_w,$new_h,$w,$h);
imagejpeg($img_dest,$dest);

客户端:

jQuery(function($)

    $('#target').Jcrop(
    onChange:   showCoords,
    onSelect:   showCoords,
    onRelease:  clearCoords
    );

);

var x,y,w,h; //these variables are necessary to crop
function showCoords(c)

    x = c.x;
    y = c.y;
    w = c.w;
    h = c.h;
;
function clearCoords()

    x=y=w=h=0;

【讨论】:

+1 很好的例子。你认为我可以使用HTML5 canvas 来完成 php 代码所做的相同工作吗? 我只知道不是每个浏览器都支持 html5,如果你在服务器站点上完成这项工作,它就不会被黑客入侵。 假设我只想为支持HTML5 canvas的浏览器提供服务。我该怎么做?有什么例子吗?【参考方案4】:

#change-avatar-file 是文件输入 #change-avatar-file是一个img标签(jcrop的目标) “关键”是 FR.onloadend 事件 https://developer.mozilla.org/en-US/docs/Web/API/FileReader

$('#change-avatar-file').change(function()
        var currentImg;
        if ( this.files && this.files[0] ) 
            var FR= new FileReader();
            FR.onload = function(e) 
                $('#avatar-change-img').attr( "src", e.target.result );
                currentImg = e.target.result;
            ;
            FR.readAsDataURL( this.files[0] );
            FR.onloadend = function(e)
                //console.log( $('#avatar-change-img').attr( "src"));
                var jcrop_api;

                $('#avatar-change-img').Jcrop(
                    bgFade:     true,
                    bgOpacity: .2,
                    setSelect: [ 60, 70, 540, 330 ]
                ,function()
                    jcrop_api = this;
                );
            
        
    );

【讨论】:

以上是关于上传前在浏览器中裁剪图像[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

在浏览器中自动裁剪图像

使用 jQuery/Java 裁剪和上传图像

裁剪 PDF 并使用 jquery 或 javascript 保存 [关闭]

客户端图像处理(裁剪)

哪个是 Laravel 中最好的图像裁剪包? [关闭]

ImageMagick:转换、裁剪、调整大图像