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 ...
随机推荐
- java ->Servlet接口
JavaWeb核心之Servlet Servlet简介 什么是Servlet(控制器的作用) Servlet 运行在服务端的Java小程序,是sun公司提供一套规范(接口),用来处理客户端请求.响应给 ...
- redis搭建实录
#!/bin/bash####redis版本为4.2.0,需要php5.6以上才支持,可先将安装包上传到/tools目录. yum -y install wgetyum -y install unzi ...
- EMAIL、用户名测试点
EMAIL xxxaa@xxx.xxx 1.没有@情况,如:aa.net 2.没有.符号,如:aa@qqcom 3..后面没有字符:如 xxxaa@xxx. 4..不在@后面, 如:xxxaa.@xx ...
- 两圆相交求面积 hdu5120
转载 两圆相交分如下集中情况:相离.相切.相交.包含. 设两圆圆心分别是O1和O2,半径分别是r1和r2,设d为两圆心距离.又因为两圆有大有小,我们设较小的圆是O1. 相离相切的面积为零,代码如下: ...
- Python - 常用的PyCharm的快捷键和使用场景介绍
关于PyCharm的快捷键,由于数量众多,差不多有100个,相信几乎没有人会记住所有,每个人都会有自己顺手的几个,这里我将自己用着顺手,不别扭的快捷键分享出来,同时分享在哪里可以找到所有的快捷键. 一 ...
- SPL数据结构
数据结构是计算机存储.组织数据的方式. SPL提供了双向链表.堆栈.队列.堆.降序堆.升序堆.优先级队列.定长数组.对象容器. 基本概念Bottom:节点,第一个节点称Bottom:Top:最后添加的 ...
- html5拖动监听
在拖动目标上触发事件 (源元素): ondragstart - 用户开始拖动元素时触发 ondrag - 元素正在拖动时触发 ondragend - 用户完成元素拖动后触发 释放目标时触发的事件: o ...
- Android中的多进程、多线程
前面几篇总结了进程.线程相关的知识.这里总结下关于Android中的多进程.多线程及其使用. 这里总结的Android中的多进程.多线程也是一个基础,可扩展的很多. Android中多进程 常见的几种 ...
- 第三篇-用Flutter手撸一个抖音国内版,看看有多炫
前言 前一篇已经开发了大部分框架,包含视频上下滑动播放,这次将上次未完成的数据显示友好显示,以及底部音乐走马灯特效,另外优化了加载数据的bug,在dart语言里 & 会自动变成& 另 ...
- 【MOOC操作系统】测试题大题-进程调度 先入先服务算法例题 【某多道程序系统供用户使用的主存为100K,磁带机2台,打印机1台,采用可变分区存储管理,静态方式分配外围设备(进程获得所需全部设备才能进入内容),忽略用户作业的I/O时间。采用动态分区、首次匹配法(从低地址区开始)分配主存,一个作业创建一个进程,且运行中不紧缩内存。作业调度采用FCFS算法,在主存中的进程采用剩余时间最短调度算法。】
分析图: 答案: (1) 8 : 00作业1到达,占有资源并调入主存运行. 8: 20作业2和3同时到达,但作业2因分不到打印机,只能在后备队列等待.作业3资源满足,可进主存运行,并与作业1平分CPU ...