node实现图片分割
前言
最近,女王大大日常找我弄图片,本来之前我一直是ps帮他弄得,后来- -,ps不能分割过长的图片,我就想想能不能通过代码来帮他实现好了。
经过我在npm搜索一番,发现没有一个纯代码层面的high tools来实现这个功能,索性就自己通过node-canvas这个库弄个小例子出来,自己使用好了
gm这个库是可以实现的,但是他需要额外安装两个工具,所以- -我就放弃了
简单搭建一下
新建一个clip目录
初始化一个
node项目工程npm init -y
安装依赖,这里主要用到了三个依赖,分别是
处理图片、获取图片大小、压缩成zip文件npm i canvas image-size archiver -S
简单的使用一下
首先,先说说我的需求,下面是一张名为 clip.png 的图片,

我们需要做的就是把他均分为3等分,所以,我们尝试写一下我们的代码
// 创建写入流
const { createWriteStream } = require('fs')
// 导入压缩文件库
const archiver = require('archiver')
// 导入canvas库,用于裁剪图片
const { createCanvas, loadImage } = require('canvas')
// 用户获取图片大小
const sizeOf = require('image-size')
!(async () => {
// 加载图片
const image = await loadImage('./clip.png')
// 获取图片宽高
const { width, height } = await sizeOf('./clip.png')
// 创建等宽登高的canvas
const mainCanvas = createCanvas(width, height)
// 获取canvas上下文
const ctx = mainCanvas.getContext('2d')
// 绘图
ctx.drawImage(image, 0, 0)
// 压缩成zip
const archive = archiver('zip', {
zlib: { level: 9 } // Sets the compression level.
});
// 输出到当前文件夹下的 clip.zip
const output = createWriteStream(__dirname + '/clip.zip');
archive.pipe(output);
// 明确我们需要垂直分割成几份
const num = 3
// 获取一份的高度
const oneHeight = height / num
for (let i = 0; i < num; i++) {
// 创建一份裁剪的canvas
let clipCanvas = createCanvas(width, oneHeight)
// 获取canvas上下文
const clipCtx = clipCanvas.getContext('2d')
// 通过 clipCtx 裁剪 mainCanvas
clipCtx.drawImage(mainCanvas, 0, oneHeight * i, width, oneHeight, 0, 0, width, oneHeight)
// 放到压缩器里
archive.append(clipCanvas.toBuffer(), { name: `${i + 1}.png` })
// 主动释放内存
clipCanvas = null
}
archive.finalize();
})()
跑一下我们写的程序,你会惊奇的发现,目录下多了一个clip.zip的压缩包,解压出来就是我们需要的图片啦
看到这里,其实我们已经实现我们想要的效果了,但是你会发现我们只是实现了水平的切割,如何实现垂直的呢?
也许你会说,加个判断不就好了?
// 垂直切割...伪代码
if(direction === "vertical"){
// 获取一份的高度
const oneHeight = height / num
for (let i = 0; i < num; i++) {
let clipCanvas = createCanvas(width, oneHeight)
// ...... 和上面一致
clipCtx.drawImage(mainCanvas, 0, oneHeight * i, width, oneHeight, 0, 0, width, oneHeight)
// ......
}
}else{
const oneWidth = width / num
for (let i = 0; i < num; i++) {
let clipCanvas = createCanvas(oneWidth, height)
// ...... 和上面一致
clipCtx.drawImage(mainCanvas, oneWidth * i, 0, width, oneHeight, 0, 0, width, oneHeight)
// ......
}
}
的确,这样写是可以,但是会不会觉得很不优雅?那我们是不是可以找找规律,把他封装成一份呢?答案是肯定可以的
这里我们可以新建一个数组配置,用来判断我们传递的参数来判断是 width/num 还是 height/num,闲话不多少了,开始写我们的代码把
// 创建写入流
const { createWriteStream } = require('fs')
// 压缩文件
const archiver = require('archiver')
// 批量裁剪
const { createCanvas, loadImage } = require('canvas')
// 获取图片大小
const sizeOf = require('image-size')
// 切割方向配置
const directionConfig = ["vertical", "horizontal"]
!(async () => {
const image = await loadImage('./clip.png')
const { width, height } = await sizeOf('./clip.png')
const mainCanvas = createCanvas(width, height)
const ctx = mainCanvas.getContext('2d')
ctx.drawImage(image, 0, 0)
// 压缩成zip
const archive = archiver('zip', {
zlib: { level: 9 } // Sets the compression level.
});
const output = createWriteStream(__dirname + '/clip.zip');
archive.pipe(output);
const clip = clipNumImage({ canvas: mainCanvas, width, height }, 3)
clip.forEach((img, idx) => {
archive.append(img, { name: `${idx + 1}.png` })
})
archive.finalize();
})()
function clipNumImage(options, num, direction = "horizontal") {
const { canvas, ...canvasSize } = options
// 生成配置的参数
let directionIdx = getIdx(direction)
// 公有配置
const directionOptions = getOptions(canvasSize, directionIdx, num)
const clip = []
for (let i = 0; i < num; i++) {
let clipCanvas = createCanvas(...directionOptions)
const clipCtx = clipCanvas.getContext('2d')
clipCtx.drawImage(
canvas,
...directionOptions.map((val, idx) => idx === directionIdx ? val * i : 0),
...directionOptions, 0, 0,
...directionOptions
)
clip.push(clipCanvas.toBuffer())
clipCanvas = null
}
return clip
}
// 获取传递过来的是垂直切割还是水平切割
function getIdx(direction) {
let directionIdx = directionConfig.indexOf(direction)
if (directionIdx === -1) {
directionIdx = 1
}
return directionIdx
}
// 获取切割参数
function getOptions(size, directionIdx, num) {
return Object.values(size).map((val, idx) => idx === directionIdx ? val / num : val)
}
通过数组,是不是感觉到我们代码比以前更加简洁了呢?好啦,这次小demo我们也写完啦,希望你通过这篇文章也学习到一点知识。感谢你的观看
ps: 对了,还有一个长图切割器,不写代码的话,直接下载用也是极好的,点我下载
最后
感谢各位观众老爷的观看 O(∩_∩)O
node实现图片分割的更多相关文章
- 第八节、图片分割之GrabCut算法、分水岭算法
所谓图像分割指的是根据灰度.颜色.纹理和形状等特征把图像划分成若干互不交迭的区域,并使这些特征在同一区域内呈现出相似性,而在不同区域间呈现出明显的差异性.我们先对目前主要的图像分割方法做个概述,后面再 ...
- WPF 把图片分割成两份自动翻页 WpfFlipPageControl:CtrlBook 书控件
原文:WPF 把图片分割成两份自动翻页 WpfFlipPageControl:CtrlBook 书控件 版权声明:本文为博主原创文章,需要转载尽管转载. https://blog.csdn.net/z ...
- 图片分割之GrabCut算法、分水岭算法
https://www.cnblogs.com/zyly/p/9392881.html 所谓图像分割指的是根据灰度.颜色.纹理和形状等特征把图像划分成若干互不交迭的区域,并使这些特征在同一区域内呈现出 ...
- node 裁剪图片
1.前端一般用Jcrop这个jq插件 要返回 x: 图片 x坐标 y: 图片 y坐标 w: 图片 宽度 h: 图片 高度 2.node 实现 var images = require("im ...
- Unity 图片分割将spirte保存在本地
如果你拿到的是一张整图,你想分割之后使用NGUI sprite来使用! 下面就能解决的需求. 步骤: 1. 使用Unity自带的spirte进行分割图片 2. 使用代码把分割出来的2DSpirte转 ...
- 好久没发贴了,最近捣鼓了个基于node的图片压缩小网站解析。
看了下,距离上次发帖都是去年10月份的事,忙于工作的我很少跑博客园里面来玩了. 做这个小网站的初衷是 https://tinypng.com/ 这个网站有时候访问很慢,然后自己去研究了下图片压缩. 网 ...
- 使用PHP写了一个图片分割等份工具,便于前台页面切图时使用。
目的: 由于网站更新活动较频繁,其大多数以静态图片为主,设计人员在除了设计图后都要给前端制作人员再次切图从而达到页面加载图片缓慢的问题,为了减少工作量做了该工具. 功能: 上传一张图,将其分割成指定等 ...
- 一个node.js图片上传显示小应用
文件结构如下: 实现的功能有: 可以通过浏览器使用. 当请求http://domain/start时,可以看到一个欢迎页面,页面上有一个文件上传的表单. 用户可以选择一个图片并提交表单,随后文件将被上 ...
- ajax+node实现图片上传
利用formData实现ajax上传图片后,保存图片到指定收藏夹,然后展示新重命名后的图片 html: <input type="file" id="uploadI ...
随机推荐
- 04JAVA基础数组
概念 存储同一种数据类型的多种元素的容器 数组初始化 动态初始化 设定数组长度,系统自动分配默认值 int[] arr = new int[3]; 静态初始化 给定数组默认值,系统自动分配长度 int ...
- Windows基础学习
0x01 常用的端口 HTTP协议代理服务器常用端口号:80/8080/3128/8081/9098SOCKS代理协议服务器常用端口号:1080FTP(文件传输)协议代理服务器常用端口号:21Teln ...
- poi excel自动转换成javabean 支持引用类型属性二级转换
最近项目需要使用excel导入功能,导入学生的时候需要指定所在班级,使用excel一次性导入! 将以前的代码改改支持属性内引用类的转换. 测试对象为User对象,javabean结构: private ...
- 仅需60秒,使用k3sup快速部署高可用K3s集群
作者简介 Dmitriy Akulov,连续创业者,16岁时搭建了开源CDN公共服务jsDelivr的v1版本.目前是边缘托管平台appfleet创始人. 原文链接: https://ma.ttias ...
- 判断对象oStringObject是否为String
1.操作符 (1)typeof操作符 格式:result=typeof variable 返回值: undefined 值未定义 boolean 布尔值 string 字符串 number 数值 ob ...
- RabbitMQ应用示例
更多详情参考官方文档:https://www.rabbitmq.com/tutorials/tutorial-six-python.html 参考博客:https://blog.csdn.net/we ...
- Linux下分析bin文件的10种方法
这世界有10种人,一种人懂二进制,另一种人不懂二进制. --鲁迅 大家好,我是良许. 二进制文件是我们几乎每天都需要打交道的文件类型,但很少人知道他们的工作原理.这里所讲的二进制文件,是指一些可执行文 ...
- Mac Chrome浏览器取消自动升级(最新版)
做自动化突然冒出错误:SessionNotCreatedException: session not created: This version of ChromeDriver only suppor ...
- 关于Java Web结构和SSM框架的理解
Java Web常见的三层结构 表现层:也就是Web层,常见的框架有Spring MVC.Struts2 ,并包括用于展示的界面,如JSP界面:业务层:Service层,专注于业务逻辑的实现:持久层: ...
- akka-typed(0) - typed-actor, typed messages
akka 2.6.x正式发布以来已经有好一段时间了.核心变化是typed-actor的正式启用,当然persistence,cluster等模块也有较大变化.一开始从名称估摸就是把传统any类型的消息 ...