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