Flutter调用HarmonyOS NEXT原生相机拍摄相册选择照片视频
目录
1.项目背景
2.遇到的问题
3.开发准备
4.开发过程
首先创建注册调用鸿蒙原生的渠道
创建并初始化插件
绑定通道完成插件中的功能
5.具体步骤
根据传值判断是相册选取还是打开相机
相册选取照片或视频
相机拍摄照片或视频
调用picker拍摄接口获取拍摄的结果
视频封面缩略图处理
打包缩略图
路径处理
数据返回
6.Flutter调用HarmonyOS原生通过路径上传到服务器
完整代码:
1.项目背景
我们的移动端项目是使用Flutter开发,考虑到开发周期和成本,使用了HarmonyOSNEXT(后续简称:鸿蒙)的Flutter兼容库,再将部分三方库更新为鸿蒙的Flutter兼容库,本项目选择相册的图片视频,使用相机拍照拍视频我们使用的是调用Android和iOS的原生方法使用
2.遇到的问题
因为我们使用的是原生方法,所以鸿蒙也得开发一套原生的配合使用,虽然我们也发现鸿蒙的Flutter兼容库中有image_picker这个库,但是在实际线上运行中,部分机型是无法正常工作的,主要是国内厂商深度定制引起的,那根据设备类型判断在纯血鸿蒙手机上用image_picker也是可行的方案,考虑到这样不方便后期维护,所以还是打算使用Flutter通过通道的形式去调用鸿蒙原生方式来实现
3.开发准备
首先得将鸿蒙适配Flutter的SDK下载,具体步骤可以参考:Flutter SDK 仓库,也可以参考我的上一篇文章:Flutter适配HarmonyOS实践_flutter支持鸿蒙系统
4.开发过程
- 首先创建注册调用鸿蒙原生的渠道
- 创建并初始化插件
- 绑定通道完成插件中的功能
首先创建注册调用鸿蒙原生的渠道
使用了兼容库后,ohos项目中在entry/src/main/ets/plugins目录下会自动生成一个GeneratedPluginRegistrant.ets文件,里面会注册所有你使用的兼容鸿蒙的插件,但是我们不能在这里注册,因为每次build,他会根据Flutter项目中的pubspec.yaml文件中最新的插件引用去重新注册。
我们找到GeneratedPluginRegistrant的注册地:EntryAbility.ets,我们在plugins中创建一个FlutterCallNativeRegistrant.ets,将他也注册一下:
import { FlutterAbility, FlutterEngine } from '@ohos/flutter_ohos';
import FlutterCallNativeRegistrant from '../plugins/FlutterCallNativeRegistrant';
import { GeneratedPluginRegistrant } from '../plugins/GeneratedPluginRegistrant';export default class EntryAbility extends FlutterAbility {configureFlutterEngine(flutterEngine: FlutterEngine) {super.configureFlutterEngine(flutterEngine)GeneratedPluginRegistrant.registerWith(flutterEngine)///GeneratedPluginRegistrant是自动根据引入的插件库生成的,所以调用原生的插件必须新起文件进行单独注册FlutterCallNativeRegistrant.registerWith(flutterEngine,this)}
}
创建并初始化插件
创建FlutterCallNativePlugin插件在FlutterCallNativeRegistrant中初始化
export default class FlutterCallNativeRegistrant {private channel: MethodChannel | null = null;private photoPlugin?:PhotoPlugin;static registerWith(flutterEngine: FlutterEngine) {try {flutterEngine.getPlugins()?.add(new FlutterCallNativePlugin());} catch (e) {}}}
绑定通道完成插件中的功能
绑定MethodChannel定义2个执行方法来调用原生的相册选取照片视频,相机拍摄照片视频:selectPhoto和selectVideo
import { FlutterPlugin, FlutterPluginBinding, MethodCall,MethodCallHandler,MethodChannel, MethodResult } from "@ohos/flutter_ohos";
import router from '@ohos.router';
import PhotoPlugin from "./PhotoPlugin";
import { UIAbility } from "@kit.AbilityKit";export default class FlutterCallNativePlugin implements FlutterPlugin,MethodCallHandler{private channel: MethodChannel | null = null;private photoPlugin?:PhotoPlugin;getUniqueClassName(): string {return "FlutterCallNativePlugin"}onMethodCall(call: MethodCall, result: MethodResult): void {switch (call.method) {case "selectPhoto":this.photoPlugin = PhotoPlugin.getInstance();this.photoPlugin.setDataInfo(call, result ,1)this.photoPlugin.openImagePicker();break;case "selectVideo":this.photoPlugin = PhotoPlugin.getInstance();this.photoPlugin.setDataInfo(call, result ,2)this.photoPlugin.openImagePicker();break;default:result.notImplemented();break;}}onAttachedToEngine(binding: FlutterPluginBinding): void {this.channel = new MethodChannel(binding.getBinaryMessenger(), "flutter_callNative");this.channel.setMethodCallHandler(this)}onDetachedFromEngine(binding: FlutterPluginBinding): void {if (this.channel != null) {this.channel.setMethodCallHandler(null)}}}
5.具体步骤
- 根据传值判断是相册选取还是打开相机
- 相册选取照片或视频
- 相机拍摄照片或视频
- 视频封面处理
- 路径处理
- 数据返回
根据传值判断是相册选取还是打开相机
openImagePicker() {if (this.type === 1) {this.openCameraTakePhoto()} else if (this.type === 2) {this.selectMedia()} else {this.selectMedia()}}
相册选取照片或视频
用户有时需要分享图片、视频等用户文件,开发者可以通过特定接口拉起系统图库,用户自行选择待分享的资源,然后最终完成分享。此接口本身无需申请权限,目前适用于界面UIAbility,使用窗口组件触发。
这个方式的好处显而易见,不像Android或者iOS还需要向用户申请隐私权限,在鸿蒙中,以下操作完全是系统级的,不需要额外申请权限
1.创建图片媒体文件类型文件选择选项实例
const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();
2.根据类型配置可选的媒体文件类型和媒体文件的最大数目等参数
if (this.mediaType === 1) {photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE // 过滤选择媒体文件类型为IMAGE} else if (this.mediaType === 2) {photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE // 过滤选择媒体文件类型为VIDEO}photoSelectOptions.maxSelectNumber = this.mediaType === 2?1:this.maxCount; // 选择媒体文件的最大数目photoSelectOptions.isPhotoTakingSupported=false;//是否支持拍照photoSelectOptions.isSearchSupported=false;//是否支持搜索
还有其他可配置项请参考API文档
3创建图库选择器实例,调用PhotoViewPicker.select接口拉起图库界面进行文件选择。文件选择成功后,返回PhotoSelectResult结果集。
let uris: Array<string> = [];
const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
photoViewPicker.select(photoSelectOptions).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {uris = photoSelectResult.photoUris;console.info('photoViewPicker.select to file succeed and uris are:' + uris);
}).catch((err: BusinessError) => {console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);
})
打印相册选择图片和视频的结果:
photoViewPicker.select to file succeed and uris
are:file://media/Photo/172/IMG_1736574824_157/IMG_20250111_135204.jpg,file://media/Photo/164/IMG_1736514105_152/image_1736514005016.jpg
photoViewPicker.select to file succeed and uris
are:file://media/Photo/136/VID_1735732161_009/VID_20250101_194749.mp4
相机拍摄照片或视频
1.配置PickerProfile
说明
PickerProfile的saveUri为可选参数,如果未配置该项,拍摄的照片和视频默认存入媒体库中。
如果不想将照片和视频存入媒体库,请自行配置应用沙箱内的文件路径。
应用沙箱内的这个文件必须是一个存在的、可写的文件。这个文件的uri传入picker接口之后,相当于应用给系统相机授权该文件的读写权限。系统相机在拍摄结束之后,会对此文件进行覆盖写入
let pathDir = getContext().filesDir;let fileName = `${new Date().getTime()}`let filePath = pathDir + `/${fileName}.tmp`let result: picker.PickerResultfileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE);let uri = fileUri.getUriFromPath(filePath);let pickerProfile: picker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,saveUri: uri};
调用picker拍摄接口获取拍摄的结果
if (this.mediaType === 1) {result =await picker.pick(getContext(), [picker.PickerMediaType.PHOTO],pickerProfile);} else if (this.mediaType === 2) {result =await picker.pick(getContext(), [picker.PickerMediaType.VIDEO],pickerProfile);}console.info(`picker resultCode: ${result.resultCode},resultUri: ${result.resultUri},mediaType: ${result.mediaType}`);
打印结果:
picker resultCode: 0,resultUri:
file://com.example.demo/data/storage/el2/base/haps/entry/files/1737443816605.tmp,mediaType: photo
picker resultCode: 0,resultUri:
file://com.example.demo/data/storage/el2/base/haps/entry/files/1737443929031.tmp,mediaType: video
因为我们配置了saveUri,所以拍摄的图片视频是存在我们应用沙盒中。
视频封面缩略图处理
视频拿到一般都是直接上传,但是有的场景需要将适配封面也拿到,那么路径在沙盒中,就直接一次性处理好
1.创建AVImageGenerator对象
// 创建AVImageGenerator对象let avImageGenerator: media.AVImageGenerator = await media.createAVImageGenerator()
2.根据传入的视频uri打开视频文件
let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
3.将打开后的文件配置给avImageGenerator
let avFileDescriptor: media.AVFileDescriptor = { fd: file.fd };avImageGenerator.fdSrc = avFileDescriptor;
4.初始化参数
let timeUs = 0let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNClet param: media.PixelMapParams = {width : 300,height : 400,}
5.异步获取缩略图
// 获取缩略图(promise模式)let pixelMap = await avImageGenerator.fetchFrameByTime(timeUs, queryOption, param)
6.缩放资源,并返回缩略图
avImageGenerator.release()console.info(`release success.`)fs.closeSync(file)return pixelMap
打包缩略图
1.创建imagePicker实例,该类是图片打包器类,用于图片压缩和打包
const imagePackerApi: image.ImagePacker = image.createImagePacker();
2.创建配置image.PackingOption
let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 }
3.将缩略图打包保存并返回文件路径
imagePackerApi.packing(pixelMap, packOpts).then(async (buffer: ArrayBuffer) => {let fileName = `${new Date().getTime()}.tmp`// //文件操作let filePath = getContext().cacheDir + fileNamelet file = fileIo.openSync(filePath,fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)fileIo.writeSync(file.fd,buffer)//获取urilet urlStr = fileUri.getUriFromPath(filePath)resolve(urlStr)})
路径处理
因为以上所有的路径都是在鸿蒙设备上的路径,Flutter的MultipartFile.fromFile(ipath)是无法读取纯血鸿蒙设备的路径
01-16 16:23:46.805 17556-17654 A00000/com.gqs...erOHOS_Native
flutter settings log message: 错误信息:PathNotFoundException: Cannot retrieve length of file, path = 'file://com.example.demo/data/storage/el2/base/haps/entry/files/1737015822716.tmp' (OS Error: No such file or directory, errno = 2)
所以我们需要把路径转换一下:
/** Copyright (c) 2023 Hunan OpenValley Digital Industry Development Co., Ltd.* Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/
import common from '@ohos.app.ability.common';
import fs from '@ohos.file.fs';
import util from '@ohos.util';
import Log from '@ohos/flutter_ohos/src/main/ets/util/Log';const TAG = "FileUtils";export default class FileUtils {static getPathFromUri(context: common.Context | null, uri: string, defExtension?: string) {Log.i(TAG, "getPathFromUri : " + uri);let inputFile: fs.File;try {inputFile = fs.openSync(uri);} catch (err) {Log.e(TAG, "open uri file failed err:" + err)return null;}if (inputFile == null) {return null;}const uuid = util.generateRandomUUID();if (!context) {return}{const targetDirectoryPath = context.cacheDir + "/" + uuid;try {fs.mkdirSync(targetDirectoryPath);let targetDir = fs.openSync(targetDirectoryPath);Log.i(TAG, "mkdirSync success targetDirectoryPath:" + targetDirectoryPath + " fd: " + targetDir.fd);fs.closeSync(targetDir);} catch (err) {Log.e(TAG, "mkdirSync failed err:" + err);return null;}const inputFilePath = uri.substring(uri.lastIndexOf("/") + 1);const inputFilePathSplits = inputFilePath.split(".");Log.i(TAG, "getPathFromUri inputFilePath: " + inputFilePath);const outputFileName = inputFilePathSplits[0];let extension: string;if (inputFilePathSplits.length == 2) {extension = "." + inputFilePathSplits[1];} else {if (defExtension) {extension = defExtension;} else {extension = ".jpg";}}const outputFilePath = targetDirectoryPath + "/" + outputFileName + extension;const outputFile = fs.openSync(outputFilePath, fs.OpenMode.CREATE);try {Log.i(TAG, "copyFileSync inputFile fd:" + inputFile.fd + " outputFile fd:" + outputFile.fd);fs.copyFileSync(inputFile.fd, outputFilePath);} catch (err) {Log.e(TAG, "copyFileSync failed err:" + err);return null;} finally {fs.closeSync(inputFile);fs.closeSync(outputFile);}return outputFilePath;}}}
通过调用FileUtils的静态方法getPathFromUri,传入上下文和路径,就能获取到真正的SD卡的文件地址:
/data/storage/el2/base/haps/entry/cache/53ee7666-7ba4-4f72-9d37-3c09111a2293/1737446424534.tmp
数据返回
let videoUrl = this.retrieveCurrentDirectoryUri(uris[0])let coverImageUrl = this.retrieveCurrentDirectoryUri(videoThumb)map.set("videoUrl", this.retrieveCurrentDirectoryUri(uris[0]));map.set("coverImageUrl", this.retrieveCurrentDirectoryUri(videoThumb));this.result?.success(map);
6.Flutter调用HarmonyOS原生通过路径上传到服务器
上文中我们提到建立通道Channel
MethodChannel communicateChannel = MethodChannel("flutter_callNative");
final result = await communicateChannel.invokeMethod("selectVideo", vars);
if (result["videoUrl"] != null && result["coverImageUrl"] != null) {String? video = await FileUploader.uploadFile(result["videoUrl"].toString());String? coverImageUrl =await FileUploader.uploadFile(result["coverImageUrl"].toString());
}
完整代码:
import { camera, cameraPicker as picker } from '@kit.CameraKit'
import { fileIo, fileUri } from '@kit.CoreFileKit'
import { MethodCall, MethodResult } from '@ohos/flutter_ohos';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';
import json from '@ohos.util.json';
import FileUtils from '../utils/FileUtils';
import HashMap from '@ohos.util.HashMap';
import media from '@ohos.multimedia.media';
import { image } from '@kit.ImageKit';
import { fileIo as fs } from '@kit.CoreFileKit';/*** @FileName : PhotoPlugin* @Author : kirk.wang* @Time : 2025/1/16 11:30* @Description : flutter调用鸿蒙原生组件的选择相片、选择视频、拍照、录制视频*/
export default class PhotoPlugin {private imgSrcList: Array<string> = [];private call?: MethodCall;private result?: MethodResult;///打开方式:1-拍摄,2-相册private type: number=0;///最大数量private maxCount: number=0;///资源类型:1-图片,2-视频,else 所有文件类型private mediaType: number=0;// 静态属性存储单例实例private static instance: PhotoPlugin;// 静态方法获取单例实例public static getInstance(): PhotoPlugin {if (!PhotoPlugin.instance) {PhotoPlugin.instance = new PhotoPlugin();}return PhotoPlugin.instance;}// 提供设置和获取数据的方法public setDataInfo(call: MethodCall, result: MethodResult, mediaType: number) {this.call = call;this.result = result;this.mediaType = mediaType;this.type = this.call.argument("type") as number;this.maxCount = call.argument("maxCount") as number;}openImagePicker() {if (this.type === 1) {this.openCameraTakePhoto()} else if (this.type === 2) {this.selectMedia()} else {this.selectMedia()}}selectMedia() {const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions();if (this.mediaType === 1) {photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE // 过滤选择媒体文件类型为IMAGE} else if (this.mediaType === 2) {photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE // 过滤选择媒体文件类型为VIDEO}photoSelectOptions.maxSelectNumber = this.mediaType === 2?1:this.maxCount; // 选择媒体文件的最大数目photoSelectOptions.isPhotoTakingSupported=false;//是否支持拍照photoSelectOptions.isSearchSupported=false;//是否支持搜索let uris: Array<string> = [];const photoViewPicker = new photoAccessHelper.PhotoViewPicker();photoViewPicker.select(photoSelectOptions).then(async (photoSelectResult: photoAccessHelper.PhotoSelectResult) => {uris = photoSelectResult.photoUris;console.info('photoViewPicker.select to file succeed and uris are:' + uris);let jsonResult = "";if (this.mediaType === 1) {uris.forEach((uri => {this.imgSrcList.push(this.retrieveCurrentDirectoryUri(uri))}))jsonResult = json.stringify(this.imgSrcList)this.result?.success(jsonResult);} else if (this.mediaType === 2) {let map = new HashMap<string, string>;await this.getVideoThumbPath(uris[0]).then((videoThumb)=>{let videoUrl = this.retrieveCurrentDirectoryUri(uris[0])let coverImageUrl = this.retrieveCurrentDirectoryUri(videoThumb)map.set("videoUrl", videoUrl);map.set("coverImageUrl", coverImageUrl);this.result?.success(map);});}console.assert('result success:'+jsonResult);}).catch((err: BusinessError) => {console.error(`Invoke photoViewPicker.select failed, code is ${err.code}, message is ${err.message}`);})}async openCameraTakePhoto() {let pathDir = getContext().filesDir;let fileName = `${new Date().getTime()}`let filePath = pathDir + `/${fileName}.tmp`let result: picker.PickerResultfileIo.createRandomAccessFileSync(filePath, fileIo.OpenMode.CREATE);let uri = fileUri.getUriFromPath(filePath);let pickerProfile: picker.PickerProfile = {cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK,saveUri: uri};if (this.mediaType === 1) {result =await picker.pick(getContext(), [picker.PickerMediaType.PHOTO],pickerProfile);} else if (this.mediaType === 2) {result =await picker.pick(getContext(), [picker.PickerMediaType.VIDEO],pickerProfile);} else if (this.mediaType === 3) {result =await picker.pick(getContext(), [picker.PickerMediaType.PHOTO, picker.PickerMediaType.VIDEO],pickerProfile);} else {result =await picker.pick(getContext(), [picker.PickerMediaType.PHOTO, picker.PickerMediaType.VIDEO],pickerProfile);}console.info(`picker resultCode: ${result.resultCode},resultUri: ${result.resultUri},mediaType: ${result.mediaType}`);if (result.resultCode == 0) {if (result.mediaType === picker.PickerMediaType.PHOTO) {let imgSrc = this.retrieveCurrentDirectoryUri(result.resultUri);this.imgSrcList.push(imgSrc);this.result?.success(json.stringify(this.imgSrcList));} else {let map = new HashMap<string, string>;await this.getVideoThumbPath(result.resultUri).then((videoThumb)=>{if(videoThumb!==''){let videoUrl = this.retrieveCurrentDirectoryUri(result.resultUri)let coverImageUrl = this.retrieveCurrentDirectoryUri(videoThumb)map.set("videoUrl",videoUrl);map.set("coverImageUrl", coverImageUrl);this.result?.success(map);}});}}}retrieveCurrentDirectoryUri(uri: string): string {let realPath = FileUtils.getPathFromUri(getContext(), uri);return realPath ?? '';}async getVideoThumbPath(filePath:string) {return new Promise<string>((resolve, reject) => {setTimeout(() => {let packOpts: image.PackingOption = { format: "image/jpeg", quality: 98 }const imagePackerApi = image.createImagePacker();this.getVideoThumb(filePath).then((pixelMap)=>{imagePackerApi.packing(pixelMap, packOpts).then(async (buffer: ArrayBuffer) => {let fileName = `${new Date().getTime()}.tmp`// //文件操作let filePath = getContext().cacheDir + fileNamelet file = fileIo.openSync(filePath,fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)fileIo.writeSync(file.fd,buffer)//获取urilet urlStr = fileUri.getUriFromPath(filePath)resolve(urlStr)})})}, 0);});}///获取视频缩略图getVideoThumb = async (filePath: string) => {// 创建AVImageGenerator对象let avImageGenerator: media.AVImageGenerator = await media.createAVImageGenerator()let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY);let avFileDescriptor: media.AVFileDescriptor = { fd: file.fd };avImageGenerator.fdSrc = avFileDescriptor;// 初始化入参let timeUs = 0let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNClet param: media.PixelMapParams = {width : 300,height : 400,}// 获取缩略图(promise模式)let pixelMap = await avImageGenerator.fetchFrameByTime(timeUs, queryOption, param)// 释放资源(promise模式)avImageGenerator.release()console.info(`release success.`)fs.closeSync(file)return pixelMap};}
创作不易,如果我的内容帮助到了你,烦请小伙伴点个关注,留个言,分享给需要的人,不胜感激。
相关文章:
Flutter调用HarmonyOS NEXT原生相机拍摄相册选择照片视频
目录 1.项目背景 2.遇到的问题 3.开发准备 4.开发过程 首先创建注册调用鸿蒙原生的渠道 创建并初始化插件 绑定通道完成插件中的功能 5.具体步骤 根据传值判断是相册选取还是打开相机 相册选取照片或视频 相机拍摄照片或视频 调用picker拍摄接口获取拍摄的结果 视频…...
浅析云场景SSD实时迁移技术
在数据中心的运营管理中,负载均衡和系统容错是确保高效稳定运行的关键。SSD实时迁移技术,为解决这些问题提供了创新方案,成为数据中心技术发展的重要驱动力。 以AI训练任务为例,其运行时间长且无需用户频繁交互。数据中心的负载会…...
WordPress Hunk Companion插件节点逻辑缺陷导致Rce漏洞复现(CVE-2024-9707)(附脚本)
免责申明: 本文所描述的漏洞及其复现步骤仅供网络安全研究与教育目的使用。任何人不得将本文提供的信息用于非法目的或未经授权的系统测试。作者不对任何由于使用本文信息而导致的直接或间接损害承担责任。如涉及侵权,请及时与我们联系,我们将尽快处理并删除相关内容。 0x0…...
BGP分解实验·11——路由聚合与条件性通告(3)
续接上(2)的实验。其拓扑如下: 路由聚合的负向也就是拆分,在有双出口的情况下,在多出口做流量分担是优选方法之一。 BGP可以根据指定来源而聚合路由,在产生该聚合路由的范围内的条目注入到本地BGP表后再向…...
SQL Server 使用SELECT INTO实现表备份
在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SELECT INTO 语句将数据从一个表备份到另一个表。 备份表的 SQL 语法: SELECT * INTO 【备份表名】 FROM 【要备份的表】 SEL…...
RPC是什么?和HTTP区别?
RPC 是什么?HTTP 是什么? 作为一个程序员,假设我们需要从A电脑的进程发送一段数据到B电脑的进程,我们一般会在代码中使用 Socket 进行编程。 此时,可选性一般就是 TCP 和 UDP 二选一,由于 TCP 可靠、UDP 不…...
西藏酥油茶:高原上的醇香温暖
西藏酥油茶:高原上的醇香温暖 在西藏高原,有一种饮品,它不仅滋养了一代又一代的藏民,还承载着丰富的文化与历史,它就是西藏酥油茶。酥油茶,藏语称为“恰苏玛”,意为搅动的茶,是藏族人民日常生活中不可或缺的一部分,更是待客、祭祀等活动中的重要礼仪物品。 历史与文化渊源 酥…...
十、VUE中的CSS
一、vue中解决样式不冲突的两种方式 scoped方式 在App.vue中引入Helloworld子组件 在Helloworld子组件中再次引入我们编写Demo子组件 解释: 这种方式是在style上加了个scoped,限制了样式的使用范围。 动态类名方式 二、vue构建打包 npm run build...
论文阅读 AlphaFold 2
用AlphaFold进行非常精确的蛋白质结构的预测(AlphaFold2) 发表于2021年07月15日 NatureDOI: 10.1038/s41586-021-03819-2自然和科学杂志评选为2021年最重要的科学突破之一2021年AI在科学界最大的突破 前言 2020年11月30号, deepmind博客说AlphaFold解决了50年以来生物学的大挑…...
PVE 虚拟机安装 Debian 无图形化界面服务器
Debian 安装 Debian 镜像下载 找一个Debian镜像服务器,根据需要的版本和自己硬件选择。 iso-cd/:较小,仅包含安装所需的基础组件,可能需要网络访问来完成安装。有镜像 debian-12.9.0-amd64-netinst.isoiso-dvd/:较…...
讯飞星火大模型将超越chatgpt?
讯飞星火大模型真的能超越ChatGPT吗? 在人工智能的世界里,新技术层出不穷,而科大讯飞最近发布的讯飞星火大模型3.0引发了不少讨论。有些人甚至大胆猜测:这个模型是否能够在某些方面超越如今广受欢迎的ChatGPT?今天,我们就来深入探讨一下这个话题,分析讯飞星火大模型3.0…...
Linux解决输入法卡死问题
说明:在Ubuntu系统中,如果您需要重启输入法服务(比如fcitx或ibus),您可以按照以下步骤操作。这些步骤适用于大多数基于Ubuntu的发行版,例如Ubuntu、Linux Mint等。 一、重启Fcitx输入法服务 1、使用Ctrl …...
PPT自动化 python-pptx -7: 占位符(placeholder)
占位符(placeholder)是演示文稿中用于容纳内容的预格式化容器。它们通过让模板设计者定义格式选项,简化了创建视觉一致幻灯片的过程,同时让最终用户专注于添加内容。这加快了演示文稿的开发速度,并确保幻灯片之间的外观…...
“AI视觉贴装系统:智能贴装,精准无忧
嘿,朋友们!今天我要跟你们聊聊一个特别厉害的技术——AI视觉贴装系统。这可不是普通的贴装设备,它可是融合了人工智能、计算机视觉和自动化控制等前沿科技的“智能贴装大师”。有了它,那些繁琐、复杂的贴装工作变得轻松又精准。来…...
【Efficient AIGC】SiTo: Similarity-based Token Pruning (AAAI-2025)
文章目录 SiTo: Training-Free and Hardware-Friendly Acceleration for Diffusion Models via Similarity-based Token Pruning背景介绍方法结果消融 文章目录 SiTo: Training-Free and Hardware-Friendly Acceleration for Diffusion Models via Similarity-based Token Prun…...
音频入门(一):音频基础知识与分类的基本流程
音频信号和图像信号在做分类时的基本流程类似,区别就在于预处理部分存在不同;本文简单介绍了下音频处理的方法,以及利用深度学习模型分类的基本流程。 目录 一、音频信号简介 1. 什么是音频信号 2. 音频信号长什么样 二、音频的深度学习分…...
mac 通过 Homebrew 安装 git 遇到的问题
问题真多啊 !!! 解决方式 见 1. / 2. / 3 . / 4. / 5. remote: Enumerating objects: 290323, done. remote: Counting objects: 100% (473/473), done. remote: Compressing objects: 100% (253/253), done. error: RPC failed; curl 92 H…...
Flutter android debug 编译报错问题。插件编译报错
下面相关内容 都以 Mac 电脑为例子。 一、问题 起因:(更新 Android studio 2024.2.2.13、 Flutter SDK 3.27.2) 最近 2025年 1 月 左右,我更新了 Android studio 和 Flutter SDK 再运行就会出现下面的问题。当然 下面的提示只是其…...
【信息系统项目管理师-选择真题】2018上半年综合知识答案和详解
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 【第1题】【第2题】【第3题】【第4题】【第5题】【第6题】【第7题】【第8题】【第9题】【第10题】【第11题】【第12题】【第13题】【第14题】【第15题】【第16题】【第17题】【第18题】【第19题】【第20题】【第…...
探究 Facebook 隐私安全发展方向,未来走向何方?
随着社交媒体的普及,隐私和数据安全问题成为了全球关注的焦点。Facebook,作为全球最大的社交平台之一,其隐私安全问题尤其引人注目。近年来,随着用户数据泄露事件的不断发生,Facebook 不断调整其隐私政策,探…...
漏洞修复:Apache Tomcat 安全漏洞(CVE-2024-50379) | Apache Tomcat 安全漏洞(CVE-2024-52318)
文章目录 引言I Apache Tomcat 安全漏洞(CVE-2024-50379)漏洞描述修复建议升级Tomcat教程II Apache Tomcat 安全漏洞(CVE-2024-52318)漏洞描述修复建议III 安全警告引言 解决方案:升级到最新版Tomcat https://blog.csdn.net/z929118967/article/details/142934649 service in…...
Leecode刷题C语言之购买水果需要的最小金币数
执行结果:通过 执行用时和内存消耗如下: int dp(int* prices, int pricesSize, int index, int* memo) {if (2 * index 2 > pricesSize) {return prices[index];}if (memo[index] -1) {int minValue INT_MAX;for (int i index 1; i < 2 * index 2; i) …...
【27】Word:徐雅雯-艺术史文章❗
目录 题目 NO1.2 NO3 NO4 NO5 NO6.7 NO8.9 NO10.11 注意:修改样式的字体颜色/字号,若中英文一致,选择所有脚本。格式相似的文本→检查多选/漏选格式刷F4重复上一步操作请❗每一步检查和保存 题目 NO1.2 F12另存为布局→行号布局…...
MySQL日志详解——日志分类、二进制日志bin log、回滚日志undo log、重做日志redo log
文章目录 一、前言1.1 MySQL体系结构1.2 MySQL日志分类1.3 其他几种日志1.3.1 查询日志1.3.2 慢查询日志1.3.3 错误日志 二、bin log 二进制日志2.1 bin log简介2.2 binlog日志格式2.3 日志删除2.4 写入/刷盘机制 三、undo log 回滚日志3.1 undo log简介3.2 隐藏字段 —— 事务…...
数字MIC PDM接口
在音频采样中,我们经常会用到PCM,PDM这种方式,它们之间也是有一些区别的。 1:PDM 工作原理: PDM使用远高于PCM采样率的时钟采样调制模拟分量,每次采样结果只有1位输出(0或1&…...
dfs专题五:FloodFill算法
1.图像渲染 link:733. 图像渲染 - 力扣(LeetCode) code class Solution { public:int prev;vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int color) {if(image[sr][sc] color) return …...
笔试-二维数组
应用 快递业务有N个站点,1<N<10000;站点0、站点1可达,记作0-1;如果0-1、1-2,则站点0、站点2可达,记作0-2;s[i][j]1表示i-j可达,反之s[i][j]0表示i-j不可达;s[i][j…...
大模型GUI系列论文阅读 DAY2续:《一个具备规划、长上下文理解和程序合成能力的真实世界Web代理》
摘要 预训练的大语言模型(LLMs)近年来在自主网页自动化方面实现了更好的泛化能力和样本效率。然而,在真实世界的网站上,其性能仍然受到以下问题的影响:(1) 开放领域的复杂性,(2) 有限的上下文长度ÿ…...
如何提升IP地址查询数据服务的安全?
随着网络科技深入人们的生活之中,数据相关服务顺时代浪潮应运而生。而在数据查询相关服务之中,数据安全乃是重中之重。而如何部署数据查询服务安全,今天让我们来大致了解一下: 数据加密 数据加密是数据查询服务安全的核心技术之…...
【Leetcode】--- 接雨水
题目传送门 方法一: 前缀和后缀和 算法原理 需要两个数组。 第一个数组存储最左边到第 i 个位置的最大高度(前缀最大值) 第二个数组存储最右边到第 i 个位置的最大高度(后缀最大值) 最终第 i 个位置的 接水量 min&am…...
深入探索Math.NET:开启高效数值计算之旅
一、引言 在当今数字化时代,数值计算已然成为科学研究、工程设计、金融分析等众多领域的核心驱动力。从探索宇宙奥秘的物理学计算,到优化建筑结构的土木工程设计,再到预测市场趋势的金融建模,数值计算的身影无处不在,…...
案例研究丨浪潮云洲通过DataEase推进多维度数据可视化建设
浪潮云洲工业互联网有限公司(以下简称为“浪潮云洲”)成立于2018年,定位于工业数字基础设施建设商、具有国际影响力的工业互联网平台运营商、生产性互联网头部服务商。截至目前,浪潮云洲工业互联网平台连续五年入选跨行业跨领域工…...
Logback日志文件详细配置
完整版Logback.xml文件 放在Resources目录下即可 Mac用户更改一下日志文件存放地点即可 <FileNamePattern>/Users/***/***/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern> <?xml version"1.0" encoding"UTF-8"?> <configurati…...
TDengine 与上海电气工业互联网平台完成兼容性认证
在工业数字化转型和智能化升级的浪潮中,企业对高效、可靠的数据管理解决方案的需求日益增长。特别是在风电智能运维、火电远程运维、机床售后服务等复杂多样的工业场景下,如何实现海量设备和时序数据的高效管理,已经成为推动行业升级的关键。…...
VMware虚拟机安装macOS11
1.安装虚拟机 如果尚未安装虚拟机,请先进行安装。地址:VMware17下载地址 2、下载苹果镜像文件 macOS Big Sur 11.0.1 (20B29) 3、下载unlock文件(目的是开启VMware的macOS选项功能) https://download.csdn.net/d…...
PostgreSQL中级专家是什么意思?
数据库技术领域,PostgreSQL 作为一种广泛使用的开源关系型数据库管理系统,吸引了众多技术人员深入学习和研究。“PostgreSQL 中级专家” 是对掌握该数据库特定技能层次的一种描述。 知识储备 中级专家深入理解 PostgreSQL 的体系结构,包括进程…...
ubuntu20使用apt安装mysql8
目录 ubuntu20使用apt安装mysql8报错列表参考链接首先删除旧mysql 一、下载配置mysql8库索引下载apt包解压包配置更新apt库索引 二、下载安装mysql8三、启动mysql服务配置开机自启动,忽略 本地登录远程登录查看mysql的所有用户使用客户端远程登陆如果报错完成 参考链…...
FastDFS的安装及使用
分布式存储发展历程 前段时间 618 活动火热进行,正是购物的好时机。当我们访问这些电 商网站的时候,每一个商品都会有各式各样的图片展示介绍,这些图 片一张两张可以随便丢在服务器的某个文件夹中,可是电商网站如此 大体量的…...
二叉树(了解)c++
二叉树是一种特殊的树型结构,它的特点是: 每个结点至多只有2棵子树(即二叉树中不存在度大于2的结点) 并且二叉树的子树有左右之分,其次序不能任意颠倒,因此是一颗有序树 以A结点为例,左边的B是它的左孩子,右边的C是…...
头像生成小程序搭建(免费分享)
如下图为小程序页面的基本效果,下面将介绍该小程序的功能 页面template代码如下: <template><view class"avatar-containner"><block v-if"!showCropper"><image class"pageback" src"../../s…...
Alluxio 联手 Solidigm 推出针对 AI 工作负载的高级缓存解决方案
作者:Wayne Gao, Yi Wang, Jie Chen, Sarika Mehta Alluxio 作为全球领先的 AI 缓存解决方案供应商, 提供针对 GPU 驱动 AI 负载的高速缓存。其可扩展架构支持数万个节点,能显著降低存储带宽的消耗。Alluxio 在解决 AI 存储挑战方面的前沿技…...
【ComfyUI专栏】ComfyUI 部署Kolors
什么是Kolors?我相信一定会有朋友可能第一次听说这个生图的模型,开始我也很难想象,这竟然是快手推出的可灵AI的项目,我们可以直接利用模型来生成图片和视频。 大家可以通过直接访问可灵AI的网址获取到可灵的项目,但是对于我们来说我们需要基于ComfyUI来生成必要的图片和视…...
HBase的原理
一、什么是HBase HBase是一个分布式,版本化,面向列的数据库,依赖Hadoop和Zookeeper (1)HBase的优点 提供高可靠性、高性能、列存储、可伸缩、实时读写的数据库系统 (2) HBase 表的特性 Region包含多行 列族包含多…...
Spring Boot中如何实现异步处理
在 Spring Boot 中实现异步处理可以通过使用 Async 注解和 EnableAsync 注解来实现。以下是如何配置和使用异步处理的步骤和示例代码。 步骤: 启用异步支持: 在 Spring Boot 配置类上使用 EnableAsync 注解启用异步处理。使用 Async 注解异步方法&…...
SSM电子商城系统
🍅点赞收藏关注 → 添加文档最下方联系方式咨询本源代码、数据库🍅 本人在Java毕业设计领域有多年的经验,陆续会更新更多优质的Java实战项目希望你能有所收获,少走一些弯路。🍅关注我不迷路🍅 项目视频 电…...
新版IDEA创建数据库表
这是老版本的IDEA创建数据库表,下面可以自己勾选Not null(非空),Auto inc(自增长),Unique(唯一标识)和Primary key(主键) 这是新版的IDEA创建数据库表,Not null和Auto inc可以看得到,但Unique和Primary key…...
二叉树的存储(下)c++
链式存储 我们可以创建两个数组L[N]、r[N],分别存储i 号结点的左右孩子的编号,这样就可以通过数组下标实现链式访问。 本质上还是孩子表示法,存储的是左右孩子的信息 #include <iostream>using namespace std;const int N 1e6 10; …...
Flutter中PlatformView在鸿蒙中的使用
Flutter中PlatformView在鸿蒙中的使用 概述在Flutter中的处理鸿蒙端创建内嵌的鸿蒙视图创建PlatformView创建PlatformViewFactory创建plugin,注册platformview注册插件 概述 集成平台视图(后称为平台视图)允许将原生视图嵌入到 Flutter 应用…...
Docker—搭建Harbor和阿里云私有仓库
Harbor概述 Harbor是一个开源的企业级Docker Registry管理项目,由VMware公司开发。它的主要用途是帮助用户迅速搭建一个企业级的Docker Registry服务,提供比Docker官方公共镜像仓库更为丰富和安全的功能,特别适合企业环境使用。12 Harb…...
一篇博文了解JVM的各个内存区域
JVM的内存区域可以细分为程序计数器、虚拟机栈、本地方法栈、堆和方法区 其中,方法区和堆是线程共享的,虚拟机栈、本地方法栈和程序计数器是私有的; 先来说说程序计数器,它也被称为PC寄存器,占据着很小的内存空间…...