在 HTML5+ (DCloud/HBuilder) 开发中,要实现拍照、从相册选图,并最终读取图片文件,核心是结合使用 plus.camera(摄像头)、plus.gallery(相册)和 plus.io(文件系统)。
这里最大的痛点通常是路径转换:拍照返回的通常是相对路径(如 _doc/xxx.jpg),直接放入 <img> 标签可能无法显示,必须通过 plus.io 转换为本地绝对路径 (file:///...)。
以下是完整的实现方案和代码示例。
核心逻辑流程
- 拍照 (
plus.camera): 调用摄像头 -> 获取图片路径。 - 相册 (
plus.gallery): 打开相册 -> 选择图片 -> 获取图片路径。 - 路径处理 (
plus.io): 将上述两种方式获取的路径,通过resolveLocalFileSystemURL转换为可用的entry对象,再通过.toLocalURL()获取<img src>可识别的地址。
完整代码示例
你可以直接将此代码片段放入你的 js 文件或 <script> 标签中。
JavaScript
// 定义全局变量方便调试
var cmr = null;
// 监听 plusready 事件,确保 HTML5+ 环境准备就绪
document.addEventListener("plusready", function() {
// 获取摄像头管理对象
cmr = plus.camera.getCamera();
}, false);
/**
* 1. 拍照函数
*/
function captureImage() {
if (!cmr) {
alert("摄像头未就绪");
return;
}
var res = cmr.supportedImageResolutions[0]; // 获取支持的分辨率
var fmt = cmr.supportedImageFormats[0]; // 获取支持的格式
console.log("开始拍照...");
cmr.captureImage(function(path) {
// 成功回调:path 是拍照后的文件路径(通常是相对路径,如 "_doc/camera/123.jpg")
console.log("拍照成功,路径:" + path);
// 【关键步骤】将路径转换为本地预览地址
resolveFile(path);
}, function(error) {
// 失败回调
console.log("拍照失败: " + error.message);
if(error.code !== 11) { // 11 是用户取消操作,不需要弹窗
alert("拍照失败: " + error.message);
}
}, {
resolution: res,
format: fmt
});
}
/**
* 2. 从相册选择函数
*/
function pickImageFromGallery() {
console.log("打开相册...");
plus.gallery.pick(function(path) {
// 成功回调:path 是选择图片的路径
console.log("选择成功,路径:" + path);
// 相册返回的路径通常已经是绝对路径,但为了统一处理,
// 依然建议走一遍 resolveFile,或者直接显示
showImage(path);
}, function(error) {
// 失败回调
console.log("选择失败: " + error.message);
}, {
filter: "image", // 只选择图片
multiple: false, // 单选
system: false // 尽量使用这种方式避免部分安卓机型兼容问题
});
}
/**
* 3. 【核心】利用 plus.io 将路径转换为可显示的 URL
* @param {String} path - 原始路径 (如 _doc/...)
*/
function resolveFile(path) {
// 通过URL参数获取目录对象或文件对象
plus.io.resolveLocalFileSystemURL(path, function(entry) {
// entry 是一个文件实体对象
// entry.toLocalURL() 获取本地绝对路径 (file:///storage/...)
// 这种路径可以直接赋值给 img src
var localUrl = entry.toLocalURL();
console.log("本地绝对路径:" + localUrl);
// 显示图片
showImage(localUrl);
// 如果你需要读取文件内容上传(例如转 Base64 或读取 File 对象)
// readFileEntry(entry);
}, function(e) {
console.log("读取文件错误:" + e.message);
});
}
/**
* 辅助:在页面显示图片
*/
function showImage(url) {
// 假设页面上有一个 img 标签 id="myImage"
var img = document.getElementById("myImage");
if (img) {
img.src = url;
} else {
console.log("未找到图片元素,图片地址为:" + url);
}
}
/**
* 进阶:如果需要读取文件数据用于上传 (读取为 File 对象)
*/
function readFileEntry(fileEntry) {
fileEntry.file(function(file) {
// file 对象类似于 Web API 的 File,包含 name, size, type 等
console.log("文件名:" + file.name);
console.log("文件大小:" + file.size);
// 配合 FileReader 读取内容
var fileReader = new plus.io.FileReader();
fileReader.readAsDataURL(file); // 比如转 base64
fileReader.onloadend = function(evt) {
console.log("Base64数据前缀:" + evt.target.result.substring(0, 50));
// 这里可以将 evt.target.result 发送给服务器
}
});
}
代码关键点解析
1. plus.io.resolveLocalFileSystemURL(path, successCB, errorCB)
这是最重要的 API。
- 为什么需要它? 拍照返回的路径通常是
_doc/开头的相对路径。原生层能识别,但 Webview 中的 HTML<img>标签有时无法直接识别这种虚拟路径。 - 它的作用: 它将路径解析为
FileEntry对象。
2. entry.toLocalURL()
- 获得
FileEntry后,调用此方法会返回一个以file://开头的本地绝对路径。这是最安全、兼容性最好的路径格式,可以直接赋值给<img src="...">。
3. 权限配置 (manifest.json)
在打包 App 时,请确保在 manifest.json 中勾选了相应的模块权限,否则代码会报错:
- Camera: 摄像头
- Gallery: 相册
- File (IO): 文件系统 (用于
plus.io)
常见坑与解决方案
- 图片旋转问题:部分 Android 手机拍照后,图片虽然显示正常,但上传或某些特定场景下会旋转 90 度。如果遇到此问题,需要在显示前利用 Canvas 或后端进行修正。
- 路径中的
file://:在某些较新的 Android 版本(Android 10+)或 iOS Webview 中,直接使用file://协议加载图片可能会受到安全策略限制(Webview 无法加载本地文件)。如果遇到图片加载不出来:- 可以使用
entry.toRemoteURL()试试(虽然名字叫 Remote,但在某些环境用于本地映射)。 - 或者在
manifest.json中配置plus->distribute->plugins相关的 Webview 设置。 - 最通用的现代做法是使用
plus.io.convertLocalFileSystemURL(path)转换路径。
- 可以使用
下一步建议:
如果你需要实现图片上传(将获取到的图片发给后端),你需要用到 plus.uploader 模块或者将图片转为 Base64。是否需要我提供“图片上传到服务器”的相关代码?
发表回复