• 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 #include "drawing/engine_adapter/skia_adapter/skia_data.h"
21 #include "drawing/engine_adapter/skia_adapter/skia_image.h"
22 #include "drawing/engine_adapter/skia_adapter/skia_graphics.h"
23 
24 #include "base/thread/background_task_executor.h"
25 #include "core/common/container.h"
26 #include "core/components_ng/image_provider/drawing_image_data.h"
27 #include "core/components_ng/render/adapter/drawing_image.h"
28 #include "core/image/image_file_cache.h"
29 #include "core/image/image_object.h"
30 
31 namespace OHOS::Ace {
32 namespace {
33 
34 // If a picture is a wide color gamut picture, its area value will be larger than this threshold.
35 constexpr double SRGB_GAMUT_AREA = 0.104149;
36 } // namespace
37 
38 std::mutex ImageProvider::loadingImageMutex_;
39 std::unordered_map<std::string, std::vector<LoadCallback>> ImageProvider::loadingImage_;
40 
41 std::mutex ImageProvider::uploadMutex_;
42 std::unordered_map<std::string, std::vector<LoadCallback>> ImageProvider::uploadingImage_;
43 
TrySetLoadingImage(const ImageSourceInfo & imageInfo,const ImageObjSuccessCallback & successCallback,const UploadSuccessCallback & uploadCallback,const FailedCallback & failedCallback)44 bool ImageProvider::TrySetLoadingImage(const ImageSourceInfo& imageInfo, const ImageObjSuccessCallback& successCallback,
45     const UploadSuccessCallback& uploadCallback, const FailedCallback& failedCallback)
46 {
47     std::lock_guard lock(loadingImageMutex_);
48     auto key = imageInfo.GetKey();
49     auto iter = loadingImage_.find(key);
50     if (iter == loadingImage_.end()) {
51         std::vector<LoadCallback> callbacks { { successCallback, uploadCallback, failedCallback } };
52         loadingImage_.emplace(key, callbacks);
53         return true;
54     } else {
55         LOGI("other thread is loading same image: %{private}s", imageInfo.ToString().c_str());
56         iter->second.emplace_back(successCallback, uploadCallback, failedCallback);
57         return false;
58     }
59 }
60 
ProccessLoadingResult(const RefPtr<TaskExecutor> & taskExecutor,const ImageSourceInfo & imageInfo,bool canStartUploadImageObj,const RefPtr<ImageObject> & imageObj,const RefPtr<PipelineBase> & context,const std::string & errorMsg)61 void ImageProvider::ProccessLoadingResult(const RefPtr<TaskExecutor>& taskExecutor, const ImageSourceInfo& imageInfo,
62     bool canStartUploadImageObj, const RefPtr<ImageObject>& imageObj, const RefPtr<PipelineBase>& context,
63     const std::string& errorMsg)
64 {
65     std::lock_guard lock(loadingImageMutex_);
66     std::vector<LoadCallback> callbacks;
67     auto key = imageInfo.GetKey();
68     auto iter = loadingImage_.find(key);
69     if (iter != loadingImage_.end()) {
70         std::swap(callbacks, iter->second);
71         for (const auto& callback : callbacks) {
72             if (imageObj == nullptr) {
73                 taskExecutor->PostTask(
74                     [imageInfo, callback, errorMsg]() {
75                         if (callback.failedCallback) {
76                             callback.failedCallback(imageInfo, errorMsg);
77                         }
78                     },
79                     TaskExecutor::TaskType::UI, "ArkUIImageProviderLoadFailed");
80                 return;
81             }
82             auto obj = imageObj->Clone();
83             taskExecutor->PostTask(
84                 [obj, imageInfo, callback]() {
85                     if (callback.successCallback) {
86                         callback.successCallback(imageInfo, obj);
87                     }
88                 },
89                 TaskExecutor::TaskType::UI, "ArkUIImageProviderLoadSuccess");
90             if (canStartUploadImageObj) {
91                 bool forceResize = (!obj->IsSvg()) && (imageInfo.IsSourceDimensionValid());
92                 obj->UploadToGpuForRender(
93                     context, callback.uploadCallback, callback.failedCallback, obj->GetImageSize(), forceResize, true);
94             }
95         }
96     } else {
97         LOGW("no loading image: %{private}s", imageInfo.ToString().c_str());
98     }
99     loadingImage_.erase(key);
100 }
101 
TryUploadingImage(const std::string & key,const UploadSuccessCallback & successCallback,const FailedCallback & failedCallback)102 bool ImageProvider::TryUploadingImage(
103     const std::string& key, const UploadSuccessCallback& successCallback, const FailedCallback& failedCallback)
104 {
105     std::lock_guard lock(uploadMutex_);
106     auto iter = uploadingImage_.find(key);
107     if (iter == uploadingImage_.end()) {
108         std::vector<LoadCallback> callbacks = { { nullptr, successCallback, failedCallback } };
109         uploadingImage_.emplace(key, callbacks);
110         return true;
111     } else {
112         iter->second.emplace_back(nullptr, successCallback, failedCallback);
113         return false;
114     }
115 }
116 
ProccessUploadResult(const RefPtr<TaskExecutor> & taskExecutor,const ImageSourceInfo & imageInfo,const Size & imageSize,const RefPtr<NG::CanvasImage> & canvasImage,const std::string & errorMsg)117 void ImageProvider::ProccessUploadResult(const RefPtr<TaskExecutor>& taskExecutor, const ImageSourceInfo& imageInfo,
118     const Size& imageSize, const RefPtr<NG::CanvasImage>& canvasImage, const std::string& errorMsg)
119 {
120     std::lock_guard lock(uploadMutex_);
121     std::vector<LoadCallback> callbacks;
122     auto key = ImageObject::GenerateCacheKey(imageInfo, imageSize);
123     auto iter = uploadingImage_.find(key);
124     if (iter != uploadingImage_.end()) {
125         std::swap(callbacks, iter->second);
126         taskExecutor->PostTask(
127             [callbacks, imageInfo, canvasImage, errorMsg]() {
128                 for (auto callback : callbacks) {
129                     if (canvasImage) {
130                         callback.uploadCallback(imageInfo, canvasImage);
131                     } else {
132                         callback.failedCallback(imageInfo, errorMsg);
133                     }
134                 }
135             },
136             TaskExecutor::TaskType::UI, "ArkUIImageProviderUploadResult");
137     } else {
138         LOGW("no uploading image: %{private}s", imageInfo.ToString().c_str());
139     }
140     uploadingImage_.erase(key);
141 }
142 
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)143 void ImageProvider::FetchImageObject(const ImageSourceInfo& imageInfo, const ImageObjSuccessCallback& successCallback,
144     const UploadSuccessCallback& uploadSuccessCallback, const FailedCallback& failedCallback,
145     const WeakPtr<PipelineBase>& context, bool syncMode, bool useSkiaSvg, bool needAutoResize,
146     const OnPostBackgroundTask& onBackgroundTaskPostCallback)
147 {
148     auto task = [context, imageInfo, successCallback, failedCallback, useSkiaSvg, uploadSuccessCallback, needAutoResize,
149                     id = Container::CurrentId(), syncMode]() mutable {
150         ContainerScope scope(id);
151         auto pipelineContext = context.Upgrade();
152         if (!pipelineContext) {
153             LOGE("pipeline context has been released. imageInfo: %{private}s", imageInfo.ToString().c_str());
154             return;
155         }
156         auto taskExecutor = pipelineContext->GetTaskExecutor();
157         if (!taskExecutor) {
158             LOGE("task executor is null. imageInfo: %{private}s", imageInfo.ToString().c_str());
159             return;
160         }
161         if (!syncMode && !TrySetLoadingImage(imageInfo, successCallback, uploadSuccessCallback, failedCallback)) {
162             LOGI("same source is loading: %{private}s", imageInfo.ToString().c_str());
163             return;
164         }
165         RefPtr<ImageObject> imageObj = QueryImageObjectFromCache(imageInfo, pipelineContext);
166         if (!imageObj) { // if image object is not in cache, generate a new one.
167             imageObj = GeneratorAceImageObject(imageInfo, pipelineContext, useSkiaSvg);
168         }
169         if (!imageObj) { // if it fails to generate an image object, trigger fail callback.
170             if (syncMode) {
171                 failedCallback(
172                     imageInfo, "Image data may be broken or absent, please check if image file or image data is valid");
173                 return;
174             }
175             ProccessLoadingResult(taskExecutor, imageInfo, false, nullptr, pipelineContext,
176                 "Image data may be broken or absent, please check if image file or image data is valid.");
177             return;
178         }
179         if (syncMode) {
180             successCallback(imageInfo, imageObj);
181         } else {
182             ProccessLoadingResult(taskExecutor, imageInfo, !needAutoResize && (imageObj->GetFrameCount() == 1),
183                 imageObj, pipelineContext);
184         }
185     };
186     if (syncMode) {
187         task();
188         return;
189     }
190     CancelableTask cancelableTask(std::move(task));
191     if (onBackgroundTaskPostCallback) {
192         onBackgroundTaskPostCallback(cancelableTask);
193     }
194     BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
195 }
196 
QueryImageObjectFromCache(const ImageSourceInfo & imageInfo,const RefPtr<PipelineBase> & pipelineContext)197 RefPtr<ImageObject> ImageProvider::QueryImageObjectFromCache(
198     const ImageSourceInfo& imageInfo, const RefPtr<PipelineBase>& pipelineContext)
199 {
200     auto imageCache = pipelineContext->GetImageCache();
201     if (!imageCache) {
202         return nullptr;
203     }
204     return imageCache->GetCacheImgObj(imageInfo.ToString(false));
205 }
206 
GeneratorAceImageObject(const ImageSourceInfo & imageInfo,const RefPtr<PipelineBase> context,bool useSkiaSvg)207 RefPtr<ImageObject> ImageProvider::GeneratorAceImageObject(
208     const ImageSourceInfo& imageInfo, const RefPtr<PipelineBase> context, bool useSkiaSvg)
209 {
210     auto imageData = LoadImageRawData(imageInfo, context);
211 
212     if (!imageData) {
213         LOGE("load image data failed. imageInfo: %{private}s", imageInfo.ToString().c_str());
214         return nullptr;
215     }
216     return ImageObject::BuildImageObject(imageInfo, context, imageData, useSkiaSvg);
217 }
218 
LoadImageRawData(const ImageSourceInfo & imageInfo,const RefPtr<PipelineBase> context)219 std::shared_ptr<RSData> ImageProvider::LoadImageRawData(
220     const ImageSourceInfo& imageInfo, const RefPtr<PipelineBase> context)
221 {
222     ACE_FUNCTION_TRACE();
223     auto imageCache = context->GetImageCache();
224     if (imageCache) {
225         // 1. try get data from cache.
226         auto cacheData = imageCache->GetCacheImageData(imageInfo.GetSrc());
227         if (cacheData) {
228             return AceType::DynamicCast<NG::DrawingImageData>(cacheData)->GetRSData();
229         }
230     }
231     // 2. try load raw image file.
232     auto imageLoader = ImageLoader::CreateImageLoader(imageInfo);
233     if (!imageLoader) {
234         LOGE("imageLoader create failed. imageInfo: %{private}s", imageInfo.ToString().c_str());
235         return nullptr;
236     }
237     NG::ImageLoadResultInfo errorInfo;
238     auto data = imageLoader->LoadImageData(imageInfo, errorInfo, context);
239     if (data && imageCache) {
240         // cache drawing data.
241         imageCache->CacheImageData(imageInfo.GetSrc(), AceType::MakeRefPtr<NG::DrawingImageData>(data));
242     }
243     return data;
244 }
245 
LoadImageRawDataFromFileCache(const RefPtr<PipelineBase> context,const std::string key,const std::string suffix)246 std::shared_ptr<RSData> ImageProvider::LoadImageRawDataFromFileCache(
247     const RefPtr<PipelineBase> context, const std::string key, const std::string suffix)
248 {
249     ACE_FUNCTION_TRACE();
250     auto data = ImageFileCache::GetInstance().GetDataFromCacheFile(key, suffix);
251     if (data) {
252         return AceType::DynamicCast<NG::DrawingImageData>(data)->GetRSData();
253     }
254     return nullptr;
255 }
256 
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)257 void ImageProvider::GetSVGImageDOMAsyncFromSrc(const std::string& src,
258     std::function<void(const sk_sp<SkSVGDOM>&)> successCallback, std::function<void()> failedCallback,
259     const WeakPtr<PipelineBase> context, uint64_t svgThemeColor, OnPostBackgroundTask onBackgroundTaskPostCallback)
260 {
261     auto task = [src, successCallback, failedCallback, context, svgThemeColor, id = Container::CurrentId()] {
262         ContainerScope scope(id);
263         auto pipelineContext = context.Upgrade();
264         if (!pipelineContext) {
265             LOGW("render image or pipeline has been released.");
266             return;
267         }
268         auto taskExecutor = pipelineContext->GetTaskExecutor();
269         if (!taskExecutor) {
270             return;
271         }
272         ImageSourceInfo info(src);
273         auto imageLoader = ImageLoader::CreateImageLoader(info);
274         if (!imageLoader) {
275             LOGE("load image failed when create image loader.");
276             return;
277         }
278         NG::ImageLoadResultInfo errorInfo;
279         auto imageData = imageLoader->LoadImageData(info, errorInfo, context);
280         if (imageData) {
281             auto skData = SkData::MakeWithoutCopy(imageData->GetData(), imageData->GetSize());
282             const auto svgStream = std::make_unique<SkMemoryStream>(std::move(skData));
283             if (svgStream) {
284                 auto skiaDom = SkSVGDOM::MakeFromStream(*svgStream, svgThemeColor);
285                 if (skiaDom) {
286                     taskExecutor->PostTask(
287                         [successCallback, skiaDom] { successCallback(skiaDom); },
288                         TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromSrcSuccess");
289                     return;
290                 }
291             }
292         }
293         LOGE("svg data wrong!");
294         taskExecutor->PostTask(
295             [failedCallback] { failedCallback(); }, TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromSrcFailed");
296     };
297     CancelableTask cancelableTask(std::move(task));
298     if (onBackgroundTaskPostCallback) {
299         onBackgroundTaskPostCallback(cancelableTask);
300     }
301     BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
302 }
303 
GetSVGImageDOMAsyncFromData(const std::shared_ptr<RSData> & data,std::function<void (const sk_sp<SkSVGDOM> &)> successCallback,std::function<void ()> failedCallback,const WeakPtr<PipelineBase> context,uint64_t svgThemeColor,OnPostBackgroundTask onBackgroundTaskPostCallback)304 void ImageProvider::GetSVGImageDOMAsyncFromData(const std::shared_ptr<RSData>& data,
305     std::function<void(const sk_sp<SkSVGDOM>&)> successCallback, std::function<void()> failedCallback,
306     const WeakPtr<PipelineBase> context, uint64_t svgThemeColor, OnPostBackgroundTask onBackgroundTaskPostCallback)
307 {
308     auto task = [data, successCallback, failedCallback, context, svgThemeColor, id = Container::CurrentId()] {
309         ContainerScope scope(id);
310         auto pipelineContext = context.Upgrade();
311         if (!pipelineContext) {
312             LOGW("render image or pipeline has been released.");
313             return;
314         }
315         auto taskExecutor = pipelineContext->GetTaskExecutor();
316         if (!taskExecutor) {
317             return;
318         }
319 
320         auto skData = SkData::MakeWithoutCopy(data->GetData(), data->GetSize());
321         const auto svgStream = std::make_unique<SkMemoryStream>(skData);
322         if (svgStream) {
323             auto skiaDom = SkSVGDOM::MakeFromStream(*svgStream, svgThemeColor);
324             if (skiaDom) {
325                 taskExecutor->PostTask(
326                     [successCallback, skiaDom] { successCallback(skiaDom); },
327                     TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromDataSuccess");
328                 return;
329             }
330         }
331         LOGE("svg data wrong!");
332         taskExecutor->PostTask(
333             [failedCallback] { failedCallback(); }, TaskExecutor::TaskType::UI, "ArkUIImageGetSvgDomFromDataFailed");
334     };
335     CancelableTask cancelableTask(std::move(task));
336     if (onBackgroundTaskPostCallback) {
337         onBackgroundTaskPostCallback(cancelableTask);
338     }
339     BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
340 }
341 
UploadImageToGPUForRender(const WeakPtr<PipelineBase> context,const std::shared_ptr<RSImage> & image,const std::shared_ptr<RSData> & data,const std::function<void (std::shared_ptr<RSImage>,std::shared_ptr<RSData>)> && callback,const std::string src)342 void ImageProvider::UploadImageToGPUForRender(const WeakPtr<PipelineBase> context,
343     const std::shared_ptr<RSImage>& image, const std::shared_ptr<RSData>& data,
344     const std::function<void(std::shared_ptr<RSImage>, std::shared_ptr<RSData>)>&& callback, const std::string src)
345 {
346 #ifdef UPLOAD_GPU_DISABLED
347     // If want to dump draw command or gpu disabled, should use CPU image.
348     callback(image, nullptr);
349 #else
350     if (data && ImageCompressor::GetInstance()->CanCompress()) {
351         LOGI("use astc cache %{private}s %{public}d * %{public}d", src.c_str(), image->GetWidth(), image->GetHeight());
352         callback(image, data);
353         return;
354     }
355     auto task = [context, image, callback, src]() {
356         ACE_DCHECK(!image->isTextureBacked());
357         bool needRaster = ImageCompressor::GetInstance()->CanCompress();
358         if (!needRaster) {
359             callback(image, nullptr);
360             return;
361         } else {
362             auto rasterizedImage = image->IsLazyGenerated() ? image->MakeRasterImage() : image;
363             if (!rasterizedImage) {
364                 LOGW("Rasterize image failed. callback.");
365                 callback(image, nullptr);
366                 return;
367             }
368             if (!rasterizedImage->CanPeekPixels()) {
369                 LOGW("Could not peek pixels of image for texture upload.");
370                 callback(rasterizedImage, nullptr);
371                 return;
372             }
373 
374             RSBitmap rsBitmap;
375             RSBitmapFormat rsBitmapFormat { image->GetColorType(), image->GetAlphaType() };
376             rsBitmap.Build(image->GetWidth(), image->GetHeight(), rsBitmapFormat);
377             if (!image->ReadPixels(rsBitmap, 0, 0)) {
378                 callback(image, nullptr);
379                 return;
380             }
381 
382             int32_t width = static_cast<int32_t>(rsBitmap.GetWidth());
383             int32_t height = static_cast<int32_t>(rsBitmap.GetHeight());
384             std::shared_ptr<RSData> compressData;
385             if (ImageCompressor::GetInstance()->CanCompress()) {
386                 compressData = ImageCompressor::GetInstance()->GpuCompress(src, rsBitmap, width, height);
387                 ImageCompressor::GetInstance()->WriteToFile(src, compressData, { width, height });
388                 auto pipelineContext = context.Upgrade();
389                 if (pipelineContext && pipelineContext->GetTaskExecutor()) {
390                     auto taskExecutor = pipelineContext->GetTaskExecutor();
391                     taskExecutor->PostDelayedTask(ImageCompressor::GetInstance()->ScheduleReleaseTask(),
392                         TaskExecutor::TaskType::UI, ImageCompressor::releaseTimeMs,
393                         "ArkUIImageCompressorScheduleRelease");
394                 } else {
395                     BackgroundTaskExecutor::GetInstance().PostTask(
396                         ImageCompressor::GetInstance()->ScheduleReleaseTask());
397                 }
398             }
399             callback(image, compressData);
400             // Trigger purge cpu bitmap resource, after image upload to gpu.
401             Rosen::Drawing::SkiaGraphics::PurgeResourceCache();
402         }
403     };
404     BackgroundTaskExecutor::GetInstance().PostTask(task);
405 #endif
406 }
407 
ResizeDrawingImage(const std::shared_ptr<RSImage> & rawImage,const std::string & src,Size imageSize,bool forceResize)408 std::shared_ptr<RSImage> ImageProvider::ResizeDrawingImage(
409     const std::shared_ptr<RSImage>& rawImage, const std::string& src, Size imageSize, bool forceResize)
410 {
411     if (!imageSize.IsValid()) {
412         LOGE("not valid size!, imageSize: %{private}s, src: %{private}s", imageSize.ToString().c_str(), src.c_str());
413         return rawImage;
414     }
415     int32_t dstWidth = static_cast<int32_t>(imageSize.Width() + 0.5);
416     int32_t dstHeight = static_cast<int32_t>(imageSize.Height() + 0.5);
417 
418     bool needResize = false;
419 
420     if (!forceResize) {
421         if (rawImage->GetWidth() > dstWidth) {
422             needResize = true;
423         } else {
424             dstWidth = rawImage->GetWidth();
425         }
426         if (rawImage->GetHeight() > dstHeight) {
427             needResize = true;
428         } else {
429             dstHeight = rawImage->GetHeight();
430         }
431     }
432 
433     if (!needResize && !forceResize) {
434         return rawImage;
435     }
436     return ApplySizeToDrawingImage(
437         rawImage, dstWidth, dstHeight, ImageObject::GenerateCacheKey(ImageSourceInfo(src), imageSize));
438 }
439 
ApplySizeToDrawingImage(const std::shared_ptr<RSImage> & rawRSImage,int32_t dstWidth,int32_t dstHeight,const std::string & srcKey)440 std::shared_ptr<RSImage> ImageProvider::ApplySizeToDrawingImage(
441     const std::shared_ptr<RSImage>& rawRSImage, int32_t dstWidth, int32_t dstHeight, const std::string& srcKey)
442 {
443     ACE_FUNCTION_TRACE();
444     RSImageInfo scaledImageInfo { dstWidth, dstHeight,
445         rawRSImage->GetColorType(), rawRSImage->GetAlphaType(), rawRSImage->GetColorSpace() };
446     RSBitmap scaledBitmap;
447     if (!scaledBitmap.TryAllocPixels(scaledImageInfo)) {
448         LOGE("Could not allocate bitmap when attempting to scale. srcKey: %{private}s, destination size: [%{public}d x"
449              " %{public}d], raw image size: [%{public}d x %{public}d]",
450             srcKey.c_str(), dstWidth, dstHeight, rawRSImage->GetWidth(), rawRSImage->GetHeight());
451         return rawRSImage;
452     }
453     if (!rawRSImage->ScalePixels(scaledBitmap, RSSamplingOptions(RSFilterMode::LINEAR, RSMipmapMode::NONE), false)) {
454         LOGE("Could not scale pixels srcKey: %{private}s, destination size: [%{public}d x"
455              " %{public}d], raw image size: [%{public}d x %{public}d]",
456             srcKey.c_str(), dstWidth, dstHeight, rawRSImage->GetWidth(), rawRSImage->GetHeight());
457         return rawRSImage;
458     }
459     // Marking this as immutable makes the MakeFromBitmap call share the pixels instead of copying.
460     scaledBitmap.SetImmutable();
461     std::shared_ptr<RSImage> scaledImage = std::make_shared<RSImage>();
462     if (scaledImage->BuildFromBitmap(scaledBitmap)) {
463         const double RESIZE_MAX_PROPORTION = ImageCompressor::GetInstance()->CanCompress() ? 1.0 : 0.25;
464         bool needCacheResizedImageFile =
465             (1.0 * dstWidth * dstHeight) / (rawRSImage->GetWidth() * rawRSImage->GetHeight()) < RESIZE_MAX_PROPORTION;
466         auto context = PipelineBase::GetCurrentContext();
467         // card doesn't encode and cache image file.
468         if (needCacheResizedImageFile && !srcKey.empty() && context && !context->IsFormRender()) {
469             BackgroundTaskExecutor::GetInstance().PostTask(
470                 [srcKey, scaledImage]() {
471                     LOGI("write png cache file: %{private}s", srcKey.c_str());
472                     auto data = scaledImage->EncodeToData(RSEncodedImageFormat::PNG, 100);
473                     if (!data) {
474                         return;
475                     }
476                     RSDataWrapper* wrapper = new RSDataWrapper{data};
477                     auto skData = SkData::MakeWithProc(data->GetData(), data->GetSize(),
478                         RSDataWrapperReleaseProc, wrapper);
479                     if (!skData) {
480                         LOGI("encode cache image into cache file failed.");
481                         return;
482                     }
483                     ImageFileCache::GetInstance().WriteCacheFile(srcKey, skData->data(), skData->size());
484                 },
485                 BgTaskPriority::LOW);
486         }
487         return scaledImage;
488     }
489     LOGE("Could not create a scaled image from a scaled bitmap. srcKey: %{private}s, destination size: [%{public}d x"
490          " %{public}d], raw image size: [%{public}d x %{public}d]",
491         srcKey.c_str(), dstWidth, dstHeight, rawRSImage->GetWidth(), rawRSImage->GetHeight());
492     return rawRSImage;
493 }
494 
GetDrawingImage(const std::string & src,const WeakPtr<PipelineBase> context,Size targetSize)495 std::shared_ptr<RSImage> ImageProvider::GetDrawingImage(
496     const std::string& src, const WeakPtr<PipelineBase> context, Size targetSize)
497 {
498     ImageSourceInfo info(src);
499     auto imageLoader = ImageLoader::CreateImageLoader(info);
500     if (!imageLoader) {
501         LOGE("Invalid src, src is %{private}s", src.c_str());
502         return nullptr;
503     }
504     NG::ImageLoadResultInfo errorInfo;
505     auto imageData = imageLoader->LoadImageData(info, errorInfo, context);
506     if (!imageData) {
507         LOGE("fetch data failed. src: %{private}s", src.c_str());
508         return nullptr;
509     }
510     std::shared_ptr<RSImage> rawImage = std::make_shared<RSImage>();
511     if (!rawImage->MakeFromEncoded(imageData)) {
512         LOGE("MakeFromEncoded failed! src: %{private}s", src.c_str());
513         return nullptr;
514     }
515     auto image = ResizeDrawingImage(rawImage, src, targetSize);
516     return image;
517 }
518 
TryLoadImageInfo(const RefPtr<PipelineBase> & context,const std::string & src,std::function<void (bool,int32_t,int32_t)> && loadCallback)519 void ImageProvider::TryLoadImageInfo(const RefPtr<PipelineBase>& context, const std::string& src,
520     std::function<void(bool, int32_t, int32_t)>&& loadCallback)
521 {
522     BackgroundTaskExecutor::GetInstance().PostTask(
523         [src, callback = std::move(loadCallback), context, id = Container::CurrentId()]() {
524             ContainerScope scope(id);
525             auto taskExecutor = context->GetTaskExecutor();
526             if (!taskExecutor) {
527                 return;
528             }
529             auto image = ImageProvider::GetDrawingImage(src, context);
530             if (image) {
531                 callback(true, image->GetWidth(), image->GetHeight());
532                 return;
533             }
534             callback(false, 0, 0);
535         });
536 }
537 
IsWideGamut(const std::shared_ptr<RSColorSpace> & rsColorSpace)538 bool ImageProvider::IsWideGamut(const std::shared_ptr<RSColorSpace>& rsColorSpace)
539 {
540     if (!rsColorSpace) {
541         return false;
542     }
543     // Normalize gamut by 1.
544     // rgb[3] represents the point of Red, Green and Blue coordinate in color space diagram.
545     Point rgb[3];
546     bool hasToXYZD50 = true;
547     auto xyzGamut = rsColorSpace->ToXYZD50(hasToXYZD50);
548     if (!hasToXYZD50) {
549         return false;
550     }
551     for (int32_t i = 0; i < 3; i++) {
552         auto sum = xyzGamut.vals[i][0] + xyzGamut.vals[i][1] + xyzGamut.vals[i][2];
553         rgb[i].SetX(xyzGamut.vals[i][0] / sum);
554         rgb[i].SetY(xyzGamut.vals[i][1] / sum);
555     }
556     // Calculate the area enclosed by the coordinates of the three RGB points
557     Point red = rgb[0];
558     Point green = rgb[1];
559     Point blue = rgb[2];
560     // Assuming there is a triangle enclosed by three points: A(x1, y1), B(x2, y2), C(x3, y3),
561     // the formula for calculating the area of triangle ABC is as follows:
562     // S = (x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2) / 2.0
563     auto areaOfPoint = std::fabs(red.GetX() * green.GetY() + green.GetX() * blue.GetY() + blue.GetX() * green.GetY() -
564                                  red.GetX() * blue.GetY() - blue.GetX() * green.GetY() - green.GetX() * red.GetY()) /
565                        2.0;
566     return GreatNotEqual(areaOfPoint, SRGB_GAMUT_AREA);
567 }
568 
MakeRSBitmapFormatFromPixelMap(const RefPtr<PixelMap> & pixmap)569 RSBitmapFormat ImageProvider::MakeRSBitmapFormatFromPixelMap(const RefPtr<PixelMap>& pixmap)
570 {
571     return { PixelFormatToDrawingColorType(pixmap), AlphaTypeToDrawingAlphaType(pixmap) };
572 }
MakeRSImageInfoFromPixelMap(const RefPtr<PixelMap> & pixmap)573 RSImageInfo ImageProvider::MakeRSImageInfoFromPixelMap(const RefPtr<PixelMap>& pixmap)
574 {
575     RSColorType ct = PixelFormatToDrawingColorType(pixmap);
576     RSAlphaType at = AlphaTypeToDrawingAlphaType(pixmap);
577     std::shared_ptr<RSColorSpace> cs = ColorSpaceToDrawingColorSpace(pixmap);
578     return { pixmap->GetWidth(), pixmap->GetHeight(), ct, at, cs };
579 }
580 
ColorSpaceToDrawingColorSpace(const RefPtr<PixelMap> & pixmap)581 std::shared_ptr<RSColorSpace> ImageProvider::ColorSpaceToDrawingColorSpace(const RefPtr<PixelMap>& pixmap)
582 {
583     return RSColorSpace::CreateSRGB(); // Media::PixelMap has not support wide gamut yet.
584 }
585 
AlphaTypeToDrawingAlphaType(const RefPtr<PixelMap> & pixmap)586 RSAlphaType ImageProvider::AlphaTypeToDrawingAlphaType(const RefPtr<PixelMap>& pixmap)
587 {
588     switch (pixmap->GetAlphaType()) {
589         case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
590             return RSAlphaType::ALPHATYPE_UNKNOWN;
591         case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
592             return RSAlphaType::ALPHATYPE_OPAQUE;
593         case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
594             return RSAlphaType::ALPHATYPE_PREMUL;
595         case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
596             return RSAlphaType::ALPHATYPE_UNPREMUL;
597         default:
598             return RSAlphaType::ALPHATYPE_UNKNOWN;
599     }
600 }
601 
PixelFormatToDrawingColorType(const RefPtr<PixelMap> & pixmap)602 RSColorType ImageProvider::PixelFormatToDrawingColorType(const RefPtr<PixelMap>& pixmap)
603 {
604     switch (pixmap->GetPixelFormat()) {
605         case PixelFormat::RGB_565:
606             return RSColorType::COLORTYPE_RGB_565;
607         case PixelFormat::RGBA_8888:
608             return RSColorType::COLORTYPE_RGBA_8888;
609         case PixelFormat::RGBA_1010102:
610             return RSColorType::COLORTYPE_RGBA_1010102;
611         case PixelFormat::BGRA_8888:
612             return RSColorType::COLORTYPE_BGRA_8888;
613         case PixelFormat::ALPHA_8:
614             return RSColorType::COLORTYPE_ALPHA_8;
615         case PixelFormat::RGBA_F16:
616             return RSColorType::COLORTYPE_RGBA_F16;
617         case PixelFormat::UNKNOWN:
618         case PixelFormat::ARGB_8888:
619         case PixelFormat::RGB_888:
620         case PixelFormat::NV21:
621         case PixelFormat::NV12:
622         case PixelFormat::CMYK:
623         default:
624             return RSColorType::COLORTYPE_UNKNOWN;
625     }
626 }
627 
628 } // namespace OHOS::Ace
629