| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- import { photoAccessHelper } from '@kit.MediaLibraryKit';
- import { fileIo } from '@kit.CoreFileKit';
- import { FileUtil } from '@pura/harmony-utils';
- import Logger from './Logger';
- import { Context } from '@kit.AbilityKit';
- import { fileUri } from '@kit.CoreFileKit';
- const TAG = 'ImagePickerUtil';
- /**
- * 图片选择工具类
- */
- export class ImagePickerUtil {
- /**
- * 选择图片并返回复制到应用私有目录的路径
- * @param context 应用上下文
- * @param maxSelectCount 最大选择数量,默认1张
- * @returns 返回选择的图片路径数组
- */
- static async selectImages(context: Context, maxSelectCount: number = 1): Promise<string[]> {
- try {
- Logger.info(TAG, '开始选择图片');
- const photoSelectOptions: photoAccessHelper.PhotoSelectOptions = {
- MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
- maxSelectNumber: maxSelectCount
- };
- const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
- const photoSelectResult = await photoViewPicker.select(photoSelectOptions);
- Logger.info(TAG, `选择了 ${photoSelectResult.photoUris.length} 张图片`);
- if (photoSelectResult.photoUris.length === 0) {
- return [];
- }
- // 将选中的图片复制到应用私有目录
- const copiedPaths: string[] = [];
- for (const uri of photoSelectResult.photoUris) {
- try {
- const copiedPath = await ImagePickerUtil.copyImageToAppDir(context, uri);
- if (copiedPath) {
- copiedPaths.push(copiedPath);
- }
- } catch (error) {
- Logger.error(TAG, `复制图片失败: ${(error as Error).message}`);
- }
- }
- return copiedPaths;
- } catch (error) {
- Logger.error(TAG, `选择图片失败: ${(error as Error).message}`);
- return [];
- }
- }
- /**
- * 选择单张图片
- * @param context 应用上下文
- * @returns 返回选择的图片路径,如果取消选择返回null
- */
- static async selectSingleImage(context: Context): Promise<string | null> {
- const paths = await ImagePickerUtil.selectImages(context, 1);
- return paths.length > 0 ? paths[0] : null;
- }
- /**
- * 将图片复制到应用私有目录
- * @param context 应用上下文
- * @param imageUri 图片URI
- * @param type 图片类型,默认为playlist,可选webdav
- * @returns 返回复制后的图片路径
- */
- private static async copyImageToAppDir(context: Context, imageUri: string, type: string = 'playlist'): Promise<string> {
- try {
- // 生成唯一文件名
- const timestamp = Date.now();
- const randomSuffix = Math.random().toString(36).substring(2, 8);
- const fileName = `${type}_cover_${timestamp}_${randomSuffix}.jpg`;
- // 目标路径
- const targetDir = context.filesDir + FileUtil.separator + `${type}_covers`;
- const targetPath = targetDir + FileUtil.separator + fileName;
- // 确保目录存在
- try {
- fileIo.mkdirSync(targetDir);
- } catch (error) {
- // 目录可能已存在,忽略错误
- }
- // 打开源文件和目标文件
- const sourceFile = fileIo.openSync(imageUri, fileIo.OpenMode.READ_ONLY);
- const targetFile = fileIo.openSync(targetPath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
- // 复制文件内容
- const buffer = new ArrayBuffer(4096);
- let readSize = 0;
- do {
- readSize = fileIo.readSync(sourceFile.fd, buffer);
- if (readSize > 0) {
- fileIo.writeSync(targetFile.fd, buffer, { length: readSize });
- }
- } while (readSize > 0);
- // 关闭文件
- fileIo.closeSync(sourceFile.fd);
- fileIo.closeSync(targetFile.fd);
- // 转换为URI格式(关键步骤!)
- const uriPath = fileUri.getUriFromPath(targetPath);
- Logger.info(TAG, `图片复制成功: ${uriPath}`);
- return uriPath;
- } catch (error) {
- Logger.error(TAG, `复制图片失败: ${(error as Error).message}`);
- throw new Error(`复制图片失败: ${(error as Error).message}`);
- }
- }
- /**
- * 选择单张图片(WebDAV账户封面)
- * @param context 应用上下文
- * @returns 返回选择的图片路径,如果取消选择返回null
- */
- static async selectSingleWebDavCover(context: Context): Promise<string | null> {
- try {
- Logger.info(TAG, '开始选择WebDAV账户封面');
- const photoSelectOptions: photoAccessHelper.PhotoSelectOptions = {
- MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
- maxSelectNumber: 1
- };
- const photoViewPicker = new photoAccessHelper.PhotoViewPicker();
- const photoSelectResult = await photoViewPicker.select(photoSelectOptions);
- Logger.info(TAG, `选择了 ${photoSelectResult.photoUris.length} 张图片`);
- if (photoSelectResult.photoUris.length === 0) {
- return null;
- }
- // 将选中的图片复制到应用私有目录
- const uri = photoSelectResult.photoUris[0];
- const copiedPath = await ImagePickerUtil.copyImageToAppDir(context, uri, 'webdav');
- return copiedPath;
- } catch (error) {
- Logger.error(TAG, `选择WebDAV账户封面失败: ${(error as Error).message}`);
- return null;
- }
- }
- /**
- * 删除歌单封面图片
- * @param imagePath 图片路径
- */
- static deleteImage(imagePath: string): void {
- try {
- if (imagePath && ImagePickerUtil.checkFileExists(imagePath)) {
- fileIo.unlinkSync(imagePath);
- Logger.info(TAG, `删除图片成功: ${imagePath}`);
- }
- } catch (error) {
- Logger.error(TAG, `删除图片失败: ${(error as Error).message}`);
- }
- }
- /**
- * 检查文件是否存在
- * @param filePath 文件路径
- * @returns 是否存在
- */
- private static checkFileExists(filePath: string): boolean {
- try {
- fileIo.accessSync(filePath);
- return true;
- } catch (error) {
- return false;
- }
- }
- /**
- * 检查图片文件是否存在
- * @param imagePath 图片路径
- * @returns 是否存在
- */
- static imageExists(imagePath: string): boolean {
- if (!imagePath) {
- Logger.info(TAG, '图片路径为空');
- return false;
- }
- const exists = ImagePickerUtil.checkFileExists(imagePath);
- Logger.info(TAG, `检查图片是否存在: ${imagePath}, 结果: ${exists}`);
- return exists;
- }
- /**
- * 获取歌单封面目录
- * @param context 应用上下文
- * @returns 歌单封面目录路径
- */
- static getPlaylistCoverDir(context: Context): string {
- return context.filesDir + FileUtil.separator + 'playlist_covers';
- }
- /**
- * 清理未使用的封面图片
- * @param context 应用上下文
- * @param usedPaths 正在使用的图片路径列表
- */
- static async cleanupUnusedCovers(context: Context, usedPaths: string[]): Promise<void> {
- try {
- const coverDir = ImagePickerUtil.getPlaylistCoverDir(context);
- // 检查目录是否存在
- if (!ImagePickerUtil.checkFileExists(coverDir)) {
- return;
- }
- // 读取目录中的所有文件
- const files = fileIo.listFileSync(coverDir);
- const usedFileNames = new Set<string>();
- // 将使用中的路径转换为文件名
- for (const path of usedPaths) {
- if (path && path.includes('playlist_covers' + FileUtil.separator)) {
- const fileName = path.substring(path.lastIndexOf(FileUtil.separator) + 1);
- usedFileNames.add(fileName);
- }
- }
- // 删除未使用的文件
- for (const fileName of files) {
- if (!usedFileNames.has(fileName)) {
- const filePath = coverDir + FileUtil.separator + fileName;
- try {
- fileIo.unlinkSync(filePath);
- Logger.info(TAG, `清理未使用的封面: ${filePath}`);
- } catch (error) {
- Logger.error(TAG, `清理封面失败: ${filePath}, 错误: ${(error as Error).message}`);
- }
- }
- }
- Logger.info(TAG, '封面清理完成');
- } catch (error) {
- Logger.error(TAG, `清理封面失败: ${(error as Error).message}`);
- }
- }
- }
- export default ImagePickerUtil;
|