HarmonyOS ArkWeb 系列之网页图片扫码识别:长按图片用 ScanKit 解码二维码
文章目录思路说明流程图完整代码实现ScanKit 支持的码类型配合 enableMultiMode识别一张图里的多个码Promise 风格的调用方式注意临时文件的清理写在最后你有没有遇到这种需求网页里有张图片是二维码用户长按想扫描它——但系统相机无法识别网页截图只能扫真实摄像头。ArkWeb ScanKit 的组合可以优雅解决这个问题长按图片把图片下载到本地然后调用detectBarcode.decode直接识别图片里的二维码不需要打开摄像头。思路说明用户长按网页中的图片onContextMenuShow触发通过getLastHitTest()拿到图片 URL图片如果是 rawfile 本地资源直接复制到filesDir图片如果是网络资源用 HTTP 下载到filesDir调用detectBarcode.decode传入本地文件路径识别二维码把识别结果显示给用户流程图完整代码实现import{webview}fromkit.ArkWeb;import{common}fromkit.AbilityKit;import{fileIoasfs}fromkit.CoreFileKit;import{systemDateTime}fromkit.BasicServicesKit;import{http}fromkit.NetworkKit;import{scanCore,scanBarcode,detectBarcode}fromkit.ScanKit;import{BusinessError}fromkit.BasicServicesKit;EntryComponentstruct WebScanQRCodeDemo{// SaveButton 配置用于其他功能这里留一个标准配置saveButtonOptions:SaveButtonOptions{icon:SaveIconStyle.FULL_FILLED,text:SaveDescription.SAVE_IMAGE,buttonType:ButtonType.Capsule};controller:webview.WebviewControllernewwebview.WebviewController();StateshowMenu:booleanfalse;StateimgUrl:string;// 当前长按图片的 URLStatedecodeResult:string;// 扫码结果contextthis.getUIContext().getHostContext()ascommon.UIAbilityContext;// 复制 rawfile 图片到 filesDir copyLocalPicToDir(rawfilePath:string,newFileName:string):string{constsrcFileDesthis.context.resourceManager.getRawFdSync(rawfilePath);constdstPaththis.context.filesDir/newFileName;constdest:fs.Filefs.openSync(dstPath,fs.OpenMode.CREATE|fs.OpenMode.READ_WRITE);letbufSize4096;constbufnewArrayBuffer(bufSize);letoffset0;letreadLen0;letlen0;while((lenfs.readSync(srcFileDes.fd,buf,{offset:srcFileDes.offsetoffset,length:bufSize}))!0){readLenlen;fs.writeSync(dest.fd,buf,{offset:offset,length:len});offsetlen;if((srcFileDes.length-readLen)bufSize){bufSizesrcFileDes.length-readLen;}}fs.close(dest.fd);returndest.path;}// 下载网络图片到 filesDir asynccopyUrlPicToDir(picUrl:string,newFileName:string):Promisestring{leturi;consthttpRequesthttp.createHttp();try{constdata:http.HttpResponseawait(httpRequest.request(picUrl)asPromisehttp.HttpResponse);if(data?.responseCodehttp.ResponseCode.OK){constdstPaththis.context.filesDir/newFileName;constdest:fs.Filefs.openSync(dstPath,fs.OpenMode.CREATE|fs.OpenMode.READ_WRITE);fs.writeSync(dest.fd,data.resultasArrayBuffer);fs.close(dest.fd);uridstPath;}}finally{httpRequest.destroy();}returnuri;}// 长按菜单 BuilderMenuBuilder(){Menu(){MenuItem({content:扫描二维码}).width(200).height(50).onClick(async(){try{letlocalFilePath;// 处理图片来源if(this.imgUrl.includes(rawfile)){// 本地 rawfile 图片constrawFileNamethis.imgUrl.substring(this.imgUrl.lastIndexOf(/)1);localFilePaththis.copyLocalPicToDir(rawFileName,qrcode_temp.png);}elseif(this.imgUrl.includes(http)||this.imgUrl.includes(https)){// 网络图片先下载consttimestampsystemDateTime.getTime();localFilePathawaitthis.copyUrlPicToDir(this.imgUrl,qrcode_${timestamp}.png);}if(!localFilePath){this.decodeResult无法获取图片文件;return;}// 配置扫码选项constscanOptions:scanBarcode.ScanOptions{scanTypes:[scanCore.ScanType.ALL],// 识别所有码类型enableMultiMode:true,// 支持多码识别enableAlbum:true};// 构造输入图片constinputImage:detectBarcode.InputImage{uri:localFilePath// 本地文件路径};// 调用识别接口异步回调方式detectBarcode.decode(inputImage,scanOptions,(error:BusinessError,results:ArrayscanBarcode.ScanResult){if(errorerror.code){console.error(识别失败${error.code},${error.message});this.decodeResult识别失败错误码${error.code};return;}if(resultsresults.length0){// 把所有识别结果拼接显示this.decodeResultresults.map((r,i)[${i1}]${r.originalValue}).join(\n);console.info(扫码结果,JSON.stringify(results));}else{this.decodeResult未识别到二维码;}});}catch(err){console.error(扫码出错${err.code},${err.message});this.decodeResult出错${err.message};}})}}build(){Column(){Web({src:$rawfile(index.html),controller:this.controller}).onContextMenuShow((event){if(event){// 获取长按位置的图片信息consthitValuethis.controller.getLastHitTest();this.imgUrlhitValue.extra;}this.showMenutrue;returntrue;}).bindContextMenu(this.MenuBuilder,ResponseType.LongPress).fileAccess(true).javaScriptAccess(true).domStorageAccess(true).height(70%)// 显示扫码结果if(this.decodeResult){Text(识别结果).fontSize(14).fontWeight(FontWeight.Bold).margin({top:12,left:16})Text(this.decodeResult).fontSize(14).margin({top:4,left:16,right:16}).fontColor(#333).wordBreak(WordBreak.BREAK_ALL)}}.width(100%).height(100%)}}ScanKit 支持的码类型scanCore.ScanType枚举包含类型说明ScanType.QR_CODE二维码QR CodeScanType.DATA_MATRIXData Matrix 码ScanType.PDF417PDF417 条形码ScanType.AZTECAztec 码ScanType.EAN_8EAN-8 条形码ScanType.EAN_13EAN-13 条形码ScanType.CODE_128Code 128 条形码ScanType.ALL所有类型配合 enableMultiMode识别一张图里的多个码constscanOptions:scanBarcode.ScanOptions{scanTypes:[scanCore.ScanType.QR_CODE],enableMultiMode:true,// 允许识别图片里的多个二维码enableAlbum:true};enableMultiMode开启后一张图片里有多个二维码的话results数组会包含所有识别出来的码。Promise 风格的调用方式上面用了回调方式也可以用 Promisetry{constresultsawaitdetectBarcode.decode(inputImage,scanOptions);if(results.length0){this.decodeResultresults[0].originalValue??空结果;}}catch(err){this.decodeResult识别失败${err.message};}注意临时文件的清理每次扫码都会在filesDir里创建临时文件用完最好删掉// 识别完成后清理临时文件try{fs.unlinkSync(localFilePath);}catch{// 删除失败不影响主流程}写在最后网页扫码这个功能在电商、票务类 App 里很实用——商品页里有二维码用户不需要截图再打开相机扫直接长按就能识别。核心是把网页图片拿到本地然后交给 ScanKit 处理整个流程清晰不绕弯。参考文章《HarmonyOS ScanKit 扫码识别使用指南》《长按图片保存到相册SaveButton photoAccessHelper 实战》《detectBarcode.decode 图片识码 API 详解》

相关新闻

最新新闻

日新闻

周新闻

月新闻