前端图片裁剪实战

  • 苏格团队
  • 做者:Bigben

在当下的的前端项目中,图片功能能够说是很是常见的,图片的展现、图片的裁剪编辑、图片的上传等,那么咱们的项目便来了个需求。css

当下咱们项目中须要一个可自由编辑图片的功能,当图片可能出现须要频繁编辑,同时能知足发现裁剪不满意想要微调的时候,会发现若是咱们处理图片按照日常的习惯,如裁剪后上传服务器或者转base64,都是不符合需求的。那么该怎么处理比较好呢?如何以尽可能少的网络请求、少占用存储来解决应用场景呢?那么,便想到了只用纯数据来跟咱们的功能打交道。前端

先安利个裁图神器cropperjs,我的认为是个易上手,配置和api方法蛮齐全的一个组件库。react

项目内引入,必定不要漏了引用样式git

import Cropper from 'cropperjs';
import 'cropperjs/dist/cropper.css';
复制代码

这里咱们以react为例github

this.state = {
  width: 640,   //图片展现宽
  height: 360,   //图片展现高   
  imgWidth: 640,   //图片实际宽
  imgHeight: 360,   //图片实际高
  imgLeft: 0,   //图片左偏移
  imgTop: 0,   //图片上偏移
  editing: false   //是否编辑中
}
//展现图片的基本dom结构,咱们使用外div内img的形式,来跟数据结合控制裁剪图片的展现
const { width, height, imgWidth, imgHeight, imgLeft, imgTop, editing } = this.state;
const containerStyle = {
  width: `${width}px`,
  height: `${height}px`
}
const imgStyle = {
  width: `${imgWidth}px`,
  height: `${imgHeight}px`,
  left: `${imgLeft}px`,
  top: `${imgTop}px`
}

.img-container {
  overflow: hidden;
  position: relative;
}

.crop-img {
  position: absolute;
  left: 0;
  top: 0;
}
<div 
  className="img-container" 
  style={containerStyle}
>
  <img 
    className="crop-img"
    src={picture} 
    style={imgStyle} 
    alt="pic"
  ></img>
</div>
复制代码

简单来讲就是外层元素控制裁剪展现的宽高,同时根据项目需求的元素定位也挂在这,内部img挂载图片实际大小和偏移。canvas

cropperjs初始化后的元素,是会与初始化对象img处在同一dom层级,也就是说若是咱们直接对展现img进行初始化的话,编辑区域展现将会受父元素,如图,放大图片时候会不方查看超出部分 api

因此在这里,为了图片编辑的自由度,建议分开展现dom与用以初始化cropper对象的dom,在这里编辑区域为全屏幕为例,根据项目实际功能区域进行调整bash

.edit-container {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}

<div 
  className="img-container" 
  style={containerStyle}
>
  <img 
    className="crop-img"
    src={picture} 
    style={imgStyle} 
    alt="pic"
  ></img>
</div>

//cropper初始化
this.myRef = React.createRef();
this.myCropper = new Cropper(this.myRef.current, options);
//options配置
const options = {
    dragMode: 'move',   //使裁剪时图片可拖动
    background: false,  //由于咱们如今是全屏可编辑,须要隐藏掉默认的背景
}
//固然还有许多常见的配置项,如编辑框尺寸比例等,你们可自行查看api

//裁剪保存
save() {
const cropBoxData = this.myCropper.getCropBoxData();    //获取裁剪框数据
const canvasData = this.myCropper.getCanvasData();      //获取图片数据
this.setState({
  width: cropBoxData.width,
  height: cropBoxData.height,
  imgLeft: canvasData.left - cropBoxData.left,
  imgTop: canvasData.top - cropBoxData.top,
  imgWidth: canvasData.width,
  imgHeight: canvasData.height
})
}
复制代码

这样的话 咱们就能够彻底在自定义的全屏内编辑,保存效果以下,到这里咱们就完成了第一部分功能,裁剪并保存数据和展现服务器

重点介绍下咱们用到的两个api方法getCropBoxData和getCanvasData,getCanvasData是用来获取图片的实际数据的(当前的宽高,和相对于父元素可视区域的位移偏移量),getCropBoxData则是获取相对于图片区域的裁剪区相关数据。网络

那么后续的需求接着来了,咱们怎么作到二次编辑的时候,能还原效果呢,嗯,其实在前面咱们记录裁图数据的时候,把相应的数据关系再计算一遍就行了,在初始化cropper的options中增长配置

const options = {
dragMode: 'move',
background: false,
//控件初始化后重置相应配置
ready: () => {
  const { width, height, imgWidth, imgHeight, imgLeft, imgTop } = this.state;
  //根据实际须要出现裁图功能进行定位,此处left和top仅为测试暂时默认值定义
  const left = 50;  
  const top = 50;
  this.myCropper.setCanvasData({
    width: imgWidth,
    height: imgHeight,
    left: left,
    top: top
  });
  this.myCropper.setCropBoxData({
    left: left - imgLeft,
    top: top - imgTop,
    width: width,
    height: height
  })
  
}
}
this.myCropper = new Cropper(this.myRef.current, options);
复制代码

这时候咱们再点击裁图,就完美还原了,左边和上边的间隙就是setCanvasData的top和left,根据实际项目进行调整,setCropBoxData的left和top是相对于cropper-canvas的定位,才有了以上的计算形式。

此时,基本功能到此结束,若是说是应用在h5编辑中,设计到scale缩放的话,相关的数据计算都要算上scale的缩放值哦,否则就会出现展现图片和编辑图片大小不对等的情况。同时还有许多功能就不作展现了,设置裁剪框比例,编辑缩放等,欢迎尝试。

固然了,若是想要保存图片,也有相应的方法处处裁剪图片的数据

this.myCropper.getCroppedCanvas().toDataURL('image/jpeg')
复制代码

最后,咱们能够看到,在整个功能过程当中,咱们须要的只是裁剪的数据,读写快,也不须要进行额外的图片存储,减小文件服务器存储的开销与优化。

cropperjs github:github.com/fengyuanche…

感谢你们收看,欢迎讨论和指正。

相关文章
相关标签/搜索