//下载依赖, 本文使用版本
"peerDependencies": {
"@capacitor/camera": "^4.1.0",
"@angular/platform-browser": "^14.2.0",
"@angular/platform-browser-dynamic": "^14.2.0"
}
//引入组件
import { Camera, CameraResultType } from '@capacitor/camera';
import { DomSanitizer } from '@angular/platform-browser';
constructor(public sanitizer: DomSanitizer){}
//异步的方法, 当触发该方法时,调用相机或相册,获取选中图片的数据 blob流 或者 base64
async selectFile() {
//调用Camera插件的 getphoto方法 实现调用手机相册和相机的功能, 电脑上会调用文件夹
// quality: 定义保存图片的质量,取值范围为[0,100],100表示质量最高
// destinationType: 选择返回数据的格式,取值为三个常量之一
// Camera.DestinationType.DATA_URL 表示返回图片作为base64编码
// Camera.DestinationType.FILE_URI 返回影像档的 URI
// Camera.DestinationType.NATIVE_URI 返回图像本机URI
// allowEdit: 取值范围为true false 设置在选择图片进行操作之前是否对其进行简单的编辑(Android系统会忽略此属性)
// encodingType: 用于设置返回文件的类型,有一下几个常量可用
// Camera.EncodingType.JPEG 表示返回JPEG编码的图片
// Camera.EncodingType.PNG 表示返回PNG编码的图片
// targetWidth: 用于定义缩放图片的宽度,以像素为单位。必须和targetHeight配合使用
// targetHeight: 用于定义缩放图片的高度,以像素为单位。必须和targetWidth 配合使用
// saveToPhotoAlbum: 取值范围为true false 用于决定是否在捕捉图片之后放入相册
//本文中用到的 resultType 等于destinationType
const image = await Camera.getPhoto({
quality: 90,
allowEditing: true,
resultType: CameraResultType.Uri
});
//获取返回的路径 eg:"blob:http://localhost:8100/8e25daf2-9a9e-43db-9331-c26e63161552" 可使用该路径在页面展示图片,要去掉blob: 的字符,不然安全策略无法通过
let selectedFileUri = image.webPath;
//调用方法,根据blob路径获取blob数据
let fileBlob = this.createBlobFromUri(image.webPath);
const imgtype = (await fileBlob).type;//获取文件类型 eg:"image/png"
const imgtypeLast = imgtype.substring(imgtype.lastIndexOf('/') + 1, imgtype.length);//过滤 eg:'png'
let fileType = imgtypeLast;
const num = 1024.00;
let imgSize = (await fileBlob).size;//获取图片大小 eg:3326616 大小单位为KB
imgSize = (imgSize / Math.pow(num, 2)).toFixed(4);//转为MB eg:"3.1725"
let fileName = 'xxxx.' + fileType;//无法获取图片本来的名字, 只能自定义名字
this.fetchBase64Data(image.webPath);//获取base64 根据blob地址
}
//异步,返回blob流
async createBlobFromUri(uri: string): Promise<Blob> {
const response = await fetch(uri);
const blob = await response.blob();
return blob;
}
//通过网络请求 获取blob流
fetchBase64Data(fileUrl: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
this.http.get(fileUrl, { responseType: 'blob' }).subscribe(
(blob: Blob) => {
this.blobToBase64(blob);
},
(error) => {
reject(error);
}
);
});
}
//根据blob流获取 base64string 注意这里用的是 Image类型,
//因为File类型在手机怎么试都不好用,所以转的Image类型 pdf之类的没试过,但估计是不能用
blobToBase64(blob: Blob): Promise<string> {
return new Promise<string>((resolve, reject) => {
const image = new Image();
image.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
const base64Data = canvas.toDataURL('image/png');
this.base64string = base64Data.split(',')[1];
resolve(base64Data);
};
image.onerror = (error) => {
reject(error);
};
const objectUrl = URL.createObjectURL(blob);
image.src = objectUrl;
});
}
//这是 File类型的版本,在浏览器好用,手机不清楚哪里写的不对,不好用
fetchBase64Data(fileUrl: string): Promise<string> {
return new Promise<string>((resolve, reject) => {
this.http.get(fileUrl, { responseType: 'blob' }).subscribe(
(blob: Blob) => {
//判断浏览器是否支持FileReader
if (typeof FileReader == 'undefined') {
console.log('您的浏览器不支持FileReader');
} else {
console.log('您的浏览器支持FileReader');
}
const reader = new FileReader();//定义FileReader类型
reader.onloadend = () => {
console.log('run onloadend');
const base64Data = reader.result as string;
// 在这里处理 Base64 数据
this.base64string =base64Data;
console.log(base64Data);
resolve(base64Data);
};//绑定onladend事件的函数
reader.readAsDataURL(blob);//执行方法
},
(error) => {
reject(error);
}
);
});
}
//前台代码 使用sanitizer.bypassSecurityTrustResourceUrl 方法可以将blob:字符过滤调
<ion-col *ngIf="selectedFileUri">
<img [src]="this.sanitizer.bypassSecurityTrustResourceUrl(selectedFileUri)" alt="Selected Image">
</ion-col>
后续补充,遇到一个问题。在安卓13系统 三星手机上, 发现 修改图片权限始终拿不到,最终将allowEdit属性设为false。不获取该权限解决。
获取blob地址,页面使用blob地址显示无问题,通过地址获取base64发现无法获取,(未知原因,)最终改为直接获取图片base64.页面显示用base64显示。
<img [src]="base64string">
async selectFile() {
let image;
try {
image = await Camera.getPhoto({
quality: 90,
resultType: CameraResultType.Base64,
allowEditing: false
});
}catch (error){
console.log('error:'+error);
//当用户取消选择, 或者传入文件损坏时,catch住报错信息,
//是否可以根据报错信息做处理,没有尝试,因为不确定是否所有机型的文言都一致。
}
//get file size
const fileSizeInBytes = image.base64String.length;
const num = 1024.00;
const imgSize = (fileSizeInBytes / Math.pow(num, 2)).toFixed(4);
//get file type
this.fileType = image.format;
//get file name
this.fileName = this.disobj.fileName1 + this.fileType;
//get file base64
this.upBase64string=image.base64String;//不带base前缀的 base64string 因为有些服务器的安全策略会拦截base64流,阻止其当作参数传输。
//如无必要,日志中不要出现流文件,很容易将服务器内存占满。
const imageStr = 'data:image/';
const baseStr = ';base64,';
this.base64string = imageStr + this.fileType + baseStr + image.base64String;
return;
}