一,安装用到的第三方库
1,安装:
liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm i -S vuedraggable@next added 2 packages in 11s
2,查看已安装的版本:
liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm list vuedraggable@next image2pdf@0.1.0 /data/vue/pdf/image2pdf └── vuedraggable@4.1.0
说明:此第三方库仅供在操作时拖动排序使用,与图片的合并无关
二,js代码:
<template>
<div>
<div style="width: 800px;margin: auto;">
<div style="margin-top: 10px;">
选择图片(可多选):
<input type="file" ref="hiddenfile" accept="image/*" multiple @change="handleFile" class="hiddenInput" />
</div>
<div style="width:400px;margin: auto;margin-top: 10px;">
<div style="width:400px;font-size:12px;">可以拖动图片改变顺序</div>
<draggable
:list="selFiles"
item-key="id"
class="list-group"
ghost-class="ghost"
@start="dragging = true"
@end="dragging = false"
>
<template #item="{ element,index }">
<div class="list-group-item">
<img class="fg" :id="'fg'+element.id" :src="element.fileimg" style="width:400px;display:block;" />
<div @click="del(index)"
style="width:40px;height:40px;position: absolute;top:0px;right:0px;">
<el-icon style="font-size: 20px;color:white;opacity:0.8;width:40px;height:40px;">
<Delete />
</el-icon>
</div>
</div>
</template>
</draggable>
</div>
<div>
<el-button ref="downButtonRef" :disabled="buttonEnable === true ? false : true" type="info" plain
@click="down" style="width:400px;margin-top: 10px;">合并图片并下载</el-button>
</div>
</div>
</div>
</template>
<script>
import {ref} from "vue"
import draggable from "vuedraggable";
export default {
name: "ImageMerge",
components: {
draggable,
},
setup() {
//最大高度和最大宽度
let maxWidth = 0;
let maxHeight = 0;
//选中的图片文件,保存在数组中
const selFiles = ref([]);
//得到各图片的最大高度和最大宽度
const getImgMaxWidthHeight = () => {
//let allHeight = 0;
for( var i=0;i<selFiles.value.length; i++ ){
let one = selFiles.value[i];
//得到高度
let img = document.getElementById("fg"+one.id);
let width = img.naturalWidth;
let height = img.naturalHeight;
console.log("width:"+width+";height:"+height);
if (width>maxWidth) {
maxWidth = width;
}
if (height > maxHeight) {
maxHeight = height;
}
}
console.log("maxWidth:"+maxWidth+";maxHeight:"+maxHeight);
}
//垂直方向合并时,得到高度:
const getImgDestHeight = () => {
let allHeight = 0;
for( var i=0;i<selFiles.value.length; i++ ){
let one = selFiles.value[i];
//得到高度
let img = document.getElementById("fg"+one.id);
let width = img.naturalWidth;
let height = img.naturalHeight;
let destHeightOne = (maxWidth * height) / width;
allHeight = allHeight+destHeightOne;
}
console.log("allHeight:"+allHeight);
return allHeight;
}
//下载pdf
const down = async () => {
getImgMaxWidthHeight();
//得到合并后图片的高度
let destHeight = getImgDestHeight();
console.log("destHeight:"+destHeight);
//生成合并后图片
const canvas = document.createElement('canvas')
canvas.width = maxWidth;
canvas.height = destHeight;
const context = canvas.getContext('2d');
let top = 0;
//合并图片
for( var i=0;i<selFiles.value.length; i++ ) {
console.log(i);
let one = selFiles.value[i];
//得到当前图片的高度
let img = document.getElementById("fg"+one.id);
let width = img.naturalWidth;
let height = img.naturalHeight;
let destHeightOne = (maxWidth * height) / width;
context.drawImage(img, 0, top, maxWidth, destHeightOne);
top = top+destHeightOne;
}
//下载图片
downJpgByCanvas(canvas);
}
//下载图片
const downJpgByCanvas = (canvas) => {
var oA = document.createElement("a");
let time = timeFormat();
oA.download = "img_"+time+'.jpg';// 设置下载的文件名,默认是'下载'
oA.href = canvas.toDataURL("image/jpeg");
document.body.appendChild(oA);
oA.click();
oA.remove(); // 下载之后把创建的元素删除
}
//选中图片时,把图片添加到数组
const handleFile = (e) => {
let filePaths = e.target.files;
//清空原有缩略图
if (filePaths.length === 0) {
//未选择,则返回
return
} else {
//清空数组中原有图片
selFiles.value.length = 0;
}
//把新选中的图片加入数组
for( var i=0;i<filePaths.length; i++ ){
let file = filePaths[i];
var reader = new FileReader();
reader.readAsArrayBuffer(file);
//reader.
let one = {
id:i,
fileimg:URL.createObjectURL(file), //预览用
file:file,
}
selFiles.value[i] = one;
}
setButton();
}
//设置下载button是否可用
const buttonEnable = ref(false);
const setButton = () => {
console.log("files length:"+selFiles.value.length);
if (selFiles.value.length>0) {
buttonEnable.value = true;
} else {
buttonEnable.value = false;
}
}
//补0
const add0 = (m) => {
return m<10?'0'+m:m
}
//格式化时间
const timeFormat = ()=>{
var time = new Date();
var y = time.getFullYear();
var m = time.getMonth()+1;
var d = time.getDate();
var h = time.getHours();
var mm = time.getMinutes();
var s = time.getSeconds();
let res = y+add0(m)+add0(d)+add0(h)+add0(mm)+add0(s);
return res;
}
return {
down,
handleFile,
selFiles,
buttonEnable,
}
}
}
</script>
<style scoped>
</style>
三,测试效果:
界面:
合并后的图片:
说明:刘宏缔的架构森林—专注it技术的博客,
网址:https://imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/06/02/vue-js3-duo-zhang-tu-pian-he-bing-vue-3-2-37/
代码: https://github.com/liuhongdi/ 或 https://gitee.com/liuhongdi
说明:作者:刘宏缔 邮箱: 371125307@qq.com
四,查看vue框架的版本:
liuhongdi@lhdpc:/data/vue/pdf/image2pdf$ npm list vue image2pdf@0.1.0 /data/vue/pdf/image2pdf ├─┬ @vue/cli-plugin-babel@5.0.8 │ └─┬ @vue/babel-preset-app@5.0.8 │ ├─┬ @vue/babel-preset-jsx@1.3.0 │ │ └── vue@3.2.37 deduped invalid: "2.x" from node_modules/@vue/babel-preset-jsx │ └── vue@3.2.37 deduped └─┬ vue@3.2.37 └─┬ @vue/server-renderer@3.2.37 └── vue@3.2.37 deduped