canvas生成图片

This commit is contained in:
sunmeng 2025-07-24 09:55:05 +08:00
parent f25c008fb5
commit abf63dc7d1
21 changed files with 318 additions and 113 deletions

View File

@ -6,6 +6,13 @@
{ {
"navigationBarTitleText" : "" "navigationBarTitleText" : ""
} }
},
{
"path" : "pages/index/canvas",
"style" :
{
"navigationBarTitleText" : ""
}
} }
], ],

95
pages/index/canvas.vue Normal file
View File

@ -0,0 +1,95 @@
<template>
<view>
<canvas
id="myCanvas"
canvas-id="myCanvas"
type="2d"
style="width: 800px; height: 600px; border: 1px solid #eee;"
></canvas>
</view>
</template>
<script>
export default {
props: {
imgUrl: String
},
data() {
return {
canvasContext: null
};
},
watch: {
imgUrl: {
handler() {
this.drawImage();
},
immediate: true
}
},
mounted() {
this.initCanvas();
},
methods: {
initCanvas() {
const query = uni.createSelectorQuery().in(this);
query.select('#myCanvas')
.fields({ node: true, size: true })
.exec((res) => {
if (!res[0]) return;
this.canvas = res[0].node;
this.ctx = res[0].node.getContext('2d');
this.canvasContext = this.ctx; //
const dpr = uni.getSystemInfoSync().pixelRatio;
this.canvas.width = res[0].width * dpr;
this.canvas.height = res[0].height * dpr;
this.ctx.scale(dpr, dpr);
// URL
if (this.imgUrl) {
this.drawImage();
}
});
},
async drawImage() {
if (!this.ctx || !this.imgUrl) return;
try {
const image = await this.loadImage(this.imgUrl);
this.clearCanvas();
this.ctx.drawImage(image, 0, 0, 800, 600);
} catch (e) {
console.error("图片加载失败:", e);
this.clearCanvas();
this.ctx.fillStyle = '#f0f0f0';
this.ctx.fillRect(0, 0, 1000, 800);
this.ctx.fillStyle = '#999';
this.ctx.textAlign = 'center';
this.ctx.textBaseline = 'middle';
this.ctx.fillText('图片加载失败', 150, 100);
}
},
clearCanvas() {
if (this.ctx) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
},
loadImage(src) {
return new Promise((resolve, reject) => {
const image = this.canvas.createImage();
image.src = src;
image.onload = () => resolve(image);
image.onerror = (err) => {
console.error('图片加载错误', err);
reject(err);
};
});
}
}
}
</script>

View File

@ -1,61 +1,26 @@
<template> <template>
<view> <view>
<canvas <canvasChild :imgUrl="'https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg'"></canvasChild>
id="myCanvas" </view>
canvas-id="myCanvas"
type="2d"
style="width: 300px; height: 200px; border: 1px solid #eee;"
></canvas>
</view>
</template> </template>
<script> <script>
export default { import canvasChild from './canvas'
onReady() { export default {
this.drawImageOnCanvas(); components:{
}, canvasChild
methods: { },
drawImageOnCanvas() { data() {
// Canvas return {
const query = uni.createSelectorQuery().in(this);
query.select('#myCanvas') }
.fields({ node: true, size: true }) },
.exec(async (res) => { methods: {
if (!res[0]) return;
}
const canvas = res[0].node; }
const ctx = canvas.getContext('2d'); </script>
const dpr = uni.getSystemInfoSync().pixelRatio;
this.canvas = canvas
//
canvas.width = res[0].width * dpr;
canvas.height = res[0].height * dpr;
ctx.scale(dpr, dpr);
// <style>
try {
const image = await this.loadImage('https://assets.tech.troyrc.com/sx25/images/background/odertupian.png'); </style>
ctx.drawImage(image, 0, 0, 300, 200);
} catch (e) {
console.error("图片加载失败:", e);
//
ctx.fillStyle = '#f0f0f0';
ctx.fillRect(0, 0, 300, 200);
ctx.fillStyle = '#999';
ctx.textAlign = 'center';
ctx.fillText('图片加载失败', 150, 100);
}
});
},
loadImage(src) {
return new Promise((resolve, reject) => {
const image = this.canvas.createImage();
image.onload = () => resolve(image);
image.onerror = reject;
image.src = src;
});
}
}
}
</script>

