-前言-
最近一直在着手研究3D方面的知识,正在研究real-time rendering这本书,书确实挺厚的还是全英文,可能3D渲染方面的博文要拖一拖了。不过在图形渲染分支上,关于之前Laya的图集方面代码看了很多遍,我还是觉得自己能实现一个打包图集并分解图集的功能更能加深对这方面的知识储备,顺带再练手一下Web方面的开发。之所以说造轮子,是因为我在看了PngSplit这个软件源码的时候想着Web上面也可以实现图集分解功能,而且更加方便,当然代码内容完全不一样,我们将使用VsCode + JavaScript原生来开发。
完整项目地址:https://github.com/dengxuhui/ImagePackerWeb
如果想直接使用该功能的同学:http://dengxuhui.cn/
-正文-
环境搭建
在Vscode上我们首先搭建调试环境,选择插件搜索Debugger for Chrome,安装好后,我们在项目跟目录下新建.vscode文件,在这个文件夹中新建一个launch.json文件来配置我们的调试配置。
{
// "version": "0.2.0",
"configurations": [
{
"name": "chrome调试",
"type": "chrome",
"request": "launch",
"file": "${workspaceRoot}/index.html",
"runtimeArgs": [
"--allow-file-access-from-files",
"--allow-file-access-frome-files",
" --disable-web-security"
]
}
]
}
开发库的选择
之前说原生JS开发,但还是需要一个工具库DropzoneJs来帮助我们管理上传文件,可能到时上传的文件会交到服务器去处理再返回给客户端,因此选择一个开发库比较方便。
项目结构
项目主要就一个index.html及一个index.js文件,css这些因为本身不是Web前端出身,就在网上copy了一些css文件来应用。只要界面能够实现交互就会把重心放在逻辑实现上面。
上面图中是这个项目的基本结构,我们所有业务逻辑都将写在index.js中,vendor文件夹中就是我们要引入的dropzone库文件。
UI文件内容
Html主要展示一个上传框,一个确认按钮。效果如下
文件内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Image Packer Web</title>
<link href="assets/css/app.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-body">
<h4 class="header-title m-t-0">拖放图片到框内上传</h4>
<p class="text-muted font-13 m-b-30">
本功能使用了Dropzonejs库,详细查看
<a href="https://www.dropzonejs.com/" target="_blank">https://www.dropzonejs.com/</a>
</p>
<form action="/file-upload" method="post" class="dropzone dz-clickable" id="myAwesomeDropzone" data-plugin="dropzone" data-previews-container="#file-previews" data-upload-preview-template="#uploadPreviewTemplate">
<div class="dz-message needsclick">
<i class="h1 text-muted dripicons-cloud-upload"></i>
<h3>拖动文件到方框内或者点击上传文件。</h3>
<span class="text-muted font-20">(Copy Right@ By AerTims)</span>
</div>
</form>
<!-- Preview -->
<div class="dropzone-previews mt-3" id="file-previews"></div>
</div>
<!-- end card-body -->
</div>
<!-- end card-->
<button type="button" class="btn btn-block btn-primary" id="btn_package_file">点击分解图片</button>
</div>
<!-- end col-->
</div>
<div id="canvasRoot"></div>
<script src="assets/js/vendor/dropzone.min.js"></script>
<script type="text/javascript" src="assets/js/index.js" ></script>
</body>
</html>
逻辑代码
在写好了UI代码之后,我们开始写逻辑代码。新建index.js文件
!function () {
"use strict";
//当前上传文件存储数据
class UpLoadFileData {
constructor() {
this.fileDic = {};
}
}
UpLoadFileData.I = new UpLoadFileData();
/**
* 拖动逻辑
*/
class DropZoneLogic {
constructor() {
this.dropzone = null;
this.initialize();
}
/**
* 初始化
*/
initialize() {
// Dropzone.autoDiscover = !1;
var $this = this;
var zone = {};
Dropzone.options.myAwesomeDropzone = zone;
zone.paramName = "packer";
zone.maxFilesize = 5;
// zone.maxFiles = 1;
zone.init = $this.init;
zone.accept = $this.accept;
zone.url = "/";
zone.acceptedFiles = ".jpg,.png,.jpeg";
zone.addRemoveLinks = true;
zone.previewTemplate = `
<div class="dz-preview dz-file-preview">
<div class="dz-details">
<div class="dz-filename"><span data-dz-name></span></div>
<div class="dz-size" data-dz-size></div>
<img data-dz-thumbnail />
`
}
/**
* 文件被添加上的回调
* @param {File} file
*/
onFileAdded(file) {
console.log(file);
}
/**
* 文件被删除
* @param {File} file
*/
onFileRemoved(file) {
console.log(file);
}
/**
* 文件被放到dropzone区域
*/
onDrop(event) {
console.log(arguments.length);
}
/**
* 出错
*/
onError(file) {
console.log("ERROR");
}
/**
* 离开zone区域
* @param {Event} event
*/
onDragLeave(event) {
}
/**
* zone初始化函数
*/
init() {
var $this = window.DropZoneLogic;
$this.dropzone = this;
this.on("addedfile", (file) => {
$this.onFileAdded(file);
});
this.on("removedfile", (file) => {
$this.onFileRemoved(file);
});
this.on("dragleave", (event) => {
$this.onDragLeave(event);
});
this.on("drop", (event) => {
$this.onDrop(event);
});
}
/**
* 处理回调
* @param {File} file
* @param {Function} done
*/
accept(file, done) {
}
confirm(question, acceptd, rejected) {
console.log("confirm");
}
}
/**
* 界面逻辑
*/
class ViewLogic {
/**
* 构造函数
*/
constructor() {
var $this = this;
//分解完成的图片
$this.splitCompleteAry = [];
//是否正在分解中
$this.isSpliting = false;
//填充画布
$this.canvas = document.createElement("canvas");
$this.canvas.width = 2048;
$this.canvas.height = 2048;
//绘画上下文
$this.ctx = $this.canvas.getContext("2d");
var c = document.querySelector("#canvasRoot");
c.appendChild($this.canvas);
//上传处理
$this.btnUpload = document.getElementById("btn_package_file");
this.btnUpload.onclick = function (e) {
if (e.currentTarget != $this.btnUpload)return;
var dropzone = window.DropZoneLogic.dropzone;
var len = dropzone.files.length;
// if(len > 0){
// $this.btnUpload.style.display = "none";
// }
if($this.isSpliting){
alert("正在分解..");
return;
}
$this.isSpliting = true;
for (var i = 0; i < len; ++i) {
$this.saveFileToCanvas(dropzone.files[i]);
}
}
}
/**
* 保存数据
* @param {File} file
*/
saveFileToCanvas(file) {
var $this = this;
createImageBitmap(file).then((data) => {
//data: ImageBitmap
console.log(data);
$this.ctx.drawImage(data,0,0);
});
}
}
/**
* 主函数
*/
class Main {
constructor() {
this.initialize();
}
initialize() {
window.DropZoneLogic = new DropZoneLogic();
this.viewLogic = new ViewLogic();
}
}
new Main();
}()
上面的代码我们讲整个项目逻辑分为4块,入口逻辑Main函数,界面的拖动交互逻辑DropZoneLogic与分解的逻辑ViewLogic,另外我们将期间的数据存储在UpLoadFileData之中。另外这是第一次写JS的web项目,发现我随时都要注意this指针到底指到了什么,确实比较麻烦~~
到了这一步我们就可以实现了上传一个文件到浏览器,并通过Cavans绘制出来,接下来我们分割图片也会利用到canvas的API来实现切割图片。
教程二:https://blog.csdn.net/weixin_36719607/article/details/102647690
教程三:https://blog.csdn.net/weixin_36719607/article/details/102671621