uni-app Canvas的drawImage 本地文件uri不显示file:///开头

发布于 1周前 作者 sinazl 来自 Uni-App

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


1 回复

在uni-app中,使用Canvas的drawImage方法时,如果你遇到本地文件URI不显示的问题,特别是当URI不以file:///开头时,通常是因为Canvas API对于资源路径的处理限制。为了确保本地图片可以正确显示在Canvas上,你需要确保图片路径是正确的本地文件路径,并且可能需要通过一些额外的步骤来加载图片。

以下是一个使用uni-app中的Canvas绘制本地图片的示例代码,这里假设你已经在项目中放置了一张本地图片,并且你知道它的相对路径或绝对路径。

示例代码

  1. 在项目中放置图片

    确保你的图片文件(例如image.png)放置在项目的static目录下。

  2. 页面代码

    <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上绘制本地图片。注意,路径问题往往是导致此类问题的主要原因,因此确保路径的正确性至关重要。

回到顶部