#HarmonyOS NEXT体验官#Web获取相机拍照图片 原创
Web获取相机拍照图片
我们本次就来看一下,我们如何使用 Web获取相机拍照图片
介绍
本示例介绍如何在HTML页面中拉起原生相机进行拍照,并获取返回的图片。
操作说明
- 点击HTML页面中的选择文件按钮,拉起原生相机进行拍照。
- 完成拍照后,将图片在HTML的img标签中显示。
效果
接下来我们一起来看一下,具体的实现
这里面我们使用了web组件的onShowFileSelector函数
onShowFileSelector
调用onShowFileSelector函数处理具有“文件”输入类型的HTML表单,以响应用户按下的“选择文件”按钮。返回值为true时用户可以通过系统弹窗能力选择图库并上传选中的图片。
需要注意的是:如果用户拉起图库后不选择图片,然后将应用切换到前台,会出现再次选择上传图片无法拉起图库现象。
原因是在第一次拉起图库时启动一个线程,线程走到选择图片时不选择图片,将图库切到后台该线程则会阻塞到选择图片的步骤,导致再次点击上传图片拉起图库失败。
建议在开发时添加如下逻辑:如果不选择图片就返回一个空值,该线程可以走完它的生命周期,当把图库切换到后台,再次上传图片时就会启动一个新的线程,成功拉起图库。
// xxx.ets
import { webview } from '@kit.ArkWeb';
import { picker } from '@kit.CoreFileKit';
import { BusinessError } from '@kit.BasicServicesKit';
@Entry
@Component
struct WebComponent {
controller: webview.WebviewController = new webview.WebviewController();
build() {
Column() {
Web({ src: $rawfile('index.html'), controller: this.controller })
.onShowFileSelector((event) => {
console.log('MyFileUploader onShowFileSelector invoked');
const documentSelectOptions = new picker.PhotoSelectOptions();
let uri: string | null = null;
const documentViewPicker = new picker.PhotoViewPicker();
documentViewPicker.select(documentSelectOptions).then((documentSelectResult) => {
uri = documentSelectResult[0];
console.info('documentViewPicker.select to file succeed and uri is:' + uri);
if (event) {
event.result.handleFileList([uri]);
}
}).catch((err: BusinessError) => {
console.error(`Invoke documentViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
})
return true;
})
}
}
}
html代码
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8">
</head>
<body>
<form id="upload-form" enctype="multipart/form-data">
<input type="file" id="upload" name="upload"/>
</form>
</body>
</html>
startAbilityForResult
UIAbilityContext.startAbilityForResult
startAbilityForResult(want: Want, callback: AsyncCallback<AbilityResult>): void
启动一个Ability。使用callback异步回调。仅支持在主线程调用。
Ability被启动后,有如下情况:
- 正常情况下可通过调用terminateSelfWithResult接口使之终止并且返回结果给调用方。
- 异常情况下比如杀死Ability会返回异常信息给调用方, 异常信息中resultCode为-1。
- 如果被启动的Ability模式是单实例模式, 不同应用多次调用该接口启动这个Ability,当这个Ability调用terminateSelfWithResult接口使之终止时,只将正常结果返回给最后一个调用方, 其它调用方返回异常信息, 异常信息中resultCode为-1。
最关键的其实,就是上面的这部分,接下来就是具体实现。
ArkTS代码
import web_webview from '@ohos.web.webview';
import { common, Want } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
class FileResult {
result: FileSelectorResult;
fileSelector: FileSelectorParam;
constructor(result: FileSelectorResult, fileSelector: FileSelectorParam) {
this.result = result;
this.fileSelector = fileSelector;
}
}
@Entry
@Component
struct WebCameraPage {
controller: web_webview.WebviewController = new web_webview.WebviewController();
build() {
Column() {
Web({ src: $rawfile("camera.html"), controller: this.controller })
.onShowFileSelector((event: FileResult) => {
this.invokeCamera(((uri: string) => {
event?.result.handleFileList([uri]);
}))
return true;
})
}
}
invokeCamera(callback: (uri: string) => void) {
const context = getContext(this) as common.UIAbilityContext;
const want: Want = {
action: "ohos.want.action.imageCapture",
parameters: {
"callBundleName": context.abilityInfo.bundleName,
}
};
const result: (error: BusinessError, data: common.AbilityResult) => void = (error: BusinessError,
data: common.AbilityResult) => {
const resultUri: string = data.want?.parameters?.resourceUri as string;
if (callback && resultUri) {
callback(resultUri);
}
}
context.startAbilityForResult(want, result);
}
}
html代码
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8">
<style>
body {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
background-color: #FFA500;
margin: 0;
padding: 20px;
}
#image {
display: none;
width: 80%;
max-width: 600px;
height: auto;
border: 2px solid #333;
border-radius: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
margin:0 auto;
}
#image_preview {
display: none;
margin-top: 15px;
font-size: 18px;
color: #333;
}
.a-upload {
text-decoration: none;
padding: 15px 30px;
height: 40px;
line-height: 40px;
position: relative;
cursor: pointer;
color: #ffffff;
background-color: #FF0000;
border-radius: 25px;
overflow: hidden;
display: inline-block;
font-size: 16px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
}
.a-upload input {
position: absolute;
font-size: 100px;
right: 0;
top: 0;
opacity: 0;
filter: alpha(opacity=0);
cursor: pointer;
border-radius: 25px;
background: #FF0000;
}
</style>
</head>
<body>
<h1>Web获取相机拍照图片</h1>
<a href="javascript:;" class="a-upload" id="a_upload">
<label class="input-file-button" for="upload">选择图片</label>
<input type="file" id="upload" name="upload" accept="image/*" capture="upload" onchange="showPic()"/>
</a>
<p id="image_preview"></p>
<img id="image">
<script>
function showPic() {
let event = this.event;
let tFile = event? event.target.files : [];
if (tFile === 0) {
document.getElementById('image_preview').style.display = 'block';
document.getElementById('image_preview').innerHTML = "未选择图片";
return;
}
document.getElementById('image').setAttribute('src', URL.createObjectURL(tFile[0]));
document.getElementById('image_preview').style.display = 'block';
document.getElementById('image').style.display = 'block';
}
</script>
</body>
</html>
代码解释
• <!DOCTYPE html>:这是 HTML5 的文档类型声明,用于告知浏览器以标准模式渲染页面。
• <html>:标记整个 HTML 文档的开始。
• <head>:包含了文档的元数据,如视口设置、字符编码等,以及样式表和脚本的引用。
• <meta name=“viewport” content=“width=device-width, initial-scale=1.0” charset=“utf-8”>:设置视口以适应不同设备,并指定字符编码为 UTF-8。
• <style> 标签内定义了一些 CSS 样式:
• body 选择器设置了页面的整体字体、文本对齐方式、背景颜色和外边距。
• #image 选择器设置了一个图片元素初始为隐藏,并设置了内边距。
• #image_preview 选择器设置了一个用于图片预览的元素初始为隐藏。
• .a-upload 选择器定义了上传按钮的样式,包括文本装饰、内边距、高度、行高、位置、鼠标指针样式、颜色、背景颜色、边框半径等。
• .a-upload input 选择器设置了上传文件输入框的样式,如位置、不透明度等。
• .upload-button 选择器定义了另一个上传按钮的样式,包括内边距、背景、边框半径、颜色和鼠标指针样式。
• <body>:包含页面的实际内容。
• <script> 标签内定义了一个 JavaScript 函数 showPic():
• 它获取触发事件的对象,并获取选择的文件。
• 如果没有选择文件,则在 image_preview 元素中显示“未选择图片”并返回。
• 如果选择了文件,通过 URL.createObjectURL() 创建一个临时的 URL 并设置为 image 元素的 src 属性,同时显示 image_preview 和 image 元素。
• 接下来是一个带有上传功能的链接和相关的输入框:
• <a> 标签作为上传的链接,具有特定的类 a-upload 和 id a_upload。
• 内部的 <label> 标签用于显示文本“相机”。
• <input> 标签是文件上传输入框,具有各种属性,如类型、名称、接受的文件类型、捕获方式等,并在文件选择发生变化时调用 showPic() 函数。
• <p id=“image_preview”></p>:用于显示图片预览的相关信息。
• <img id=“image”>:用于显示选择的图片。
总体来说,这段代码创建了一个具有图片上传功能的页面,包括上传按钮、文件选择处理和图片显示区域。
总结
本文我们实现的是 Web获取相机拍照图片并返回,这里面要感谢坚果派这个组织,是在坚果派的各位大佬的帮助下,实现了这个功能。