uni-app Canvas的drawImage 本地文件uri不显示file:///开头
uni-app Canvas的drawImage 本地文件uri不显示file:///开头
开发环境 | 版本号 | 项目创建方式 |
---|---|---|
Mac | 12.3 | HBuilderX |
产品分类:uniapp/App
PC开发环境操作系统:Mac
HBuilderX类型:正式
HBuilderX版本号:4.36
手机系统:Android
手机系统版本号:Android 13
手机厂商:模拟器
手机机型:模拟器
页面类型:vue
vue版本:vue3
打包方式:离线
项目创建方式:HBuilderX
示例代码:
<template>
<view class="container">
<view style="display: flex;flex-direction: row;justify-content: space-around;" >
<view @click="onClick('clear')">清空</view>
<view @click="onClick('undo')">撤消</view>
<view @click="onClick('save')">保存</view>
</view>
<view style="width: 750rpx ;height: 750rpx;">
<canvas id="myCanvas" @touchstart="startDrawing" @touchmove="draw" @touchend="endDrawing" style="width: 100%; height: 100%;">
</canvas>
</view>
<view style="flex-direction: row;height: 300upx;">
<scroll-view style="background-color: aliceblue; flex-direction: row;flex:5" direction="horizontal" id="scrollViewImgList">
<view v-for="(item,index) in imgList" @click="clickItem(item,index)">
<image :src="item" style="width: 100rpx;" mode="widthFix" />
</view>
</scroll-view>
<view style="flex:1;justify-content: center;align-items: center;height: 300upx;">
新增
</view>
</view>
</view>
</template>
<script>
import * as MCanvas from "@/uni_modules/czm-canvas"
type MImageData={
path:string,
imageData:ImageData
}
export default {
data() {
return {
title: 'Hello',
penColor: 'red',
canvasWidth: 0,
canvasHeight: 0,
penSize: 5,
url: '',
lastX: 0,
lastY: 0,
isDrawing: false,
openSmooth: true,
offsetTop: 0,
offsetLeft: 0,
canvas: null as UniCanvasElement | null,
canvasContext: null as CanvasContext | null,
ctx: null as CanvasRenderingContext2D | null,
imageSrc: 'file:///storage/emulated/0/Android/data/io.dcloud.uniappx/cache/uni-snapshot/1733203538080.png',
imgList: [] as Array<String>,
mImageList:[] as Array<MImageData>,
dpr:1
}
},
onLoad() {
uni.createCanvasContextAsync({
id: 'myCanvas',
component: this,
success: (context : CanvasContext) => {
this.canvasContext = context;
this.ctx = context.getContext('2d')!;
this.canvas = this.ctx!.canvas;
this.canvasWidth = this.canvas!.height;
this.canvasHeight = this.canvas!.width;
this.offsetTop = this.canvas!.offsetTop;
this.offsetLeft = this.canvas!.offsetLeft;
console.log("canvas success");
// 处理高清屏 scale防止canvas获取的像素位置不对
this.dpr = uni.getDeviceInfo().devicePixelRatio ?? 1;
console.log("dpr", this.dpr)
this.canvas!.width = this.canvas!.offsetWidth * this.dpr;
this.canvas!.height = this.canvas!.offsetHeight * this.dpr;
this.ctx!.scale(this.dpr, this.dpr); // 仅需调用一次,当调用 reset 方法后需要再次 scale
},
fail(error : UniError) {
console.log("create error", error.errMsg)
}
})
},
onReady() {
},
methods: {
clickItem(item:string,index:number){
this.clearCanvas();
//显示图片
console.log("item",item);
// console.log("imageData",this.mImageList[index].imageData);
// this.ctx!.putImageData(this.mImageList[index].imageData,0,0);
// let retstr=MCanvas.drawFileImg(item);
// console.log("retstr",retstr);
// MCanvas.getType(this.mImageList[index].imageData);
let width= 300;
let height=300;
console.log("this.canvasWidth,this.canvasHeight",this.canvasWidth+"---"+this.canvasHeight)
const image=new Image(width,height);
image.src="file://"+item;
image.setAttribute("mode","widthFix");
image.onload = () => {
this.ctx!.drawImage(image,0,0,width,height);
}
},
//3个按钮点击处理
onClick(type : string) {
if (type == 'undo') {
}
if (type == 'save') {
this.saveEleToFile()
}
if (type == 'clear') {
this.clearCanvas()
}
},
saveEleToFile() {
this.canvas!.takeSnapshot({
success: function (res) {
// 打印截图文件临时路径
console.log(res.tempFilePath)
this.imageSrc = res.tempFilePath
this.imgList.push(this.imageSrc);
const imageData=this.ctx?.getImageData(0,0,this.canvasWidth,this.canvasHeight) as ImageData
// console.log("imageData",imageData.data.buffer)
const imageItem={path:this.imageSrc,imageData} as MImageData ;
this.mImageList.push(imageItem);
uni.getElementById("scrollViewImgList") as UniElement;
},
fail: function (res) {
console.log(res)
uni.showToast({
icon: 'error',
title: '截图失败'
})
}
} as TakeSnapshotOptions)
},
clearCanvas(){
this.ctx?.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
},
//开始touch
startDrawing(e : UniTouchEvent) {
this.isDrawing = true;
const touchEvent = e.touches[0];
this.lastX = touchEvent.clientX - this.offsetLeft;
this.lastY = touchEvent.clientY - this.offsetTop;
this.ctx!.beginPath();
},
//touchmove
draw(e : UniTouchEvent) {
if (!this.isDrawing) return;
const touchEvent = e.touches[0];
const endx = touchEvent.clientX - this.offsetLeft;
const endy = touchEvent.clientY - this.offsetTop;
this.ctx?.moveTo(this.lastX, this.lastY)
this.ctx!.lineTo(endx, endy);
// console.log("endx", endx + ":" + endy)
this.ctx!.stroke();
this.lastX = endx;
this.lastY = endy;
},
//touchend
endDrawing() {
this.isDrawing = false;
}
}
}
</script>
操作步骤:
uniappx项目 如果吧image.src=“file://”+item; 这个改成网络图片可以显示 本地图片不能显示
预期结果:
需要本地图片也能显示并支持mode属性
实际结果:
本地图片不能显示
bug描述:
CanvasRenderingContext2D 的drawImage本地图片不能显示,只能显示网络图片和static工程目录下的图片 也不支持设置mode
在uni-app中,使用Canvas的drawImage
方法时,如果你遇到本地文件URI不显示的问题,特别是当URI不以file:///
开头时,通常是因为Canvas API对于资源路径的处理限制。为了确保本地图片可以正确显示在Canvas上,你需要确保图片路径是正确的本地文件路径,并且可能需要通过一些额外的步骤来加载图片。
以下是一个使用uni-app中的Canvas绘制本地图片的示例代码,这里假设你已经在项目中放置了一张本地图片,并且你知道它的相对路径或绝对路径。
示例代码
-
在项目中放置图片
确保你的图片文件(例如
image.png
)放置在项目的static
目录下。 -
页面代码
<template> <view> <canvas canvas-id="myCanvas" style="width: 300px; height: 300px;"></canvas> </view> </template> <script> export default { onLoad() { this.drawImageOnCanvas(); }, methods: { drawImageOnCanvas() { const ctx = uni.createCanvasContext('myCanvas'); const imagePath = '/static/image.png'; // 相对路径,确保路径正确 uni.getImageInfo({ src: imagePath, success: (res) => { const imgPath = res.path; // 获取图片的本地路径 ctx.drawImage(imgPath, 0, 0, 300, 300); // 绘制图片 ctx.draw(); }, fail: (err) => { console.error('获取图片信息失败:', err); } }); } } } </script> <style> /* 添加必要的样式 */ </style>
解释
uni.getImageInfo
: 这个API用于获取图片信息,包括图片的本地路径。这对于Canvas绘制本地图片是必要的,因为drawImage
方法需要一个有效的本地文件路径。ctx.drawImage
: 使用获取到的本地图片路径来绘制图片。- 路径处理: 确保图片路径是正确的。在uni-app中,通常使用相对路径(如
/static/image.png
)来引用静态资源。
通过这种方式,你可以确保即使URI不以file:///
开头,也能正确地在Canvas上绘制本地图片。注意,路径问题往往是导致此类问题的主要原因,因此确保路径的正确性至关重要。