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