• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 
16 #include "core/image/image_provider.h"
17 
18 #include "image_compressor.h"
19 
20 #ifdef USE_ROSEN_DRAWING
21 #include "drawing/engine_adapter/skia_adapter/skia_data.h"
22 #include "drawing/engine_adapter/skia_adapter/skia_image.h"
23 #include "drawing/engine_adapter/skia_adapter/skia_graphics.h"
24 #endif
25 
26 #include "base/thread/background_task_executor.h"
27 #include "core/common/container.h"
28 #ifdef USE_ROSEN_DRAWING
29 #include "core/components_ng/image_provider/adapter/rosen/drawing_image_data.h"
30 #include "core/components_ng/render/adapter/rosen/drawing_image.h"
31 #endif
32 #include "core/image/image_file_cache.h"
33 #include "core/image/image_object.h"
34 
35 namespace OHOS::Ace {
36 namespace {
37 
38 // If a picture is a wide color gamut picture, its area value will be larger than this threshold.
39 constexpr double SRGB_GAMUT_AREA = 0.104149;
40 } // namespace
41 
42 std::mutex ImageProvider::loadingImageMutex_;
43 std::unordered_map<std::string, std::vector<LoadCallback>> ImageProvider::loadingImage_;
44 
45 std::mutex ImageProvider::uploadMutex_;
46 std::unordered_map<std::string, std::vector<LoadCallback>> ImageProvider::uploadingImage_;
47 
TrySetLoadingImage(const ImageSourceInfo & imageInfo,const ImageObjSuccessCallback & successCallback,const UploadSuccessCallback & uploadCallback,const FailedCallback & failedCallback)48 bool ImageProvider::TrySetLoadingImage(const ImageSourceInfo& imageInfo, const ImageObjSuccessCallback& successCallback,
49     const UploadSuccessCallback& uploadCallback, const FailedCallback& failedCallback)
50 {
51     std::lock_guard lock(loadingImageMutex_);
52     auto key = imageInfo.GetKey();
53     auto iter = loadingImage_.find(key);
54     if (iter == loadingImage_.end()) {
55         std::vector<LoadCallback> callbacks { { successCallback, uploadCallback, failedCallback } };
56         loadingImage_.emplace(key, callbacks);
57         return true;
58     } else {
59         LOGI("other thread is loading same image: %{private}s", imageInfo.ToString().c_str());
60         iter->second.emplace_back(successCallback, uploadCallback, failedCallback);
61         return false;
62     }
63 }
64 
ProccessLoadingResult(const RefPtr<TaskExecutor> & taskExecutor,const ImageSourceInfo & imageInfo,bool canStartUploadImageObj,const RefPtr<ImageObject> & imageObj,const RefPtr<PipelineBase> & context,const std::string & errorMsg)65 void ImageProvider::ProccessLoadingResult(const RefPtr<TaskExecutor>& taskExecutor, const ImageSourceInfo& imageInfo,
66     bool canStartUploadImageObj, const RefPtr<ImageObject>& imageObj, const RefPtr<PipelineBase>& context,
67     const std::string& errorMsg)
68 {
69     std::lock_guard lock(loadingImageMutex_);
70     std::vector<LoadCallback> callbacks;
71     auto key = imageInfo.GetKey();
72     auto iter = loadingImage_.find(key);
73     if (iter != loadingImage_.end()) {
74         std::swap(callbacks, iter->second);
75         for (const auto& callback : callbacks) {
76             if (imageObj == nullptr) {
77                 taskExecutor->PostTask(
78                     [imageInfo, callback, errorMsg]() {
79                         if (callback.failedCallback) {
80                             callback.failedCallback(imageInfo, errorMsg);
81                         }
82                     },
83                     TaskExecutor::TaskType::UI, "ArkUIImageProviderLoadFailed");
84                 return;
85             }
86             auto obj = imageObj->Clone();
87             taskExecutor->PostTask(
88                 [obj, imageInfo, callback]() {
89                     if (callback.successCallback) {
90                         callback.successCallback(imageInfo, obj);
91                     }
92                 },
93                 TaskExecutor::TaskType::UI, "ArkUIImageProviderLoadSuccess");
94             if (canStartUploadImageObj) {
95                 bool forceResize = (!obj->IsSvg()) && (imageInfo.IsSourceDimensionValid());
96                 obj->UploadToGpuForRender(
97                     context, callback.uploadCallback, callback.failedCallback, obj->GetImageSize(), forceResize, true);
98             }
99         }
100     } else {
101         LOGW("no loading image: %{private}s", imageInfo.ToString().c_str());
102     }
103     loadingImage_.erase(key);
104 }
105 
TryUploadingImage(const std::string & key,const UploadSuccessCallback & successCallback,const FailedCallback & failedCallback)106 bool ImageProvider::TryUploadingImage(
107     const std::string& key, const UploadSuccessCallback& successCallback, const FailedCallback& failedCallback)
108 {
109     std::lock_guard lock(uploadMutex_);
110     auto iter = uploadingImage_.find(key);
111     if (iter == uploadingImage_.end()) {
112         std::vector<LoadCallback> callbacks = { { nullptr, successCallback, failedCallback } };
113         uploadingImage_.emplace(key, callbacks);
114         return true;
115     } else {
116         iter->second.emplace_back(nullptr, successCallback, failedCallback);
117         return false;
118     }
119 }
120 
ProccessUploadResult(const RefPtr<TaskExecutor> & taskExecutor,const ImageSourceInfo & imageInfo,const Size & imageSize,const RefPtr<NG::CanvasImage> & canvasImage,const std::string & errorMsg)121 void ImageProvider::ProccessUploadResult(const RefPtr<TaskExecutor>& taskExecutor, const ImageSourceInfo& imageInfo,
122     const Size& imageSize, const RefPtr<NG::CanvasImage>& canvasImage, const std::string& errorMsg)
123 {
124     std::lock_guard lock(uploadMutex_);
125     std::vector<LoadCallback> callbacks;
126     auto key = ImageObject::GenerateCacheKey(imageInfo, imageSize);
127     auto iter = uploadingImage_.find(key);
128     if (iter != uploadingImage_.end()) {
129         std::swap(callbacks, iter->second);
130         taskExecutor->PostTask(
131             [callbacks, imageInfo, canvasImage, errorMsg]() {
132                 for (auto callback : callbacks) {
133                     if (canvasImage) {
134                         callback.uploadCallback(imageInfo, canvasImage);
135                     } else {
136                         callback.failedCallback(imageInfo, errorMsg);
137                     }
138                 }
139             },
140             TaskExecutor::TaskType::UI, "ArkUIImageProviderUploadResult");
141     } else {
142         LOGW("no uploading image: %{private}s", imageInfo.ToString().c_str());
143     }
144     uploadingImage_.erase(key);
145 }
146 
FetchImageObject(const ImageSourceInfo & imageInfo,const ImageObjSuccessCallback & successCallback,const UploadSuccessCallback & uploadSuccessCallback,const FailedCallback & failedCallback,const WeakPtr<PipelineBase> & context,bool syncMode,bool useSkiaSvg,bool needAutoResize,const OnPostBackgroundTask & onBackgroundTaskPostCallback)147 void ImageProvider::FetchImageObject(const ImageSourceInfo& imageInfo, const ImageObjSuccessCallback& successCallback,
148     const UploadSuccessCallback& uploadSuccessCallback, const FailedCallback& failedCallback,
149     const WeakPtr<PipelineBase>& context, bool syncMode, bool useSkiaSvg, bool needAutoResize,
150     const OnPostBackgroundTask& onBackgroundTaskPostCallback)
151 {
152     auto task = [context, imageInfo, successCallback, failedCallback, useSkiaSvg, uploadSuccessCallback, needAutoResize,
153                     id = Container::CurrentId(), syncMode]() mutable {
154         ContainerScope scope(id);
155         auto pipelineContext = context.Upgrade();
156         if (!pipelineContext) {
157             LOGE("pipeline context has been released. imageInfo: %{private}s", imageInfo.ToString().c_str());
158             return;
159         }
160         auto taskExecutor = pipelineContext->GetTaskExecutor();
161         if (!taskExecutor) {
162             LOGE("task executor is null. imageInfo: %{private}s", imageInfo.ToString().c_str());
163             return;
164         }
165         if (!syncMode && !TrySetLoadingImage(imageInfo, successCallback, uploadSuccessCallback, failedCallback)) {
166             LOGI("same source is loading: %{private}s", imageInfo.ToString().c_str());
167             return;
168         }
169         RefPtr<ImageObject> imageObj = QueryImageObjectFromCache(imageInfo, pipelineContext);
170         if (!imageObj) { // if image object is not in cache, generate a new one.
171             imageObj = GeneratorAceImageObject(imageInfo, pipelineContext, useSkiaSvg);
172         }
173         if (!imageObj) { // if it fails to generate an image object, trigger fail callback.
174             if (syncMode) {
175                 failedCallback(
176                     imageInfo, "Image data may be broken or absent, please check if image file or image data is valid");
177                 return;
178             }
179             ProccessLoadingResult(taskExecutor, imageInfo, false, nullptr, pipelineContext,
180                 "Image data may be broken or absent, please check if image file or image data is valid.");
181             return;
182         }
183         if (syncMode) {
184             successCallback(imageInfo, imageObj);
185         } else {
186             ProccessLoadingResult(taskExecutor, imageInfo, !needAutoResize && (imageObj->GetFrameCount() == 1),
187                 imageObj, pipelineContext);
188         }
189     };
190     if (syncMode) {
191         task();
192         return;
193     }
194     CancelableTask cancelableTask(std::move(task));
195     if (onBackgroundTaskPostCallback) {
196         onBackgroundTaskPostCallback(cancelableTask);
197     }
198     BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
199 }
200 
QueryImageObjectFromCache(const ImageSourceInfo & imageInfo,const RefPtr<PipelineBase> & pipelineContext)201 RefPtr<ImageObject> ImageProvider::QueryImageObjectFromCache(
202     const ImageSourceInfo& imageInfo, const RefPtr<PipelineBase>& pipelineContext)
203 {
204     auto imageCache = pipelineContext->GetImageCache();
205     if (!imageCache) {
206         return nullptr;
207     }
208     return imageCache->GetCacheImgObj(imageInfo.ToString(false));
209 }
210 
GeneratorAceImageObject(const ImageSourceInfo & imageInfo,const RefPtr<PipelineBase> context,bool useSkiaSvg)211 RefPtr<ImageObject> ImageProvider::GeneratorAceImageObject(
212     const ImageSourceInfo& imageInfo, const RefPtr<PipelineBase> context, bool useSkiaSvg)
213 {
214     auto imageData = LoadImageRawData(imageInfo, context);
215 
216     if (!imageData) {
217         LOGE("load image data failed. imageInfo: %{private}s", imageInfo.ToString().c_str());
218         return nullptr;
219     }
220     return ImageObject::BuildImageObject(imageInfo, context, imageData, useSkiaSvg);
221 }
222 
223 #ifndef USE_ROSEN_DRAWING
LoadImageRawData(const ImageSourceInfo & imageInfo,const RefPtr<PipelineBase> context)224 sk_sp<SkData> ImageProvider::LoadImageRawData(const ImageSourceInfo& imageInfo, const RefPtr<PipelineBase> context)
225 #else
226 std::shared_ptr<RSData> ImageProvider::LoadImageRawData(
227     const ImageSourceInfo& imageInfo, const RefPtr<PipelineBase> context)
228 #endif
229 {
230     ACE_FUNCTION_TRACE();
231     auto imageCache = context->GetImageCache();
232     if (imageCache) {
233         // 1. try get data from cache.
234         auto cacheData = imageCache->GetCacheImageData(imageInfo.GetSrc());
235         if (cacheData) {
236 #ifndef USE_ROSEN_DRAWING
237             const auto* skData = reinterpret_cast<const sk_sp<SkData>*>(cacheData->GetDataWrapper());
238             return *skData;
239 #else
240             return AceType::DynamicCast<NG::DrawingImageData>(cacheData)->GetRSData();
241 #endif
242         }
243     }
244     // 2. try load raw image file.
245     auto imageLoader = ImageLoader::CreateImageLoader(imageInfo);
246     if (!imageLoader) {
247         LOGE("imageLoader create failed. imageInfo: %{private}s", imageInfo.ToString().c_str());
248         return nullptr;
249     }
250     auto data = imageLoader->LoadImageData(imageInfo, context);
251     if (data && imageCache) {
252 #ifndef USE_ROSEN_DRAWING
253         // cache sk data.
254         imageCache->CacheImageData(imageInfo.GetSrc(), NG::ImageData::MakeFromDataWrapper(&data));
255 #else
256         // cache drawing data.
257         imageCache->CacheImageData(imageInfo.GetSrc(), AceType::MakeRefPtr<NG::DrawingImageData>(data));
258 #endif
259     }
260     return data;
261 }
262 
263 #ifndef USE_ROSEN_DRAWING
LoadImageRawDataFromFileCache(const RefPtr<PipelineBase> context,const std::string key,const std::string suffix)264 sk_sp<SkData> ImageProvider::LoadImageRawDataFromFileCache(
265 #else
266 std::shared_ptr<RSData> ImageProvider::LoadImageRawDataFromFileCache(
267 #endif
268     const RefPtr<PipelineBase> context, const std::string key, const std::string suffix)
269 {
270     ACE_FUNCTION_TRACE();
271     auto data = ImageFileCache::GetInstance().GetDataFromCacheFile(key, suffix);
272     if (data) {
273 #ifndef USE_ROSEN_DRAWING
274         const auto* skData = reinterpret_cast<const sk_sp<SkData>*>(data->GetDataWrapper());
275         return *skData;
276 #else
277         return AceType::DynamicCast<NG::DrawingImageData>(data)->GetRSData();
278 #endif
279     }
280     return nullptr;
281 }
282 
GetSVGImageDOMAsyncFromSrc(const std::string & src,std::function<void (const sk_sp<SkSVGDOM> &)> successCallback,std::function<void ()> failedCallback,const WeakPtr<PipelineBase> context,uint64_t svgThemeColor,OnPostBackgroundTask onBackgroundTaskPostCallback)283 void ImageProvider::GetSVGImageDOMAsyncFromSrc(const std::string& src,
284     std::function<void(const sk_sp<SkSVGDOM>&)> successCallback, std::function<void()> failedCallback,
285     const WeakPtr<PipelineBase> context, uint64_t svgThemeColor, OnPostBackgroundTask onBackgroundTaskPostCallback)
286 {
287     auto task = [src, successCallback, failedCallback, context, svgThemeColor, id = Container::CurrentId()] {
288         ContainerScope scope(id);
289         auto pipelineContext = context.Upgrade();
290         if (!pipelineContext) {
291             LOGW("render image or pipeline has been released.");
292             return;
293         }
294         auto taskExecutor = pipelineContext->GetTaskExecutor();
295         if (!taskExecutor) {
296             return;
297         }
298         ImageSourceInfo info(src);
299         auto imageLoader = ImageLoader::CreateImageLoader(info);
300         if (!imageLoader) {
301             LOGE("load image failed when create image loader.");
302             return;
303         }
304         auto imageData = imageLoader->LoadImageData(info, context);
305         if (imageData) {
306 #ifndef USE_ROSEN_DRAWING
307             const auto svgStream = std::make_unique<SkMemoryStream>(std::move(imageData));
308 #else
309             auto skData = SkData::MakeWithoutCopy(imageData->GetData(), imageData->GetSize());
310             const auto svgStream = std::make_unique<SkMemoryStream>(std::move(skData));
311 #endif
312             if (svgStream) {
313                 auto skiaDom = SkSVGDOM::MakeFromStream(*svgStream, svgThemeColor);
314                 if (skiaDom) {
315                     taskExecutor->PostTask(
316                         [successCallback, skiaDom] { successCallback(skiaDom); },
317                         TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromSrcSuccess");
318                     return;
319                 }
320             }
321         }
322         LOGE("svg data wrong!");
323         taskExecutor->PostTask(
324             [failedCallback] { failedCallback(); }, TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromSrcFailed");
325     };
326     CancelableTask cancelableTask(std::move(task));
327     if (onBackgroundTaskPostCallback) {
328         onBackgroundTaskPostCallback(cancelableTask);
329     }
330     BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
331 }
332 
333 #ifndef USE_ROSEN_DRAWING
GetSVGImageDOMAsyncFromData(const sk_sp<SkData> & skData,std::function<void (const sk_sp<SkSVGDOM> &)> successCallback,std::function<void ()> failedCallback,const WeakPtr<PipelineBase> context,uint64_t svgThemeColor,OnPostBackgroundTask onBackgroundTaskPostCallback)334 void ImageProvider::GetSVGImageDOMAsyncFromData(const sk_sp<SkData>& skData,
335 #else
336 void ImageProvider::GetSVGImageDOMAsyncFromData(const std::shared_ptr<RSData>& data,
337 #endif
338     std::function<void(const sk_sp<SkSVGDOM>&)> successCallback, std::function<void()> failedCallback,
339     const WeakPtr<PipelineBase> context, uint64_t svgThemeColor, OnPostBackgroundTask onBackgroundTaskPostCallback)
340 {
341 #ifndef USE_ROSEN_DRAWING
342     auto task = [skData, successCallback, failedCallback, context, svgThemeColor, id = Container::CurrentId()] {
343 #else
344     auto task = [data, successCallback, failedCallback, context, svgThemeColor, id = Container::CurrentId()] {
345 #endif
346         ContainerScope scope(id);
347         auto pipelineContext = context.Upgrade();
348         if (!pipelineContext) {
349             LOGW("render image or pipeline has been released.");
350             return;
351         }
352         auto taskExecutor = pipelineContext->GetTaskExecutor();
353         if (!taskExecutor) {
354             return;
355         }
356 
357 #ifndef USE_ROSEN_DRAWING
358         const auto svgStream = std::make_unique<SkMemoryStream>(skData);
359 #else
360         auto skData = SkData::MakeWithoutCopy(data->GetData(), data->GetSize());
361         const auto svgStream = std::make_unique<SkMemoryStream>(skData);
362 #endif
363         if (svgStream) {
364             auto skiaDom = SkSVGDOM::MakeFromStream(*svgStream, svgThemeColor);
365             if (skiaDom) {
366                 taskExecutor->PostTask(
367                     [successCallback, skiaDom] { successCallback(skiaDom); },
368                     TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromDataSuccess");
369                 return;
370             }
371         }
372         LOGE("svg data wrong!");
373         taskExecutor->PostTask(
374             [failedCallback] { failedCallback(); }, TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromDataFailed");
375     };
376     CancelableTask cancelableTask(std::move(task));
377     if (onBackgroundTaskPostCallback) {
378         onBackgroundTaskPostCallback(cancelableTask);
379     }
380     BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
381 }
382 
383 #ifndef USE_ROSEN_DRAWING
384 void ImageProvider::UploadImageToGPUForRender(const WeakPtr<PipelineBase> context, const sk_sp<SkImage>& image,
385     const sk_sp<SkData>& data, const std::function<void(sk_sp<SkImage>, sk_sp<SkData>)>&& callback,
386     const std::string src)
387 {
388 #ifdef UPLOAD_GPU_DISABLED
389     // If want to dump draw command or gpu disabled, should use CPU image.
390     callback(image, nullptr);
391 #else
392     if (data && ImageCompressor::GetInstance()->CanCompress()) {
393         LOGI("use astc cache %{private}s %{public}d * %{public}d", src.c_str(), image->width(), image->height());
394         callback(image, data);
395         return;
396     }
397     auto task = [context, image, callback, src]() {
398         ACE_DCHECK(!image->isTextureBacked());
399         bool needRaster = ImageCompressor::GetInstance()->CanCompress();
400         if (!needRaster) {
401             callback(image, nullptr);
402             return;
403         } else {
404             auto rasterizedImage = image->isLazyGenerated() ? image->makeRasterImage() : image;
405             if (!rasterizedImage) {
406                 LOGW("Rasterize image failed. callback.");
407                 callback(image, nullptr);
408                 return;
409             }
410             SkPixmap pixmap;
411             if (!rasterizedImage->peekPixels(&pixmap)) {
412                 LOGW("Could not peek pixels of image for texture upload.");
413                 callback(rasterizedImage, nullptr);
414                 return;
415             }
416             int32_t width = static_cast<int32_t>(pixmap.width());
417             int32_t height = static_cast<int32_t>(pixmap.height());
418             sk_sp<SkData> compressData;
419             if (ImageCompressor::GetInstance()->CanCompress()) {
420                 compressData = ImageCompressor::GetInstance()->GpuCompress(src, pixmap, width, height);
421                 ImageCompressor::GetInstance()->WriteToFile(src, compressData, { width, height });
422                 auto pipelineContext = context.Upgrade();
423                 if (pipelineContext && pipelineContext->GetTaskExecutor()) {
424                     auto taskExecutor = pipelineContext->GetTaskExecutor();
425                     taskExecutor->PostDelayedTask(
426                         ImageCompressor::GetInstance()->ScheduleReleaseTask(), TaskExecutor::TaskType::UI,
427                         ImageCompressor::releaseTimeMs, "ArkUIImageCompressorScheduleRelease");
428                 } else {
429                     BackgroundTaskExecutor::GetInstance().PostTask(
430                         ImageCompressor::GetInstance()->ScheduleReleaseTask());
431                 }
432             }
433             callback(image, compressData);
434             // Trigger purge cpu bitmap resource, after image upload to gpu.
435             SkGraphics::PurgeResourceCache();
436         }
437     };
438     BackgroundTaskExecutor::GetInstance().PostTask(task);
439 #endif
440 }
441 #else
442 void ImageProvider::UploadImageToGPUForRender(const WeakPtr<PipelineBase> context,
443     const std::shared_ptr<RSImage>& image, const std::shared_ptr<RSData>& data,
444     const std::function<void(std::shared_ptr<RSImage>, std::shared_ptr<RSData>)>&& callback, const std::string src)
445 {
446 #ifdef UPLOAD_GPU_DISABLED
447     // If want to dump draw command or gpu disabled, should use CPU image.
448     callback(image, nullptr);
449 #else
450     if (data && ImageCompressor::GetInstance()->CanCompress()) {
451         LOGI("use astc cache %{private}s %{public}d * %{public}d", src.c_str(), image->GetWidth(), image->GetHeight());
452         callback(image, data);
453         return;
454     }
455     auto task = [context, image, callback, src]() {
456         ACE_DCHECK(!image->isTextureBacked());
457         bool needRaster = ImageCompressor::GetInstance()->CanCompress();
458         if (!needRaster) {
459             callback(image, nullptr);
460             return;
461         } else {
462             auto rasterizedImage = image->IsLazyGenerated() ? image->MakeRasterImage() : image;
463             if (!rasterizedImage) {
464                 LOGW("Rasterize image failed. callback.");
465                 callback(image, nullptr);
466                 return;
467             }
468             if (!rasterizedImage->CanPeekPixels()) {
469                 LOGW("Could not peek pixels of image for texture upload.");
470                 callback(rasterizedImage, nullptr);
471                 return;
472             }
473 
474             RSBitmap rsBitmap;
475             RSBitmapFormat rsBitmapFormat { image->GetColorType(), image->GetAlphaType() };
476             rsBitmap.Build(image->GetWidth(), image->GetHeight(), rsBitmapFormat);
477             if (!image->ReadPixels(rsBitmap, 0, 0)) {
478                 callback(image, nullptr);
479                 return;
480             }
481 
482             int32_t width = static_cast<int32_t>(rsBitmap.GetWidth());
483             int32_t height = static_cast<int32_t>(rsBitmap.GetHeight());
484             std::shared_ptr<RSData> compressData;
485             if (ImageCompressor::GetInstance()->CanCompress()) {
486                 compressData = ImageCompressor::GetInstance()->GpuCompress(src, rsBitmap, width, height);
487                 ImageCompressor::GetInstance()->WriteToFile(src, compressData, { width, height });
488                 auto pipelineContext = context.Upgrade();
489                 if (pipelineContext && pipelineContext->GetTaskExecutor()) {
490                     auto taskExecutor = pipelineContext->GetTaskExecutor();
491                     taskExecutor->PostDelayedTask(ImageCompressor::GetInstance()->ScheduleReleaseTask(),
492                         TaskExecutor::TaskType::UI, ImageCompressor::releaseTimeMs,
493                         "ArkUIImageCompressorScheduleRelease");
494                 } else {
495                     BackgroundTaskExecutor::GetInstance().PostTask(
496                         ImageCompressor::GetInstance()->ScheduleReleaseTask());
497                 }
498             }
499             callback(image, compressData);
500             // Trigger purge cpu bitmap resource, after image upload to gpu.
501             Rosen::Drawing::SkiaGraphics::PurgeResourceCache();
502         }
503     };
504     BackgroundTaskExecutor::GetInstance().PostTask(task);
505 #endif
506 }
507 #endif
508 
509 #ifndef USE_ROSEN_DRAWING
510 sk_sp<SkImage> ImageProvider::ResizeSkImage(
511     const sk_sp<SkImage>& rawImage, const std::string& src, Size imageSize, bool forceResize)
512 {
513     if (!imageSize.IsValid()) {
514         LOGE("not valid size!, imageSize: %{private}s, src: %{private}s", imageSize.ToString().c_str(), src.c_str());
515         return rawImage;
516     }
517     int32_t dstWidth = static_cast<int32_t>(imageSize.Width() + 0.5);
518     int32_t dstHeight = static_cast<int32_t>(imageSize.Height() + 0.5);
519 
520     bool needResize = false;
521 
522     if (!forceResize) {
523         if (rawImage->width() > dstWidth) {
524             needResize = true;
525         } else {
526             dstWidth = rawImage->width();
527         }
528         if (rawImage->height() > dstHeight) {
529             needResize = true;
530         } else {
531             dstHeight = rawImage->height();
532         }
533     }
534 
535     if (!needResize && !forceResize) {
536         return rawImage;
537     }
538     return ApplySizeToSkImage(
539         rawImage, dstWidth, dstHeight, ImageObject::GenerateCacheKey(ImageSourceInfo(src), imageSize));
540 }
541 #else
542 std::shared_ptr<RSImage> ImageProvider::ResizeDrawingImage(
543     const std::shared_ptr<RSImage>& rawImage, const std::string& src, Size imageSize, bool forceResize)
544 {
545     if (!imageSize.IsValid()) {
546         LOGE("not valid size!, imageSize: %{private}s, src: %{private}s", imageSize.ToString().c_str(), src.c_str());
547         return rawImage;
548     }
549     int32_t dstWidth = static_cast<int32_t>(imageSize.Width() + 0.5);
550     int32_t dstHeight = static_cast<int32_t>(imageSize.Height() + 0.5);
551 
552     bool needResize = false;
553 
554     if (!forceResize) {
555         if (rawImage->GetWidth() > dstWidth) {
556             needResize = true;
557         } else {
558             dstWidth = rawImage->GetWidth();
559         }
560         if (rawImage->GetHeight() > dstHeight) {
561             needResize = true;
562         } else {
563             dstHeight = rawImage->GetHeight();
564         }
565     }
566 
567     if (!needResize && !forceResize) {
568         return rawImage;
569     }
570     return ApplySizeToDrawingImage(
571         rawImage, dstWidth, dstHeight, ImageObject::GenerateCacheKey(ImageSourceInfo(src), imageSize));
572 }
573 #endif
574 
575 #ifndef USE_ROSEN_DRAWING
576 sk_sp<SkImage> ImageProvider::ApplySizeToSkImage(
577     const sk_sp<SkImage>& rawImage, int32_t dstWidth, int32_t dstHeight, const std::string& srcKey)
578 {
579     ACE_FUNCTION_TRACE();
580     auto scaledImageInfo =
581         SkImageInfo::Make(dstWidth, dstHeight, rawImage->colorType(), rawImage->alphaType(), rawImage->refColorSpace());
582     SkBitmap scaledBitmap;
583     if (!scaledBitmap.tryAllocPixels(scaledImageInfo)) {
584         LOGE("Could not allocate bitmap when attempting to scale. srcKey: %{private}s, destination size: [%{public}d x"
585              " %{public}d], raw image size: [%{public}d x %{public}d]",
586             srcKey.c_str(), dstWidth, dstHeight, rawImage->width(), rawImage->height());
587         return rawImage;
588     }
589     if (!rawImage->scalePixels(scaledBitmap.pixmap(), SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone),
590             SkImage::kDisallow_CachingHint)) {
591         LOGE("Could not scale pixels srcKey: %{private}s, destination size: [%{public}d x"
592              " %{public}d], raw image size: [%{public}d x %{public}d]",
593             srcKey.c_str(), dstWidth, dstHeight, rawImage->width(), rawImage->height());
594         return rawImage;
595     }
596     // Marking this as immutable makes the MakeFromBitmap call share the pixels instead of copying.
597     scaledBitmap.setImmutable();
598     auto scaledImage = SkImage::MakeFromBitmap(scaledBitmap);
599     if (scaledImage) {
600         const double RESIZE_MAX_PROPORTION = ImageCompressor::GetInstance()->CanCompress() ? 1.0 : 0.25;
601         bool needCacheResizedImageFile =
602             (1.0 * dstWidth * dstHeight) / (rawImage->width() * rawImage->height()) < RESIZE_MAX_PROPORTION;
603         auto context = PipelineBase::GetCurrentContext();
604         CHECK_NULL_RETURN(context, scaledImage);
605         // card doesn't encode and cache image file.
606         if (needCacheResizedImageFile && !srcKey.empty() && context && !context->IsFormRender()) {
607             BackgroundTaskExecutor::GetInstance().PostTask(
608                 [srcKey, scaledImage]() {
609                     LOGI("write png cache file: %{private}s", srcKey.c_str());
610                     auto data = scaledImage->encodeToData(SkEncodedImageFormat::kPNG, 100);
611                     if (!data) {
612                         LOGI("encode cache image into cache file failed.");
613                         return;
614                     }
615                     ImageFileCache::GetInstance().WriteCacheFile(srcKey, data->data(), data->size());
616                 },
617                 BgTaskPriority::LOW);
618         }
619         return scaledImage;
620     }
621     LOGE("Could not create a scaled image from a scaled bitmap. srcKey: %{private}s, destination size: [%{public}d x"
622          " %{public}d], raw image size: [%{public}d x %{public}d]",
623         srcKey.c_str(), dstWidth, dstHeight, rawImage->width(), rawImage->height());
624     return rawImage;
625 }
626 #else
627 std::shared_ptr<RSImage> ImageProvider::ApplySizeToDrawingImage(
628     const std::shared_ptr<RSImage>& rawRSImage, int32_t dstWidth, int32_t dstHeight, const std::string& srcKey)
629 {
630     ACE_FUNCTION_TRACE();
631     RSImageInfo scaledImageInfo { dstWidth, dstHeight,
632         rawRSImage->GetColorType(), rawRSImage->GetAlphaType(), rawRSImage->GetColorSpace() };
633     RSBitmap scaledBitmap;
634     if (!scaledBitmap.TryAllocPixels(scaledImageInfo)) {
635         LOGE("Could not allocate bitmap when attempting to scale. srcKey: %{private}s, destination size: [%{public}d x"
636              " %{public}d], raw image size: [%{public}d x %{public}d]",
637             srcKey.c_str(), dstWidth, dstHeight, rawRSImage->GetWidth(), rawRSImage->GetHeight());
638         return rawRSImage;
639     }
640     if (!rawRSImage->ScalePixels(scaledBitmap, RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::NONE), false)) {
641         LOGE("Could not scale pixels srcKey: %{private}s, destination size: [%{public}d x"
642              " %{public}d], raw image size: [%{public}d x %{public}d]",
643             srcKey.c_str(), dstWidth, dstHeight, rawRSImage->GetWidth(), rawRSImage->GetHeight());
644         return rawRSImage;
645     }
646     // Marking this as immutable makes the MakeFromBitmap call share the pixels instead of copying.
647     scaledBitmap.SetImmutable();
648     std::shared_ptr<RSImage> scaledImage = std::make_shared<RSImage>();
649     if (scaledImage->BuildFromBitmap(scaledBitmap)) {
650         const double RESIZE_MAX_PROPORTION = ImageCompressor::GetInstance()->CanCompress() ? 1.0 : 0.25;
651         bool needCacheResizedImageFile =
652             (1.0 * dstWidth * dstHeight) / (rawRSImage->GetWidth() * rawRSImage->GetHeight()) < RESIZE_MAX_PROPORTION;
653         auto context = PipelineBase::GetCurrentContext();
654         // card doesn't encode and cache image file.
655         if (needCacheResizedImageFile && !srcKey.empty() && context && !context->IsFormRender()) {
656             BackgroundTaskExecutor::GetInstance().PostTask(
657                 [srcKey, scaledImage]() {
658                     LOGI("write png cache file: %{private}s", srcKey.c_str());
659                     auto data = scaledImage->EncodeToData(RSEncodedImageFormat::PNG, 100);
660                     if (!data) {
661                         return;
662                     }
663                     RSDataWrapper* wrapper = new RSDataWrapper{data};
664                     auto skData = SkData::MakeWithProc(data->GetData(), data->GetSize(),
665                         RSDataWrapperReleaseProc, wrapper);
666                     if (!skData) {
667                         LOGI("encode cache image into cache file failed.");
668                         return;
669                     }
670                     ImageFileCache::GetInstance().WriteCacheFile(srcKey, skData->data(), skData->size());
671                 },
672                 BgTaskPriority::LOW);
673         }
674         return scaledImage;
675     }
676     LOGE("Could not create a scaled image from a scaled bitmap. srcKey: %{private}s, destination size: [%{public}d x"
677          " %{public}d], raw image size: [%{public}d x %{public}d]",
678         srcKey.c_str(), dstWidth, dstHeight, rawRSImage->GetWidth(), rawRSImage->GetHeight());
679     return rawRSImage;
680 }
681 #endif
682 
683 #ifndef USE_ROSEN_DRAWING
684 sk_sp<SkImage> ImageProvider::GetSkImage(const std::string& src, const WeakPtr<PipelineBase> context, Size targetSize)
685 {
686     ImageSourceInfo info(src);
687     auto imageLoader = ImageLoader::CreateImageLoader(info);
688     if (!imageLoader) {
689         LOGE("Invalid src, src is %{private}s", src.c_str());
690         return nullptr;
691     }
692     auto imageSkData = imageLoader->LoadImageData(info, context);
693     if (!imageSkData) {
694         LOGE("fetch data failed. src: %{private}s", src.c_str());
695         return nullptr;
696     }
697     auto rawImage = SkImage::MakeFromEncoded(imageSkData);
698     if (!rawImage) {
699         LOGE("MakeFromEncoded failed! src: %{private}s", src.c_str());
700         return nullptr;
701     }
702     auto image = ResizeSkImage(rawImage, src, targetSize);
703     return image;
704 }
705 #else
706 std::shared_ptr<RSImage> ImageProvider::GetDrawingImage(
707     const std::string& src, const WeakPtr<PipelineBase> context, Size targetSize)
708 {
709     ImageSourceInfo info(src);
710     auto imageLoader = ImageLoader::CreateImageLoader(info);
711     if (!imageLoader) {
712         LOGE("Invalid src, src is %{private}s", src.c_str());
713         return nullptr;
714     }
715     auto imageData = imageLoader->LoadImageData(info, context);
716     if (!imageData) {
717         LOGE("fetch data failed. src: %{private}s", src.c_str());
718         return nullptr;
719     }
720     std::shared_ptr<RSImage> rawImage = std::make_shared<RSImage>();
721     if (!rawImage->MakeFromEncoded(imageData)) {
722         LOGE("MakeFromEncoded failed! src: %{private}s", src.c_str());
723         return nullptr;
724     }
725     auto image = ResizeDrawingImage(rawImage, src, targetSize);
726     return image;
727 }
728 #endif
729 
730 void ImageProvider::TryLoadImageInfo(const RefPtr<PipelineBase>& context, const std::string& src,
731     std::function<void(bool, int32_t, int32_t)>&& loadCallback)
732 {
733     BackgroundTaskExecutor::GetInstance().PostTask(
734         [src, callback = std::move(loadCallback), context, id = Container::CurrentId()]() {
735             ContainerScope scope(id);
736             auto taskExecutor = context->GetTaskExecutor();
737             if (!taskExecutor) {
738                 return;
739             }
740 #ifndef USE_ROSEN_DRAWING
741             auto image = ImageProvider::GetSkImage(src, context);
742             if (image) {
743                 callback(true, image->width(), image->height());
744                 return;
745             }
746 #else
747             auto image = ImageProvider::GetDrawingImage(src, context);
748             if (image) {
749                 callback(true, image->GetWidth(), image->GetHeight());
750                 return;
751             }
752 #endif
753             callback(false, 0, 0);
754         });
755 }
756 
757 bool ImageProvider::IsWideGamut(const std::shared_ptr<RSColorSpace>& rsColorSpace)
758 {
759     if (!rsColorSpace) {
760         return false;
761     }
762     // Normalize gamut by 1.
763     // rgb[3] represents the point of Red, Green and Blue coordinate in color space diagram.
764     Point rgb[3];
765     bool hasToXYZD50 = true;
766     auto xyzGamut = rsColorSpace->ToXYZD50(hasToXYZD50);
767     if (!hasToXYZD50) {
768         return false;
769     }
770     for (int32_t i = 0; i < 3; i++) {
771         auto sum = xyzGamut.vals[i][0] + xyzGamut.vals[i][1] + xyzGamut.vals[i][2];
772         rgb[i].SetX(xyzGamut.vals[i][0] / sum);
773         rgb[i].SetY(xyzGamut.vals[i][1] / sum);
774     }
775     // Calculate the area enclosed by the coordinates of the three RGB points
776     Point red = rgb[0];
777     Point green = rgb[1];
778     Point blue = rgb[2];
779     // Assuming there is a triangle enclosed by three points: A(x1, y1), B(x2, y2), C(x3, y3),
780     // the formula for calculating the area of triangle ABC is as follows:
781     // S = (x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2) / 2.0
782     auto areaOfPoint = std::fabs(red.GetX() * green.GetY() + green.GetX() * blue.GetY() + blue.GetX() * green.GetY() -
783                                  red.GetX() * blue.GetY() - blue.GetX() * green.GetY() - green.GetX() * red.GetY()) /
784                        2.0;
785     return GreatNotEqual(areaOfPoint, SRGB_GAMUT_AREA);
786 }
787 
788 #ifndef USE_ROSEN_DRAWING
789 SkImageInfo ImageProvider::MakeSkImageInfoFromPixelMap(const RefPtr<PixelMap>& pixmap)
790 {
791     SkColorType ct = PixelFormatToSkColorType(pixmap);
792     SkAlphaType at = AlphaTypeToSkAlphaType(pixmap);
793     sk_sp<SkColorSpace> cs = ColorSpaceToSkColorSpace(pixmap);
794     return SkImageInfo::Make(pixmap->GetWidth(), pixmap->GetHeight(), ct, at, cs);
795 }
796 #else
797 RSBitmapFormat ImageProvider::MakeRSBitmapFormatFromPixelMap(const RefPtr<PixelMap>& pixmap)
798 {
799     return { PixelFormatToDrawingColorType(pixmap), AlphaTypeToDrawingAlphaType(pixmap) };
800 }
801 RSImageInfo ImageProvider::MakeRSImageInfoFromPixelMap(const RefPtr<PixelMap>& pixmap)
802 {
803     RSColorType ct = PixelFormatToDrawingColorType(pixmap);
804     RSAlphaType at = AlphaTypeToDrawingAlphaType(pixmap);
805     std::shared_ptr<RSColorSpace> cs = ColorSpaceToDrawingColorSpace(pixmap);
806     return { pixmap->GetWidth(), pixmap->GetHeight(), ct, at, cs };
807 }
808 #endif
809 
810 #ifndef USE_ROSEN_DRAWING
811 sk_sp<SkColorSpace> ImageProvider::ColorSpaceToSkColorSpace(const RefPtr<PixelMap>& pixmap)
812 {
813     return SkColorSpace::MakeSRGB(); // Media::PixelMap has not support wide gamut yet.
814 }
815 #else
816 std::shared_ptr<RSColorSpace> ImageProvider::ColorSpaceToDrawingColorSpace(const RefPtr<PixelMap>& pixmap)
817 {
818     return RSColorSpace::CreateSRGB(); // Media::PixelMap has not support wide gamut yet.
819 }
820 #endif
821 
822 #ifndef USE_ROSEN_DRAWING
823 SkAlphaType ImageProvider::AlphaTypeToSkAlphaType(const RefPtr<PixelMap>& pixmap)
824 {
825     switch (pixmap->GetAlphaType()) {
826         case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
827             return SkAlphaType::kUnknown_SkAlphaType;
828         case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
829             return SkAlphaType::kOpaque_SkAlphaType;
830         case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
831             return SkAlphaType::kPremul_SkAlphaType;
832         case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
833             return SkAlphaType::kUnpremul_SkAlphaType;
834         default:
835             return SkAlphaType::kUnknown_SkAlphaType;
836     }
837 }
838 #else
839 RSAlphaType ImageProvider::AlphaTypeToDrawingAlphaType(const RefPtr<PixelMap>& pixmap)
840 {
841     switch (pixmap->GetAlphaType()) {
842         case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
843             return RSAlphaType::ALPHATYPE_UNKNOWN;
844         case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
845             return RSAlphaType::ALPHATYPE_OPAQUE;
846         case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
847             return RSAlphaType::ALPHATYPE_PREMUL;
848         case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
849             return RSAlphaType::ALPHATYPE_UNPREMUL;
850         default:
851             return RSAlphaType::ALPHATYPE_UNKNOWN;
852     }
853 }
854 #endif
855 
856 #ifndef USE_ROSEN_DRAWING
857 SkColorType ImageProvider::PixelFormatToSkColorType(const RefPtr<PixelMap>& pixmap)
858 {
859     switch (pixmap->GetPixelFormat()) {
860         case PixelFormat::RGB_565:
861             return SkColorType::kRGB_565_SkColorType;
862         case PixelFormat::RGBA_8888:
863             return SkColorType::kRGBA_8888_SkColorType;
864         case PixelFormat::BGRA_8888:
865             return SkColorType::kBGRA_8888_SkColorType;
866         case PixelFormat::ALPHA_8:
867             return SkColorType::kAlpha_8_SkColorType;
868         case PixelFormat::RGBA_F16:
869             return SkColorType::kRGBA_F16_SkColorType;
870         case PixelFormat::UNKNOWN:
871         case PixelFormat::ARGB_8888:
872         case PixelFormat::RGB_888:
873         case PixelFormat::NV21:
874         case PixelFormat::NV12:
875         case PixelFormat::CMYK:
876         default:
877             return SkColorType::kUnknown_SkColorType;
878     }
879 }
880 #else
881 RSColorType ImageProvider::PixelFormatToDrawingColorType(const RefPtr<PixelMap>& pixmap)
882 {
883     switch (pixmap->GetPixelFormat()) {
884         case PixelFormat::RGB_565:
885             return RSColorType::COLORTYPE_RGB_565;
886         case PixelFormat::RGBA_8888:
887             return RSColorType::COLORTYPE_RGBA_8888;
888         case PixelFormat::RGBA_1010102:
889             return RSColorType::COLORTYPE_RGBA_1010102;
890         case PixelFormat::BGRA_8888:
891             return RSColorType::COLORTYPE_BGRA_8888;
892         case PixelFormat::ALPHA_8:
893             return RSColorType::COLORTYPE_ALPHA_8;
894         case PixelFormat::RGBA_F16:
895             return RSColorType::COLORTYPE_RGBA_F16;
896         case PixelFormat::UNKNOWN:
897         case PixelFormat::ARGB_8888:
898         case PixelFormat::RGB_888:
899         case PixelFormat::NV21:
900         case PixelFormat::NV12:
901         case PixelFormat::CMYK:
902         default:
903             return RSColorType::COLORTYPE_UNKNOWN;
904     }
905 }
906 #endif
907 
908 } // namespace OHOS::Ace
909