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