/* * Copyright (c) 2024 Huawei Device 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 { image } from '@kit.ImageKit'; import { effectKit } from '@kit.ArkGraphics2D'; import Logger from './Logger'; import { fileIo, fileUri } from '@kit.CoreFileKit'; import { http } from '@kit.NetworkKit'; import { BusinessError } from '@kit.BasicServicesKit'; import ResponseCode from '@ohos.net.http'; import { photoAccessHelper } from '@kit.MediaLibraryKit'; import fs from '@ohos.file.fs'; import { FileUtil, MD5, PreferencesUtil } from '@pura/harmony-utils'; import MediaTable from './MediaTable'; const TAG = 'ImageUtils'; export class ImageDealData { imageColor: string = 'rgba(0, 0, 2, 1.00)'; imageColorHex: string = ''; blurPixelMap: PixelMap | undefined = undefined; blurPixelMapForCard: PixelMap | undefined = undefined; } /** * Color conversion processing class. */ class ImageUtils { /** * Generate an immersive background color for the image. * @param rRGB * @param gRGB * @param bRGB * @returns */ public dealColor(rRGB: number, gRGB: number, bRGB: number) { let max = Math.max(Math.max(rRGB, gRGB), bRGB); let min = Math.min(Math.min(rRGB, gRGB), bRGB); let sHSB = max === 0 ? 0 : (max - min) / max; let bHSB = max / 255; let hHSB = 0; if (max === rRGB && gRGB >= bRGB) { hHSB = 60 * (gRGB - bRGB) / (max - min) + 0; } if (max === rRGB && gRGB < bRGB) { hHSB = 60 * (gRGB - bRGB) / (max - min) + 360; } if (max === gRGB) { hHSB = 60 * (bRGB - rRGB) / (max - min) + 120; } if (max === bRGB) { hHSB = 60 * (rRGB - gRGB) / (max - min) + 240; } if (bHSB >= 0.4) { bHSB = 0.3; } else if (bHSB >= 0.2) { bHSB -= 0.1; } else { bHSB = bHSB + 0.2; } let i: number = Math.floor((hHSB / 60) % 6); let f = (hHSB / 60) - i; let p = bHSB * (1 - sHSB); let q = bHSB * (1 - f * sHSB); let t = bHSB * (1 - (1 - f) * sHSB); switch (i) { case 0: rRGB = bHSB; gRGB = t; bRGB = p; break; case 1: rRGB = q; gRGB = bHSB; bRGB = p; break; case 2: rRGB = p; gRGB = bHSB; bRGB = t; break; case 3: rRGB = p; gRGB = q; bRGB = bHSB; break; case 4: rRGB = t; gRGB = p; bRGB = bHSB; break; case 5: rRGB = bHSB; gRGB = p; bRGB = q; break; default: break; } return [Math.floor(rRGB * 255.0), Math.floor(gRGB * 255.0), Math.floor(bRGB * 255.0)]; } public async getBlurPixelMap(pixelMap: PixelMap, blur: number): Promise { let filter = effectKit.createEffect(pixelMap); filter.blur(blur); let blurPixelMap: PixelMap = await filter.getEffectPixelMap(); return blurPixelMap; } public getImageDealData(context: Context, imagePath: string,filePath?:string): Promise { return new Promise(async (resolve, reject) => { try { console.log(` onecold testtag imagePath:`+imagePath); let newPath = '' if(filePath){ let name = await MD5.digestSync(filePath) newPath = context.filesDir + FileUtil.separator + name newPath = fileUri.getUriFromPath(newPath) } if(imagePath.startsWith('http')){ // let isExite = fileIo.accessSync(newPath) let isExite = PreferencesUtil.getBooleanSync(newPath+'isAccessImage',false) console.log(" onecold testtag isExite = "+isExite); if(!isExite){ // FileUtil.unlinkSync(newPath) let result = await loadImageWithUrl(context,imagePath,newPath) if(result&&filePath){//这里更新数据库 但是测试发现更新数据失败 留着以后修复 let table:MediaTable = new MediaTable( context) table.updatePixelMapPath(filePath,newPath, (success: boolean, error?: string) => { if (success) { console.log(" onecold testtag 更新音乐封面成功,数据库已同步"); } else { console.error(" onecold testtag 更新音乐封面数据库失败原因: " + error); } }); } console.log(` onecold testtag newPath:`+newPath); } imagePath = newPath } console.log(` onecold testtag imagePath2:`+imagePath); let file = fileIo.openSync(imagePath, fileIo.OpenMode.READ_ONLY | fileIo.OpenMode.CREATE) let fd = file.fd; let imageSource = image.createImageSource(fd); // let value = context.resourceManager.getMediaContentSync(imageSource) let opts: image.DecodingOptions = { editable: false }; // 使用ImageSource创建PixelMap imageSource.createPixelMap(opts).then(async pixelMap => { let imageData = await this.getImageDealDataByArr2(pixelMap) resolve(imageData); }).catch((error: Error) => { console.error(`onecold 创建PixelMap失败: ${error.message}`); reject(error); }); } catch (err) { Logger.info(TAG, `getImageDealData err :${JSON.stringify(err)}`) reject(err); } }); } public async compressImage(sourcePixelMap: image.PixelMap, maxCompressedImageSize: number): Promise { Logger.info(TAG, 'compressImage'); let compressedImageData: ArrayBuffer = await this.packing(sourcePixelMap); if (compressedImageData.byteLength <= maxCompressedImageSize * 1024) { Logger.info(TAG, 'compressImage first'); return sourcePixelMap; } let imageScale = 1; while (compressedImageData.byteLength > maxCompressedImageSize * 1024) { if (imageScale > 0) { imageScale = imageScale - 0.05; await sourcePixelMap.scale(imageScale, imageScale); compressedImageData = await this.packing(sourcePixelMap); } else { break; } } let afterCompressionSize = (compressedImageData.byteLength / 1024).toFixed(1); Logger.info(TAG, `compressImage afterCompressionSize:` + afterCompressionSize); if (compressedImageData.byteLength > maxCompressedImageSize * 1024) { Logger.info(TAG, 'compress iamge failed'); } return sourcePixelMap; } async packing(sourcePixelMap: image.PixelMap): Promise { const imagePackerApi = image.createImagePacker(); const packOpts: image.PackingOption = { format: 'image/' + 'jpeg', quality: 100 }; const data: ArrayBuffer = await imagePackerApi.packing(sourcePixelMap, packOpts); return data; } public getImageDealDataByArr(buffer: ArrayBuffer): Promise { return new Promise(async (resolve, reject) => { try { let pixelMap = image.createImageSource(buffer).createPixelMapSync(); if (buffer.byteLength > 2048 * 1024) { pixelMap = await this.compressImage(pixelMap, 2048); } let imageData = new ImageDealData(); let colorPicker = await effectKit.createColorPicker(pixelMap); let mainColor = colorPicker.getMainColorSync(); let colorArr = this.dealColor(mainColor.red, mainColor.green, mainColor.blue); let imageColor = `rgba(${colorArr[0]}, ${colorArr[1]}, ${colorArr[2]}, 1)`; let imageColorHex = `${colorArr[0].toString(16)}${colorArr[1].toString(16)}${colorArr[2].toString(16)}`; Logger.info(TAG, `getImageDealDataByArr imageColor :${imageColor}`); Logger.info(TAG, `getImageDealDataByArr imageColorHex :${imageColorHex}`); imageData.imageColor = imageColor; imageData.imageColorHex = imageColorHex; imageData.blurPixelMap = await this.getBlurPixelMap(pixelMap, 15); imageData.blurPixelMapForCard = await this.getBlurPixelMap(pixelMap, 100); Logger.info(TAG, `getImageDealDataByArr success`); resolve(imageData); } catch (err) { Logger.info(TAG, `getImageDealDataByArr err :${JSON.stringify(err)}`) reject(err); } }); } public getImageDealDataByArr2(pixelMap: image.PixelMap): Promise { return new Promise(async (resolve, reject) => { try { let imageData = new ImageDealData(); let colorPicker = await effectKit.createColorPicker(pixelMap); let mainColor = colorPicker.getMainColorSync(); let colorArr = this.dealColor(mainColor.red, mainColor.green, mainColor.blue); let imageColor = `rgba(${colorArr[0]}, ${colorArr[1]}, ${colorArr[2]}, 1)`; let imageColorHex = `${colorArr[0].toString(16)}${colorArr[1].toString(16)}${colorArr[2].toString(16)}`; Logger.info(TAG, `getImageDealDataByArr imageColor :${imageColor}`); Logger.info(TAG, `getImageDealDataByArr imageColorHex :${imageColorHex}`); imageData.imageColor = imageColor; imageData.imageColorHex = imageColorHex; imageData.blurPixelMap = await this.getBlurPixelMap(pixelMap, 15); imageData.blurPixelMapForCard = await this.getBlurPixelMap(pixelMap, 100); Logger.info(TAG, `getImageDealDataByArr success`); resolve(imageData); } catch (err) { Logger.info(TAG, `getImageDealDataByArr err :${JSON.stringify(err)}`) reject(err); } }); } } export default new ImageUtils(); export async function loadImageWithUrl(context: Context, url: string, filePath: string,): Promise { return new Promise((resolve, reject) => { http.createHttp().request(url, { method: http.RequestMethod.GET, connectTimeout: 60000, readTimeout: 60000 }, async (error: BusinessError, data: http.HttpResponse) => { if (error) { console.error(`http request failed with. Code: ${error.code}, message: ${error.message}`); reject(false); } else { if (ResponseCode.ResponseCode.OK === data.responseCode) { let imageBuffer: ArrayBuffer = data.result as ArrayBuffer; try { // 获取相册路径 let file = await fs.open(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE); // 写入文件 await fs.write(file.fd, imageBuffer); // 关闭文件 await fs.close(file.fd); //更新数据库的 PreferencesUtil.putSync(filePath+'isAccessImage',true) // 返回文件标识符 resolve(true); } catch (error) { console.error("error is " + JSON.stringify(error)); reject(false); } } else { console.error("error occurred when image downloaded!"); reject(false); } } }); }); }