纯前端使用Canvas旋转图片并封装成通用工具方法

简介

在现代前端开发中,Canvas 是一个强大的 HTML5 元素,它允许我们使用 JavaScript 在网页上绘制图形。通过使用 Canvas,我们可以实现各种各样的图形效果和交互功能。本文将介绍如何使用 Canvas 绘制图片并实现旋转功能,并将其封装成通用的工具方法,方便其他开发者在项目中使用。

图片旋转示意:

主要思路

加载图片

Web 环境中表示图片的形式有多种:

  • base64 字符串
  • 图片 URL 链接:包括在线 URL 链接、浏览器缓存中的 Blob 链接等
  • <img> 元素
  • <cavnas> 元素

其中 base64 字符串 和图片 URL 链接 需要先加载为 Image 对象 ,才能进行绘图,加载过程为:

构造一个 Image 对象,指定其 src 为要加载的数据或图片 URL 链接,对象的 onload 事件触发则表示图片加载完成。

计算输出图片尺寸

按照图片旋转角度不同可以分为两种情况:

  1. 旋转角度为 90° 的倍数
  2. 旋转角度非 90° 的倍数

若按照 90° 倍数旋转,输出图片尺寸一定是和原图一致的,要么宽高相同,要么宽高相反。

若按照非 90°倍数旋转,要看原图是按照裁切模式(类似于css里的cover)还是包含模式(类似于css里的contain)处理,输出图片的尺寸和原图尺寸不相同。

Canvas绘图并旋转

Canvas 中实现图片旋转绘图的思路是:

  • 先将绘图坐标系移动到图片中心点

  • 按照旋转角度旋转坐标系,这里以顺时针旋转45°为例

  • 从新的坐标系的原点开始绘图

    这样绘制的图片不在画布中心,需要偏移绘图起始点

  • 从新的坐标系偏移起始点为图片尺寸的一半进行绘图

    可以看到,旋转角度不是 90°,绘图结果超出了原始图片尺寸,需要进行裁剪或者缩小。

    如果旋转角度为 90° 或 90° 的倍数,以 90° 为例

    先进行了前面计算输出图片尺寸的步骤,能保证输出图片不被裁剪。

    如果旋转角度为180°或180°的倍数,则旋转后图片尺寸与原图完全一样。

输出图片

前端输出图片有两种形式:输出图片数据 、输出本地预览链接,这里的预览链接不是那种 http 开头的 URL 地址。

对于上述实现方式来说,直接返回创建的 Canvas 对象就可以,通过 canvas.toBlob() 返回一个 Blob 对象,也可以使用 cavnas.toDataURL() 直接得到图片 base64 字符串。

详细实现步骤

下面介绍图片旋转功能的详细代码实现,完整代码已开源,可前往 GitHub 查看。

加载图片

封装成一个工具方法,根据传入的图片是否 base64 字符串、是否 URL 链接、是否是 Blob 链接来决定是否拼接图片基础路径。

ts 复制代码
// 这里省略了isUrlLike isBlobUrlLike
export function loadImage (
  url: string,
  /**
   * @defaultValue `false`
   */
  isBase64: boolean = false,
  /**
   * @defaultValue `''`
   */
  baseUrl: string = ''
): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    let tempUrl = isBase64 ? url : (isUrlLike(url) || isBlobUrlLike(url)) ? url : baseUrl + url
    const image = new Image()
    image.src = tempUrl
    image.crossOrigin = 'anonymous'
    image.onload = () => { resolve(image) }
    image.onerror = (e) => { reject(e) }
  })
}

计算输出图片尺寸

当旋转角度是 90° 或 270° 时,输出图片与原图尺寸互换;当旋转角度为 0° 或 360° 时,两者尺寸保持一致。

ts 复制代码
// 这是部分代码
if (degree === 90 || degree === 270) {
  canvas.width = image.height
  canvas.height = image.width
} else {
  canvas.width = image.width
  canvas.height = image.height
}

Canvas绘图

使用 translate 方法移动绘图坐标系原点到输出图片中心。

转换角度为弧度,使用 rotate 方法旋转绘图坐标系。

使用 drawImage 方法沿着新坐标系绘图,绘图起始点向 X 轴、Y 轴负方向偏移图片一半尺寸。

ts 复制代码
// 这是部分代码
const radians = degree * Math.PI / 180
ctx?.translate(canvas.width / 2, canvas.height / 2)
ctx?.rotate(radians)
ctx?.drawImage(image, -image.width / 2, -image.height / 2)
return canvas

输出图片

工具方法直接返回绘图的 Canvas 对象。

获取输出图片 base64 数据:

ts 复制代码
const rotatedImage = rotateImage(img, 90)
rotatedImage.toDataURL() // 返回base64数据

获取输出图片 Blob 对象:

ts 复制代码
const rotatedImage = rotateImage(img, 90)
rotatedImage.toBlob() // 返回Blob对象

获取图片本地预览链接:

ts 复制代码
// 这里使用@dinofe/xt-core/web工具库中Blob转URL的工具方法
import { convertBlobToUrl } from '@dinofe/xt-core/web'
const rotatedImage = rotateImage(img, 90)
convertBlobToUrl(rotatedImage.toBlob()) // Blob生成的本地预览连接

封装工具方法

为了方便复用和维护,我们可以将实现的旋转图片功能封装成一个方法,然后发不成 npm 包。

这一步需要考虑 npm 包各种模块规范的兼容性、JS 代码语法兼容性、polyfill 等,比较复杂,这里有比较完整实现可以参考。

总结

本文介绍了如何使用 Canvas 实现了纯前端进行图片旋转的功能,同时还将这一功能的实现封装成了一个工具方法方便复用。不过,文中的图片旋转实现只支持进行 90° 倍数的角度旋转,后面再考虑支持任意角度旋转。

参考资料

相关推荐
小蒜学长5 小时前
基于Python的动物救助站管理系统的设计与实现(代码+数据库+LW)
数据库·后端·python·django·动物救助
小小张说故事5 小时前
Python 中 __new__ 和 __init__ 到底谁才是构造函数?一文讲透区别与 5 个坑
后端·python
故七月5 小时前
GEO 信源评估体系:如何判断一条网页信源能否被大模型采信
前端·网络·人工智能
liangshanbo12155 小时前
Webpack 常见 Plugin 面试题
前端·webpack·node.js
xxwl5856 小时前
vue3的入门学习
前端·vue.js·学习
用户847172102846 小时前
.shot 文件格式规范
前端·后端
web打印社区6 小时前
政务办事大厅:叫号小票、办理回执网页怎么静默出纸
前端·javascript·vue.js·pdf·html·政务
C++ 老炮儿的技术栈6 小时前
有符号变量与无符号变量的区别
服务器·开发语言·前端·数据结构·c++·算法·c
aixingpan6 小时前
aixingpan.cn API开发文档:api_docs_bichart_natalvssecondary2接口指南
前端·php
liangshanbo12156 小时前
Webpack Tree Shaking 面试题整理
前端·webpack·node.js