#HarmonyOS NEXT体验官#Web获取相机拍照图片 原创

早起睡不够
发布于 2024-7-26 17:36
浏览
0收藏

Web获取相机拍照图片

我们本次就来看一下,我们如何使用 Web获取相机拍照图片

介绍

本示例介绍如何在HTML页面中拉起原生相机进行拍照,并获取返回的图片。

操作说明

  1. 点击HTML页面中的选择文件按钮,拉起原生相机进行拍照。
  2. 完成拍照后,将图片在HTML的img标签中显示。

效果

#HarmonyOS NEXT体验官#Web获取相机拍照图片-鸿蒙开发者社区

#HarmonyOS NEXT体验官#Web获取相机拍照图片-鸿蒙开发者社区

接下来我们一起来看一下,具体的实现

这里面我们使用了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获取相机拍照图片并返回,这里面要感谢坚果派这个组织,是在坚果派的各位大佬的帮助下,实现了这个功能。

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
收藏
回复
举报
回复
    相关推荐