View File

@ -1 +1 @@
{"version":3,"file":"app.js","sources":["App.vue"],"sourcesContent":["<script>\n\texport default {\n\t\tonLaunch: function() {\n\t\t\tconsole.log('App Launch')\n\t\t},\n\t\tonShow: function() {\n\t\t\tconsole.log('App Show')\n\t\t},\n\t\tonHide: function() {\n\t\t\tconsole.log('App Hide')\n\t\t}\n\t}\n</script>\n\n<style>\n\t/*每个页面公共css */\n</style>\n"],"names":["uni"],"mappings":";;;;;;AACC,MAAK,YAAU;AAAA,EACd,UAAU,WAAW;AACpBA,kBAAAA,MAAY,MAAA,OAAA,gBAAA,YAAY;AAAA,EACxB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,gBAAA,UAAU;AAAA,EACtB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,iBAAA,UAAU;AAAA,EACvB;AACD;;;;;;;;;"} {"version":3,"file":"app.js","sources":["App.vue"],"sourcesContent":["<script>\n\texport default {\n\t\tonLaunch: function() {\n\t\t\tconsole.log('App Launch')\n\t\t},\n\t\tonShow: function() {\n\t\t\tconsole.log('App Show')\n\t\t},\n\t\tonHide: function() {\n\t\t\tconsole.log('App Hide')\n\t\t}\n\t}\n</script>\n\n<style>\n\t/*每个页面公共css */\n</style>\n"],"names":["uni"],"mappings":";;;;;;;AACC,MAAK,YAAU;AAAA,EACd,UAAU,WAAW;AACpBA,kBAAAA,MAAY,MAAA,OAAA,gBAAA,YAAY;AAAA,EACxB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,gBAAA,UAAU;AAAA,EACtB;AAAA,EACD,QAAQ,WAAW;AAClBA,kBAAAA,MAAY,MAAA,OAAA,iBAAA,UAAU;AAAA,EACvB;AACD;;;;;;;;;"}

View File

