123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523 |
- <!-- mosowe-canvas-image -->
- <template>
- <view class='mosowe-canvas-image'>
- <view class="slot-view" @click="createCanvas">
- <slot></slot>
- </view>
- <view class="canvas-wrap-box">
- <!-- 主面板绘制 -->
- <canvas class="canvas-wrap" canvas-id="canvas"
- :style="'width: '+ width +'px; height: '+ height +'px;'"></canvas>
- <!-- 这个是用来绘制圆形图片的 -->
- <canvas class="canvas-wrap" canvas-id="canvas-arc"
- :style="'width: '+ canvasArcWidth +'px; height: '+ canvasArcHeight +'px;'"></canvas>
- </view>
- </view>
- </template>
- <script>
- import QR from './wxqrcode.js';
- export default {
- name: 'mosowe-canvas-image',
- components: {},
- props: {
- imgType: { // 图片类型
- type: String,
- default: 'jpg',
- validator: () => {
- return ['jpg', 'png'];
- }
- },
- compress: { // 是否开启压缩
- type: Boolean,
- default: false
- },
- compressSize: { // 压缩界限,超过界限压缩,默认2M
- type: [Number, String],
- default: 1024 * 1024 * 2
- },
- showPreview: { // 生成图像后是否预览
- type: Boolean,
- default: false
- },
- height: { // canvas高度
- type: [String, Number],
- default: 200
- },
- width: { // canvas宽度
- type: [String, Number],
- default: 200
- },
- lists: {
- type: Array,
- default: () => {
- return [];
- }
- }
- },
- data() {
- return {
- canvas: null,
- listsIndex: 0,
- listsLength: 0,
- canvasArc: null,
- canvasArcWidth: 100,
- canvasArcHeight: 100,
- compressQuality: 20,
- compressQualityH5: 5,
- };
- },
- watch: {},
- // 组件实例化之前
- beforeCreate() {},
- // 组件创建完成
- created() {
- this.canvas = uni.createCanvasContext('canvas', this);
- this.canvasArc = uni.createCanvasContext('canvas-arc', this);
- },
- // 组件挂载之前
- beforeMount() {},
- // 组件挂载之后
- mounted() {},
- // 组件数据更新时
- beforeUpdate() {},
- // 组价更新
- updated() {},
- // 组件销毁前
- beforeDestroy() {},
- // 组件销毁后
- destroyed() {},
- // 页面方法
- methods: {
- // 开始绘制
- createCanvas() {
- this.clearCanvas();
- if (this.lists.length === 0) {
- uni.showToast({
- title: 'lists不能为空',
- icon: 'none'
- });
- return;
- }
- this.listsIndex = 0;
- this.listsLength = this.lists.length - 1;
- uni.showLoading({
- title: '正在生成图片...',
- mask: true
- });
- // 先生成一个白色背景
- this.canvas.setFillStyle('#fff');
- this.canvas.globalAlpha = 1;
- this.canvas.fillRect(0, 0, this.width, this.height);
- this.dataDrawCanvas();
- },
- // 数据绘制
- dataDrawCanvas() {
- let item = this.lists[this.listsIndex];
- if (item.type === 'image') { // 图片
- if (item.content.indexOf('https://') > -1) { // https://网络图片
- // #ifndef H5
- // 非H5
- this.downloadImageNotH5(item);
- // #endif
- // #ifdef H5
- // H5
- this.downloadImageH5(item);
- // #endif
- } else { // 本地选择图片
- if (this.compress && item.hasOwnProperty('file') && item.file.size > this
- .compressSize) { // 大于限制2M压缩
- this.compressImage(item);
- } else {
- if (item.arc) {
- this.drawImageArc(item);
- } else {
- this.drawImage(item);
- }
- }
- }
- } else if (item.type === 'text') { // 文本
- this.drawText(item);
- } else if (item.type === 'rect') { // 矩形(线条)
- this.drawRect(item);
- } else if (item.type === 'arc') { // 圆形
- this.drawArc(item);
- } else if (item.type === 'qr') { // 二维码
- this.drawQR(item);
- }
- },
- // #ifndef H5
- // https图片下载本地并绘制,非H5
- downloadImageNotH5(item) {
- uni.downloadFile({
- url: item.content,
- header: {
- 'Access-Control-Allow-Origin': '*',
- },
- success: (res) => {
- item.content = res.tempFilePath;
- if (item.arc) {
- this.drawImageArc(item);
- } else {
- this.drawImage(item);
- }
- },
- fail: (res) => {
- console.log(res);
- }
- });
- },
- // #endif
- // #ifdef H5
- // https图片下载本地并绘制,H5
- downloadImageH5(item) {
- let image = null;
- image = new Image();
- image.setAttribute('crossOrigin', 'anonymous');
- image.crossOrigin = 'Anonymous';
- image.src = item.content;
- image.onload = () => {
- let canvas = document.createElement('canvas');
- canvas.width = item.width;
- canvas.height = item.height;
- let ctx = canvas.getContext('2d');
- ctx.drawImage(
- image,
- 0,
- 0,
- item.width,
- item.height
- );
- let dataURL = canvas.toDataURL('image/png');
- if (item.arc) { // 绘制圆形
- item.content = dataURL;
- this.drawImageArc(item);
- } else {
- this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
- this.canvas.drawImage(
- dataURL,
- item.x,
- item.y,
- item.hasOwnProperty('width') ? item.width : this.width,
- item.hasOwnProperty('height') ? item.height : this.height
- );
- this.checkDrawOver();
- }
- };
- },
- // #endif
- // 图片压缩
- compressImage(item) {
- uni.showLoading({
- title: '压缩中...',
- mask: true
- });
- // 非H5压缩
- // #ifndef H5
- uni.compressImage({
- src: item.content,
- quality: this.compressQuality,
- success: (res) => {
- uni.showLoading({
- title: '正在生成图片...',
- mask: true
- });
- item.content = res.tempFilePath;
- if (item.arc) {
- this.drawImageArc(item);
- } else {
- this.drawImage(item);
- }
- },
- fail: (res) => {
- console.log(res);
- uni.showToast({
- title: '压缩失败',
- icon: 'none'
- });
- }
- });
- // #endif
- // H5压缩
- // #ifdef H5
- let image = new Image();
- image.setAttribute('crossOrigin', 'anonymous');
- image.crossOrigin = 'Anonymous';
- image.src = item.content;
- image.onload = () => {
- let canvas = document.createElement('canvas');
- canvas.width = item.width;
- canvas.height = item.height;
- let ctx = canvas.getContext('2d');
- ctx.drawImage(
- image,
- 0,
- 0,
- item.width,
- item.height
- );
- let dataURL = canvas.toDataURL('image/png');
- item.content = dataURL;
- if (item.arc) {
- this.drawImageArc(item);
- } else {
- this.drawImage(item);
- }
- };
- // #endif
- },
- // 圆形图片另外绘制canvas,png格式
- drawImageArc(item) {
- this.canvasArc.clearRect(0, 0, this.canvasArcWidth, this.canvasArcHeight);
- this.canvasArcWidth = item.arcR * 2;
- this.canvasArcHeight = item.arcR * 2;
- this.canvasArc.save();
- let arcT = setTimeout(() => {
- clearTimeout(arcT);
- this.canvasArc.arc(item.arcR, item.arcR, item.arcR, 0, 2 * Math.PI);
- this.canvasArc.clip();
- // this.canvasArc.closePath();
- this.canvasArc.drawImage(
- item.content,
- item.arcX,
- item.arcY,
- item.width,
- item.height
- );
- this.canvasArc.draw(false, setTimeout(() => {
- let t = setTimeout(() => {
- clearTimeout(t);
- uni.canvasToTempFilePath({
- x: 0,
- y: 0,
- width: item.arcR * 2,
- height: item.arcR * 2,
- fileType: 'png',
- canvasId: 'canvas-arc',
- success: (res) => {
- item.width = item.arcR * 2;
- item.height = item.arcR * 2;
- item.content = res.tempFilePath;
- this.drawImage(item);
- },
- fail: (res) => {
- console.log(res);
- },
- complete: () => {
- this.canvasArc.restore();
- this.canvasArc.fillRect(0, 0, 0, 0);
- this.canvasArc.clearRect(0, 0, this
- .canvasArcWidth, this.canvasArcHeight);
- }
- }, this);
- }, 100);
- }));
- }, 100);
- },
- // 图片绘制
- drawImage(item) {
- this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
- this.canvas.drawImage(
- item.content,
- item.x,
- item.y,
- item.hasOwnProperty('width') ? item.width : this.width,
- item.hasOwnProperty('height') ? item.height : this.height
- );
- this.checkDrawOver();
- },
- // 文本绘制
- drawText(item) {
- this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
- // this.canvas.setFontSize(item.hasOwnProperty('size') ? item.size : 20);
- this.canvas.setFontSize(10);
- let font = (item.hasOwnProperty('weight') ? item.weight : 'normal') + (item.hasOwnProperty('style') ? ' ' + item.style : ' normal') + (item.hasOwnProperty('size') ? ' ' + item.size : ' 10px') + (item.hasOwnProperty('family') ? ' ' + item.family : ' sans-serif')
- this.canvas.font = font
- this.canvas.setTextAlign(item.hasOwnProperty('align') ? item.align : 'left');
- this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
- if (item.maxWidth) {
- this.canvas.fillText(item.content, item.x, item.y, item.maxWidth);
- } else {
- this.canvas.fillText(item.content, item.x, item.y);
- }
- this.checkDrawOver();
- },
- // 矩形(线条)绘制
- drawRect(item) {
- this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
- this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
- this.canvas.fillRect(item.x, item.y, item.width, item.height);
- this.checkDrawOver();
- },
- // 圆形绘制
- drawArc(item) {
- this.canvas.arc(item.arcX, item.arcY, item.arcR, 0, 2 * Math.PI);
- this.canvas.setFillStyle(item.hasOwnProperty('color') ? item.color : '#000000');
- this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
- this.canvas.fill();
- this.canvas.closePath();
- this.checkDrawOver();
- },
- // 二维码绘制
- async drawQR(item) {
- await this.removeSave();
- console.log("content:", item.content)
- let projectid = item.hasOwnProperty('projectid') ? item.projectid : "tmp_base64src";
- item.content = await this.base64ToSave(item.content, projectid);
- // item.content = "wxfile://usr/tmp_base64src.png"
- console.log("content:", item.content)
- if (item.content) {
- this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
- this.canvas.drawImage(
- item.content,
- item.x,
- item.y,
- item.hasOwnProperty('width') ? item.width : this.width,
- item.hasOwnProperty('height') ? item.height : this.height
- );
- }
- // item['qr'] = QR.createQrCodeImg(item.content, {
- // size: parseInt(300)
- // });
- // console.log("qr: ", item.qr)
- // this.canvas.globalAlpha = item.hasOwnProperty('globalAlpha') ? item.globalAlpha : 1;
- // this.canvas.drawImage(
- // item.qr,
- // item.x,
- // item.y,
- // item.hasOwnProperty('width') ? item.width : this.width,
- // item.hasOwnProperty('height') ? item.height : this.height
- // );
- this.checkDrawOver();
- },
- // 判断是否绘制完
- checkDrawOver() {
- if (this.listsIndex < this.listsLength) { // lists未画完
- this.listsIndex++;
- this.dataDrawCanvas();
- } else {
- this.canvasImage();
- }
- },
- // 绘制到画布并生成图片
- canvasImage() {
- this.listsIndex = 0
- this.canvas.draw(false, setTimeout(() => {
- setTimeout(() => {
- uni.canvasToTempFilePath({
- x: 0,
- y: 0,
- width: Number(this.width),
- height: Number(this.height),
- fileType: this.imgType,
- canvasId: 'canvas',
- success: (res) => {
- this.$emit('canvasImage', res.tempFilePath);
- if (this.showPreview) {
- this.showPreviewFn(res.tempFilePath);
- }
- },
- fail: (res) => {
- console.log(res);
- },
- complete: () => {
- uni.hideLoading();
- }
- }, this);
- }, 500);
- }));
- },
- // 预览图
- showPreviewFn(img) {
- uni.previewImage({
- current: 0,
- urls: [img]
- });
- },
- // 清空画布
- clearCanvas() {
- this.canvas.clearRect(0, 0, this.width, this.height);
- },
- removeSave(FILE_BASE_NAME = 'tmp_base64src', format = 'jpg') {
- return new Promise((resolve) => {
- // 把文件删除后再写进,防止超过最大范围而无法写入
- const fsm = uni.getFileSystemManager(); //文件管理器
- const FILE_BASE_NAME = 'tmp_base64src';
- const format = 'png';
- const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
- fsm.unlink({
- filePath: filePath,
- success(res) {
- console.log('文件删除成功');
- resolve(true);
- },
- fail(e) {
- console.log('readdir文件删除失败:', e);
- resolve(true);
- }
- });
- })
- },
- base64ToSave(base64data, FILE_BASE_NAME = 'tmp_base64src') {
- const fsm = uni.getFileSystemManager();
- return new Promise((resolve, reject) => {
- //format这个跟base64数据的开头对应
- const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
- if (!format) {
- reject(new Error('ERROR_BASE64SRC_PARSE'));
- }
- const filePath = `${wx.env.USER_DATA_PATH}/${FILE_BASE_NAME}.${format}`;
- //const buffer = wx.base64ToArrayBuffer(bodyData);
- fsm.writeFile({
- filePath,
- data: bodyData,
- //data: base64data.split(";base64,")[1],
- encoding: 'base64',
- success() {
- console.log("保存成功")
- resolve(filePath);
- },
- fail() {
- console.log("保存失败")
- reject(new Error('ERROR_BASE64SRC_WRITE'));
- },
- });
- });
- },
- }
- };
- </script>
- <style lang='scss' scoped>
- .mosowe-canvas-image {
- overflow: hidden;
- .canvas-wrap-box {
- overflow: hidden;
- height: 0;
- width: 0;
- position: fixed;
- left: 200%;
- top: 0;
- }
- .canvas-wrap {
- overflow: hidden;
- height: 0;
- width: 0;
- }
- }
- </style>
|