ImageUtils.ets 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * Copyright (c) 2024 Huawei Device Co., Ltd.
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. import { image } from '@kit.ImageKit';
  16. import { effectKit } from '@kit.ArkGraphics2D';
  17. import Logger from './Logger';
  18. import { fileIo, fileUri } from '@kit.CoreFileKit';
  19. import { http } from '@kit.NetworkKit';
  20. import { BusinessError } from '@kit.BasicServicesKit';
  21. import ResponseCode from '@ohos.net.http';
  22. import { photoAccessHelper } from '@kit.MediaLibraryKit';
  23. import fs from '@ohos.file.fs';
  24. import { FileUtil, MD5, PreferencesUtil } from '@pura/harmony-utils';
  25. import MediaTable from './MediaTable';
  26. const TAG = 'ImageUtils';
  27. export class ImageDealData {
  28. imageColor: string = 'rgba(0, 0, 2, 1.00)';
  29. imageColorHex: string = '';
  30. blurPixelMap: PixelMap | undefined = undefined;
  31. blurPixelMapForCard: PixelMap | undefined = undefined;
  32. }
  33. /**
  34. * Color conversion processing class.
  35. */
  36. class ImageUtils {
  37. /**
  38. * Generate an immersive background color for the image.
  39. * @param rRGB
  40. * @param gRGB
  41. * @param bRGB
  42. * @returns
  43. */
  44. public dealColor(rRGB: number, gRGB: number, bRGB: number) {
  45. let max = Math.max(Math.max(rRGB, gRGB), bRGB);
  46. let min = Math.min(Math.min(rRGB, gRGB), bRGB);
  47. let sHSB = max === 0 ? 0 : (max - min) / max;
  48. let bHSB = max / 255;
  49. let hHSB = 0;
  50. if (max === rRGB && gRGB >= bRGB) {
  51. hHSB = 60 * (gRGB - bRGB) / (max - min) + 0;
  52. }
  53. if (max === rRGB && gRGB < bRGB) {
  54. hHSB = 60 * (gRGB - bRGB) / (max - min) + 360;
  55. }
  56. if (max === gRGB) {
  57. hHSB = 60 * (bRGB - rRGB) / (max - min) + 120;
  58. }
  59. if (max === bRGB) {
  60. hHSB = 60 * (rRGB - gRGB) / (max - min) + 240;
  61. }
  62. if (bHSB >= 0.4) {
  63. bHSB = 0.3;
  64. } else if (bHSB >= 0.2) {
  65. bHSB -= 0.1;
  66. } else {
  67. bHSB = bHSB + 0.2;
  68. }
  69. let i: number = Math.floor((hHSB / 60) % 6);
  70. let f = (hHSB / 60) - i;
  71. let p = bHSB * (1 - sHSB);
  72. let q = bHSB * (1 - f * sHSB);
  73. let t = bHSB * (1 - (1 - f) * sHSB);
  74. switch (i) {
  75. case 0:
  76. rRGB = bHSB;
  77. gRGB = t;
  78. bRGB = p;
  79. break;
  80. case 1:
  81. rRGB = q;
  82. gRGB = bHSB;
  83. bRGB = p;
  84. break;
  85. case 2:
  86. rRGB = p;
  87. gRGB = bHSB;
  88. bRGB = t;
  89. break;
  90. case 3:
  91. rRGB = p;
  92. gRGB = q;
  93. bRGB = bHSB;
  94. break;
  95. case 4:
  96. rRGB = t;
  97. gRGB = p;
  98. bRGB = bHSB;
  99. break;
  100. case 5:
  101. rRGB = bHSB;
  102. gRGB = p;
  103. bRGB = q;
  104. break;
  105. default:
  106. break;
  107. }
  108. return [Math.floor(rRGB * 255.0), Math.floor(gRGB * 255.0), Math.floor(bRGB * 255.0)];
  109. }
  110. public async getBlurPixelMap(pixelMap: PixelMap, blur: number): Promise<PixelMap> {
  111. let filter = effectKit.createEffect(pixelMap);
  112. filter.blur(blur);
  113. let blurPixelMap: PixelMap = await filter.getEffectPixelMap();
  114. return blurPixelMap;
  115. }
  116. public getImageDealData(context: Context, imagePath: string,filePath?:string): Promise<ImageDealData> {
  117. return new Promise(async (resolve, reject) => {
  118. try {
  119. console.log(` onecold testtag imagePath:`+imagePath);
  120. let newPath = ''
  121. if(filePath){
  122. let name = await MD5.digestSync(filePath)
  123. newPath = context.filesDir + FileUtil.separator + name
  124. newPath = fileUri.getUriFromPath(newPath)
  125. }
  126. if(imagePath.startsWith('http')){
  127. // let isExite = fileIo.accessSync(newPath)
  128. let isExite = PreferencesUtil.getBooleanSync(newPath+'isAccessImage',false)
  129. console.log(" onecold testtag isExite = "+isExite);
  130. if(!isExite){
  131. // FileUtil.unlinkSync(newPath)
  132. let result = await loadImageWithUrl(context,imagePath,newPath)
  133. if(result&&filePath){//这里更新数据库 但是测试发现更新数据失败 留着以后修复
  134. let table:MediaTable = new MediaTable( context)
  135. table.updatePixelMapPath(filePath,newPath, (success: boolean, error?: string) => {
  136. if (success) {
  137. console.log(" onecold testtag 更新音乐封面成功,数据库已同步");
  138. } else {
  139. console.error(" onecold testtag 更新音乐封面数据库失败原因: " + error);
  140. }
  141. });
  142. }
  143. console.log(` onecold testtag newPath:`+newPath);
  144. }
  145. imagePath = newPath
  146. }
  147. console.log(` onecold testtag imagePath2:`+imagePath);
  148. let file = fileIo.openSync(imagePath, fileIo.OpenMode.READ_ONLY | fileIo.OpenMode.CREATE)
  149. let fd = file.fd;
  150. let imageSource = image.createImageSource(fd);
  151. // let value = context.resourceManager.getMediaContentSync(imageSource)
  152. let opts: image.DecodingOptions = { editable: false };
  153. // 使用ImageSource创建PixelMap
  154. imageSource.createPixelMap(opts).then(async pixelMap => {
  155. let imageData = await this.getImageDealDataByArr2(pixelMap)
  156. resolve(imageData);
  157. }).catch((error: Error) => {
  158. console.error(`onecold 创建PixelMap失败: ${error.message}`);
  159. reject(error);
  160. });
  161. } catch (err) {
  162. Logger.info(TAG, `getImageDealData err :${JSON.stringify(err)}`)
  163. reject(err);
  164. }
  165. });
  166. }
  167. public async compressImage(sourcePixelMap: image.PixelMap, maxCompressedImageSize: number): Promise<PixelMap> {
  168. Logger.info(TAG, 'compressImage');
  169. let compressedImageData: ArrayBuffer = await this.packing(sourcePixelMap);
  170. if (compressedImageData.byteLength <= maxCompressedImageSize * 1024) {
  171. Logger.info(TAG, 'compressImage first');
  172. return sourcePixelMap;
  173. }
  174. let imageScale = 1;
  175. while (compressedImageData.byteLength > maxCompressedImageSize * 1024) {
  176. if (imageScale > 0) {
  177. imageScale = imageScale - 0.05;
  178. await sourcePixelMap.scale(imageScale, imageScale);
  179. compressedImageData = await this.packing(sourcePixelMap);
  180. } else {
  181. break;
  182. }
  183. }
  184. let afterCompressionSize = (compressedImageData.byteLength / 1024).toFixed(1);
  185. Logger.info(TAG, `compressImage afterCompressionSize:` + afterCompressionSize);
  186. if (compressedImageData.byteLength > maxCompressedImageSize * 1024) {
  187. Logger.info(TAG, 'compress iamge failed');
  188. }
  189. return sourcePixelMap;
  190. }
  191. async packing(sourcePixelMap: image.PixelMap): Promise<ArrayBuffer> {
  192. const imagePackerApi = image.createImagePacker();
  193. const packOpts: image.PackingOption = { format: 'image/' + 'jpeg', quality: 100 };
  194. const data: ArrayBuffer = await imagePackerApi.packing(sourcePixelMap, packOpts);
  195. return data;
  196. }
  197. public getImageDealDataByArr(buffer: ArrayBuffer): Promise<ImageDealData> {
  198. return new Promise(async (resolve, reject) => {
  199. try {
  200. let pixelMap = image.createImageSource(buffer).createPixelMapSync();
  201. if (buffer.byteLength > 2048 * 1024) {
  202. pixelMap = await this.compressImage(pixelMap, 2048);
  203. }
  204. let imageData = new ImageDealData();
  205. let colorPicker = await effectKit.createColorPicker(pixelMap);
  206. let mainColor = colorPicker.getMainColorSync();
  207. let colorArr = this.dealColor(mainColor.red, mainColor.green, mainColor.blue);
  208. let imageColor = `rgba(${colorArr[0]}, ${colorArr[1]}, ${colorArr[2]}, 1)`;
  209. let imageColorHex = `${colorArr[0].toString(16)}${colorArr[1].toString(16)}${colorArr[2].toString(16)}`;
  210. Logger.info(TAG, `getImageDealDataByArr imageColor :${imageColor}`);
  211. Logger.info(TAG, `getImageDealDataByArr imageColorHex :${imageColorHex}`);
  212. imageData.imageColor = imageColor;
  213. imageData.imageColorHex = imageColorHex;
  214. imageData.blurPixelMap = await this.getBlurPixelMap(pixelMap, 15);
  215. imageData.blurPixelMapForCard = await this.getBlurPixelMap(pixelMap, 100);
  216. Logger.info(TAG, `getImageDealDataByArr success`);
  217. resolve(imageData);
  218. } catch (err) {
  219. Logger.info(TAG, `getImageDealDataByArr err :${JSON.stringify(err)}`)
  220. reject(err);
  221. }
  222. });
  223. }
  224. public getImageDealDataByArr2(pixelMap: image.PixelMap): Promise<ImageDealData> {
  225. return new Promise(async (resolve, reject) => {
  226. try {
  227. let imageData = new ImageDealData();
  228. let colorPicker = await effectKit.createColorPicker(pixelMap);
  229. let mainColor = colorPicker.getMainColorSync();
  230. let colorArr = this.dealColor(mainColor.red, mainColor.green, mainColor.blue);
  231. let imageColor = `rgba(${colorArr[0]}, ${colorArr[1]}, ${colorArr[2]}, 1)`;
  232. let imageColorHex = `${colorArr[0].toString(16)}${colorArr[1].toString(16)}${colorArr[2].toString(16)}`;
  233. Logger.info(TAG, `getImageDealDataByArr imageColor :${imageColor}`);
  234. Logger.info(TAG, `getImageDealDataByArr imageColorHex :${imageColorHex}`);
  235. imageData.imageColor = imageColor;
  236. imageData.imageColorHex = imageColorHex;
  237. imageData.blurPixelMap = await this.getBlurPixelMap(pixelMap, 15);
  238. imageData.blurPixelMapForCard = await this.getBlurPixelMap(pixelMap, 100);
  239. Logger.info(TAG, `getImageDealDataByArr success`);
  240. resolve(imageData);
  241. } catch (err) {
  242. Logger.info(TAG, `getImageDealDataByArr err :${JSON.stringify(err)}`)
  243. reject(err);
  244. }
  245. });
  246. }
  247. }
  248. export default new ImageUtils();
  249. export async function loadImageWithUrl(context: Context, url: string, filePath: string,): Promise<boolean > {
  250. return new Promise((resolve, reject) => {
  251. http.createHttp().request(url, { method: http.RequestMethod.GET, connectTimeout: 60000, readTimeout: 60000 },
  252. async (error: BusinessError, data: http.HttpResponse) => {
  253. if (error) {
  254. console.error(`http request failed with. Code: ${error.code}, message: ${error.message}`);
  255. reject(false);
  256. } else {
  257. if (ResponseCode.ResponseCode.OK === data.responseCode) {
  258. let imageBuffer: ArrayBuffer = data.result as ArrayBuffer;
  259. try {
  260. // 获取相册路径
  261. let file = await fs.open(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
  262. // 写入文件
  263. await fs.write(file.fd, imageBuffer);
  264. // 关闭文件
  265. await fs.close(file.fd);
  266. //更新数据库的
  267. PreferencesUtil.putSync(filePath+'isAccessImage',true)
  268. // 返回文件标识符
  269. resolve(true);
  270. } catch (error) {
  271. console.error("error is " + JSON.stringify(error));
  272. reject(false);
  273. }
  274. } else {
  275. console.error("error occurred when image downloaded!");
  276. reject(false);
  277. }
  278. }
  279. });
  280. });
  281. }