@ -0,0 +1 @@
{"version":3,"file":"canvas.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"version":3,"file":"canvas.js","sources":["pages/index/canvas.vue?type=page"],"sourcesContent":["import MiniProgramPage from '/Users/sunmeng/Desktop/wx/canvas/pages/index/canvas.vue'\nwx.createPage(MiniProgramPage)"],"names":["MiniProgramPage"],"mappings":";;AACA,GAAG,WAAWA,OAAe,eAAA;"}

View File

@ -0,0 +1 @@
{"version":3,"file":"canvas2.js","sources":["/Users/sunmeng/Desktop/wx/canvas/pages/index/canvas.vue?type=page"],"sourcesContent":["import MiniProgramPage from '/Users/sunmeng/Desktop/wx/canvas/pages/index/canvas.vue'\nwx.createPage(MiniProgramPage)"],"names":["MiniProgramPage"],"mappings":";;AACA,GAAG,WAAWA,OAAe,eAAA;"}

View File

@ -1 +1 @@
{"version":3,"file":"index.js","sources":["pages/index/index.vue?type=page"],"sourcesContent":["import MiniProgramPage from '/Users/sunmeng/Desktop/wx/canvas/pages/index/index.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"} {"version":3,"file":"index.js","sources":["pages/index/index.vue?type=page"],"sourcesContent":["import MiniProgramPage from '/Users/sunmeng/Desktop/wx/canvas/pages/index/index.vue'\nwx.createPage(MiniProgramPage)"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AACA,GAAG,WAAW,eAAe;"}

View File

@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const common_vendor = require("./common/vendor.js"); const common_vendor = require("./common/vendor.js");
if (!Math) { if (!Math) {
"./pages/index/index.js"; "./pages/index/index.js";
"./pages/index/canvas.js";
} }
const _sfc_main = { const _sfc_main = {
onLaunch: function() { onLaunch: function() {

View File

@ -1,6 +1,7 @@
{ {
"pages": [ "pages": [
"pages/index/index" "pages/index/index",
"pages/index/canvas"
], ],
"window": { "window": {
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black",

82
unpackage/dist/dev/mp-weixin/canvas.js vendored Normal file
View File

@ -0,0 +1,82 @@
"use strict";
const common_vendor = require("./common/vendor.js");
const _sfc_main = {
props: {
imgUrl: String
},
data() {
return {
canvasContext: null
};
},
watch: {
imgUrl: {
handler() {
this.drawImage();
},
immediate: true
}
},
mounted() {
this.initCanvas();
},
methods: {
initCanvas() {
const query = common_vendor.index.createSelectorQuery().in(this);
query.select("#myCanvas").fields({ node: true, size: true }).exec((res) => {
if (!res[0])
return;
this.canvas = res[0].node;
this.ctx = res[0].node.getContext("2d");
this.canvasContext = this.ctx;
const dpr = common_vendor.index.getSystemInfoSync().pixelRatio;
this.canvas.width = res[0].width * dpr;
this.canvas.height = res[0].height * dpr;
this.ctx.scale(dpr, dpr);
if (this.imgUrl) {
this.drawImage();
}
});
},
async drawImage() {
if (!this.ctx || !this.imgUrl)
return;
try {
const image = await this.loadImage(this.imgUrl);
this.clearCanvas();
this.ctx.drawImage(image, 0, 0, 800, 600);
} catch (e) {
common_vendor.index.__f__("error", "at pages/index/canvas.vue:65", "图片加载失败:", e);
this.clearCanvas();
this.ctx.fillStyle = "#f0f0f0";
this.ctx.fillRect(0, 0, 1e3, 800);
this.ctx.fillStyle = "#999";
this.ctx.textAlign = "center";
this.ctx.textBaseline = "middle";
this.ctx.fillText("图片加载失败", 150, 100);
}
},
clearCanvas() {
if (this.ctx) {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
},
loadImage(src) {
return new Promise((resolve, reject) => {
const image = this.canvas.createImage();
image.src = src;
image.onload = () => resolve(image);
image.onerror = (err) => {
common_vendor.index.__f__("error", "at pages/index/canvas.vue:88", "图片加载错误", err);
reject(err);
};
});
}
}
};
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {};
}
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
exports.MiniProgramPage = MiniProgramPage;
//# sourceMappingURL=../.sourcemap/mp-weixin/canvas.js.map

View File

@ -1252,6 +1252,9 @@ function isReadonly(value) {
function isShallow(value) { function isShallow(value) {
return !!(value && value["__v_isShallow"]); return !!(value && value["__v_isShallow"]);
} }
function isProxy(value) {
return isReactive(value) || isReadonly(value);
}
function toRaw(observed) { function toRaw(observed) {
const raw = observed && observed["__v_raw"]; const raw = observed && observed["__v_raw"];
return raw ? toRaw(raw) : observed; return raw ? toRaw(raw) : observed;
@ -2043,6 +2046,47 @@ function setCurrentRenderingInstance(instance) {
instance && instance.type.__scopeId || null; instance && instance.type.__scopeId || null;
return prev; return prev;
} }
const COMPONENTS = "components";
function resolveComponent(name, maybeSelfReference) {
return resolveAsset(COMPONENTS, name, true, maybeSelfReference) || name;
}
function resolveAsset(type, name, warnMissing = true, maybeSelfReference = false) {
const instance = currentRenderingInstance || currentInstance;
if (instance) {
const Component2 = instance.type;
if (type === COMPONENTS) {
const selfName = getComponentName(
Component2,
false
);
if (selfName && (selfName === name || selfName === camelize(name) || selfName === capitalize(camelize(name)))) {
return Component2;
}
}
const res = (
// local registration
// check instance[type] first which is resolved for options API
resolve(instance[type] || Component2[type], name) || // global registration
resolve(instance.appContext[type], name)
);
if (!res && maybeSelfReference) {
return Component2;
}
if (warnMissing && !res) {
const extra = type === COMPONENTS ? `
If this is a native custom element, make sure to exclude it from component resolution via compilerOptions.isCustomElement.` : ``;
warn$1(`Failed to resolve ${type.slice(0, -1)}: ${name}${extra}`);
}
return res;
} else {
warn$1(
`resolve${capitalize(type.slice(0, -1))} can only be used in render() or setup().`
);
}
}
function resolve(registry, name) {
return registry && (registry[name] || registry[camelize(name)] || registry[capitalize(camelize(name))]);
}
const INITIAL_WATCHER_VALUE = {}; const INITIAL_WATCHER_VALUE = {};
function watch(source, cb, options) { function watch(source, cb, options) {
if (!isFunction(cb)) { if (!isFunction(cb)) {
@ -3653,6 +3697,12 @@ const Static = Symbol.for("v-stc");
function isVNode(value) { function isVNode(value) {
return value ? value.__v_isVNode === true : false; return value ? value.__v_isVNode === true : false;
} }
const InternalObjectKey = `__vInternal`;
function guardReactiveProps(props) {
if (!props)
return null;
return isProxy(props) || InternalObjectKey in props ? extend({}, props) : props;
}
const emptyAppContext = createAppContext(); const emptyAppContext = createAppContext();
let uid = 0; let uid = 0;
function createComponentInstance(vnode, parent, suspense) { function createComponentInstance(vnode, parent, suspense) {
@ -4891,6 +4941,11 @@ function initApp(app) {
} }
} }
const propsCaches = /* @__PURE__ */ Object.create(null); const propsCaches = /* @__PURE__ */ Object.create(null);
function renderProps(props) {
const { uid: uid2, __counter } = getCurrentInstance();
const propsId = (propsCaches[uid2] || (propsCaches[uid2] = [])).push(guardReactiveProps(props)) - 1;
return uid2 + "," + propsId + "," + __counter;
}
function pruneComponentPropsCache(uid2) { function pruneComponentPropsCache(uid2) {
delete propsCaches[uid2]; delete propsCaches[uid2];
} }
@ -4931,6 +4986,7 @@ function getCreateApp() {
return my[method]; return my[method];
} }
} }
const p = (props) => renderProps(props);
function createApp$1(rootComponent, rootProps = null) { function createApp$1(rootComponent, rootProps = null) {
rootComponent && (rootComponent.mpType = "app"); rootComponent && (rootComponent.mpType = "app");
return createVueApp(rootComponent, rootProps).use(plugin); return createVueApp(rootComponent, rootProps).use(plugin);
@ -5251,8 +5307,8 @@ function promisify$1(name, fn) {
if (hasCallback(args)) { if (hasCallback(args)) {
return wrapperReturnValue(name, invokeApi(name, fn, args, rest)); return wrapperReturnValue(name, invokeApi(name, fn, args, rest));
} }
return wrapperReturnValue(name, handlePromise(new Promise((resolve, reject) => { return wrapperReturnValue(name, handlePromise(new Promise((resolve2, reject) => {
invokeApi(name, fn, extend(args, { success: resolve, fail: reject }), rest); invokeApi(name, fn, extend(args, { success: resolve2, fail: reject }), rest);
}))); })));
}; };
} }
@ -5567,7 +5623,7 @@ function invokeGetPushCidCallbacks(cid2, errMsg) {
getPushCidCallbacks.length = 0; getPushCidCallbacks.length = 0;
} }
const API_GET_PUSH_CLIENT_ID = "getPushClientId"; const API_GET_PUSH_CLIENT_ID = "getPushClientId";
const getPushClientId = defineAsyncApi(API_GET_PUSH_CLIENT_ID, (_, { resolve, reject }) => { const getPushClientId = defineAsyncApi(API_GET_PUSH_CLIENT_ID, (_, { resolve: resolve2, reject }) => {
Promise.resolve().then(() => { Promise.resolve().then(() => {
if (typeof enabled === "undefined") { if (typeof enabled === "undefined") {
enabled = false; enabled = false;
@ -5576,7 +5632,7 @@ const getPushClientId = defineAsyncApi(API_GET_PUSH_CLIENT_ID, (_, { resolve, re
} }
getPushCidCallbacks.push((cid2, errMsg) => { getPushCidCallbacks.push((cid2, errMsg) => {
if (cid2) { if (cid2) {
resolve({ cid: cid2 }); resolve2({ cid: cid2 });
} else { } else {
reject(errMsg); reject(errMsg);
} }
@ -5645,9 +5701,9 @@ function promisify(name, api) {
if (isFunction(options.success) || isFunction(options.fail) || isFunction(options.complete)) { if (isFunction(options.success) || isFunction(options.fail) || isFunction(options.complete)) {
return wrapperReturnValue(name, invokeApi(name, api, options, rest)); return wrapperReturnValue(name, invokeApi(name, api, options, rest));
} }
return wrapperReturnValue(name, handlePromise(new Promise((resolve, reject) => { return wrapperReturnValue(name, handlePromise(new Promise((resolve2, reject) => {
invokeApi(name, api, extend({}, options, { invokeApi(name, api, extend({}, options, {
success: resolve, success: resolve2,
fail: reject fail: reject
}), rest); }), rest);
}))); })));
@ -6236,13 +6292,13 @@ function initRuntimeSocket(hosts, port, id) {
} }
const SOCKET_TIMEOUT = 500; const SOCKET_TIMEOUT = 500;
function tryConnectSocket(host2, port, id) { function tryConnectSocket(host2, port, id) {
return new Promise((resolve, reject) => { return new Promise((resolve2, reject) => {
const socket = index.connectSocket({ const socket = index.connectSocket({
url: `ws://${host2}:${port}/${id}`, url: `ws://${host2}:${port}/${id}`,
multiple: true, multiple: true,
// 支付宝小程序 是否开启多实例 // 支付宝小程序 是否开启多实例
fail() { fail() {
resolve(null); resolve2(null);
} }
}); });
const timer = setTimeout(() => { const timer = setTimeout(() => {
@ -6250,19 +6306,19 @@ function tryConnectSocket(host2, port, id) {
code: 1006, code: 1006,
reason: "connect timeout" reason: "connect timeout"
}); });
resolve(null); resolve2(null);
}, SOCKET_TIMEOUT); }, SOCKET_TIMEOUT);
socket.onOpen((e) => { socket.onOpen((e) => {
clearTimeout(timer); clearTimeout(timer);
resolve(socket); resolve2(socket);
}); });
socket.onClose((e) => { socket.onClose((e) => {
clearTimeout(timer); clearTimeout(timer);
resolve(null); resolve2(null);
}); });
socket.onError((e) => { socket.onError((e) => {
clearTimeout(timer); clearTimeout(timer);
resolve(null); resolve2(null);
}); });
}); });
} }
@ -6694,7 +6750,7 @@ function initOnError() {
function initRuntimeSocketService() { function initRuntimeSocketService() {
const hosts = "127.0.0.1,172.10.0.205"; const hosts = "127.0.0.1,172.10.0.205";
const port = "8090"; const port = "8090";
const id = "mp-weixin_UOOu72"; const id = "mp-weixin_S3vPwR";
const lazy = typeof swan !== "undefined"; const lazy = typeof swan !== "undefined";
let restoreError = lazy ? () => { let restoreError = lazy ? () => {
} : initOnError(); } : initOnError();
@ -7636,4 +7692,6 @@ const createSubpackageApp = initCreateSubpackageApp();
exports._export_sfc = _export_sfc; exports._export_sfc = _export_sfc;
exports.createSSRApp = createSSRApp; exports.createSSRApp = createSSRApp;
exports.index = index; exports.index = index;
exports.p = p;
exports.resolveComponent = resolveComponent;
//# sourceMappingURL=../../.sourcemap/mp-weixin/common/vendor.js.map //# sourceMappingURL=../../.sourcemap/mp-weixin/common/vendor.js.map

View File

@ -0,0 +1,4 @@
"use strict";
const canvas = require("../../canvas.js");
wx.createPage(canvas.MiniProgramPage);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/index/canvas.js.map

View File

@ -0,0 +1,4 @@
{
"navigationBarTitleText": "",
"usingComponents": {}
}

View File

@ -0,0 +1 @@
<view><canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width:800px;height:600px;border:1px solid #eee"></canvas></view>

View File

View File

@ -0,0 +1,4 @@
"use strict";
const canvas = require("../../canvas.js");
wx.createPage(canvas.MiniProgramPage);
//# sourceMappingURL=../../../.sourcemap/mp-weixin/pages/index/canvas2.js.map

View File

@ -1,47 +1,25 @@
"use strict"; "use strict";
const common_vendor = require("../../common/vendor.js"); const common_vendor = require("../../common/vendor.js");
const canvasChild = () => "./canvas2.js";
const _sfc_main = { const _sfc_main = {
onReady() { components: {
this.drawImageOnCanvas(); canvasChild
}, },
methods: { data() {
drawImageOnCanvas() { return {};
const query = common_vendor.index.createSelectorQuery().in(this); },
query.select("#myCanvas").fields({ node: true, size: true }).exec(async (res) => { methods: {}
if (!res[0])
return;
const canvas = res[0].node;
const ctx = canvas.getContext("2d");
const dpr = common_vendor.index.getSystemInfoSync().pixelRatio;
this.canvas = canvas;
canvas.width = res[0].width * dpr;
canvas.height = res[0].height * dpr;
ctx.scale(dpr, dpr);
try {
const image = await this.loadImage("https://assets.tech.troyrc.com/sx25/images/background/odertupian.png");
ctx.drawImage(image, 0, 0, 300, 200);
} catch (e) {
common_vendor.index.__f__("error", "at pages/index/index.vue:40", "图片加载失败:", e);
ctx.fillStyle = "#f0f0f0";
ctx.fillRect(0, 0, 300, 200);
ctx.fillStyle = "#999";
ctx.textAlign = "center";
ctx.fillText("图片加载失败", 150, 100);
}
});
},
loadImage(src) {
return new Promise((resolve, reject) => {
const image = this.canvas.createImage();
image.onload = () => resolve(image);
image.onerror = reject;
image.src = src;
});
}
}
}; };
if (!Array) {
const _component_canvasChild = common_vendor.resolveComponent("canvasChild");
_component_canvasChild();
}
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) { function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return {}; return {
a: common_vendor.p({
imgUrl: "https://assets.tech.troyrc.com/sx25/images/events/XBDT.jpg"
})
};
} }
const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]); const MiniProgramPage = /* @__PURE__ */ common_vendor._export_sfc(_sfc_main, [["render", _sfc_render]]);
wx.createPage(MiniProgramPage); wx.createPage(MiniProgramPage);

View File

@ -1,4 +1,6 @@
{ {
"navigationBarTitleText": "", "navigationBarTitleText": "",
"usingComponents": {} "usingComponents": {
"canvas-child": "./canvas"
}
} }

View File

@ -1 +1 @@
<view><canvas id="myCanvas" canvas-id="myCanvas" type="2d" style="width:300px;height:200px;border:1px solid #eee"></canvas></view> <view><canvas-child wx:if="{{a}}" u-i="42112c14-0" bind:__l="__l" u-p="{{a}}"></canvas-child></view>