一、需求

使用的插件

  • 后台服务使用 laravel 5.5 构建
  • laravel 使用 intervetion/image 进行图片裁剪处理
  • 前端使用文件上传插件即可
  • jquery 裁剪插件使用 zui.imgcutter.min.js

使用什么裁剪插件无所谓,使用 zui.imgcutter.min.js 的原因是这种思想符合想要实现的思想。

思想如下

  1. 使用无刷新上传插件将图片上传到服务器
  2. 返回图片 url 到前端界面进行显示
  3. 调用 图片裁剪插件 前端显示对图片进行裁剪
  4. 提交到后台的时候,将裁剪的 尺寸x/y 坐标 发送到后端
  5. 后端对图片进行裁剪工作并重新保存覆盖原来的图片

二、详细流程

1、文件上传

为了优化体验,用户选择文件进行文件上传,后端将文件保存即可,同时返回保存的图片 url。

图片上传最终需要的实际上就是保存的 url,而返回的 url 也需要在页面上显示并且用户构造剪切插件使用。

2、图片显示及裁剪

最终我们需要的是在后端进行图片的处理,因此上传后使用返回的 url,并且构建剪切插件:

我使用的是:http://zui.sexy/#javascript/imgcutter

这个插件可以单独引入使用,思想和上面的思想一样。

3、获取裁剪的宽度高度和 x/y 坐标

intervetion/image 处理图片的时候,需要使用 width,height,x,y坐标

获取到这些信息后,我的处理方式是将这些信息进行 JSON.stringfy() ,同样在提交的时候发送给后端处理。

因此后端拿到数据的时候,也会拿到裁剪的这些信息。

4、后端接收信息进行处理

如果要使用 intervetion/imagecomposer 安装即可:

composer require intervetion/image

加入 laravel 的 providers 中:

编辑 config/app.php

$providers 添加 Intervention\Image\ImageServiceProvider::class
$aliases 添加 Image' => Intervention\Image\Facades\Image::class

引入Image的时候直接使用:

use Intervention\Image\Facades\Image;
// 修改图片尺寸 并且保存为相同的图片路径 将之前的文件覆盖掉
    protected function reSaveImage($url, $imageData)
    {
        $img = Image::make('uploads/'.$url)->resize($imageData['naturalWidth'],null,function($constraint){
            $constraint->aspectRatio();
        })->crop(intval($imageData['width']),intval($imageData['height']),$imageData['left'],$imageData['top']);
        $img->save();
    }

关于 intervetion/image 更多更详细的 API 介绍,可以查看:

上面的函数根据实际使用场景使用的,其中 $url 就是 path,也就是上传的文件的保存路径,其次,$imageData 是图片裁剪插件进行的 json 数据,在这之前已经使用 json_decode($jsonData, true) 进行解析了,因此可以直接使用。

$img->save() 能够直接覆盖原来的图片,这样不会造成保存两张图片的尴尬局面。

三、注意点

由于图片在页面上渲染的时候,可能并不是图片的真实宽度,因此如果还是按照裁剪的宽度和高度以及 x/y 坐标来处理,必定会出现问题。

上面的问题有两种解决方法:

1、解决方式一:resize 服务端图像,保证两者图片一致

reSaveImage 函数中,你可以发现一个$imageData['naturalWith'] 属性,这个属性实际上是我自己得到的,并不是 imgcutter.js 插件自己有的。

naturakWidth 实际上就是获取的图片渲染的宽度,而我在 reSaveImage() 方法中,使用了 resize(),将图片宽度压缩或者提高到 naturalWidth ,从而保证服务端保存的图片和前端裁剪时渲染的图片使用的是相同宽度,这样子就能保存裁剪的样子就是需要的样子。

这种方式也有缺点,对服务端保存的图片实际上是进行了尺寸变化,虽然这种尺寸变化是等比例的,还是先变化图片,再进行裁剪。

2、解决方式二:通过比例计算,计算新的裁剪宽高和 x/y 坐标

如果不想对服务端的图片进行变化,则可以在服务端获取图片的宽度,然后通过和 $imageData['naturalWidth'] 进行比例计算,通过这个比例来调整 $imageData['width']$imageData['height']$imageData['left']$imageData['top'],这样子裁剪的时候,通过比例调整可以直接在原图像上进行裁剪。

归根结底, 获取前端裁剪时图片的渲染宽度是非常关键的

虽然 html5 提供了一个 naturalWidth 用来获取图片的原始尺寸,但是我这里的 naturalWidth 是渲染尺寸,主要是为了不想和 imgcutter.js 中的 width 冲突罢了。

1.jpg