1 /*
2 * Copyright (c) 2021 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 "experimental/svg/model/SkSVGDOM.h"
19 #include "third_party/skia/include/core/SkGraphics.h"
20 #include "third_party/skia/include/core/SkStream.h"
21
22 #include "base/thread/background_task_executor.h"
23 #include "core/common/container.h"
24 #include "core/common/container_scope.h"
25 #include "core/components/image/flutter_render_image.h"
26 #include "core/event/ace_event_helper.h"
27 #include "core/image/flutter_image_cache.h"
28 #include "core/image/image_object.h"
29
30 namespace OHOS::Ace {
31 namespace {
32
33 constexpr double RESIZE_MAX_PROPORTION = 0.5 * 0.5; // Cache image when resize exceeds 25%
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
37 } // namespace
38
FetchImageObject(ImageSourceInfo imageInfo,ImageObjSuccessCallback successCallback,UploadSuccessCallback uploadSuccessCallback,FailedCallback failedCallback,const WeakPtr<PipelineContext> context,bool syncMode,bool useSkiaSvg,bool needAutoResize,RefPtr<FlutterRenderTaskHolder> & renderTaskHolder,OnPostBackgroundTask onBackgroundTaskPostCallback)39 void ImageProvider::FetchImageObject(
40 ImageSourceInfo imageInfo,
41 ImageObjSuccessCallback successCallback,
42 UploadSuccessCallback uploadSuccessCallback,
43 FailedCallback failedCallback,
44 const WeakPtr<PipelineContext> context,
45 bool syncMode,
46 bool useSkiaSvg,
47 bool needAutoResize,
48 RefPtr<FlutterRenderTaskHolder>& renderTaskHolder,
49 OnPostBackgroundTask onBackgroundTaskPostCallback)
50 {
51 auto task = [context, imageInfo, successCallback, failedCallback, useSkiaSvg, renderTaskHolder,
52 uploadSuccessCallback, needAutoResize, id = Container::CurrentId()]() mutable {
53 ContainerScope scope(id);
54 auto pipelineContext = context.Upgrade();
55 if (!pipelineContext) {
56 LOGE("pipline context has been released. imageInfo: %{private}s", imageInfo.ToString().c_str());
57 return;
58 }
59 auto taskExecutor = pipelineContext->GetTaskExecutor();
60 if (!taskExecutor) {
61 LOGE("task executor is null. imageInfo: %{private}s", imageInfo.ToString().c_str());
62 return;
63 }
64 RefPtr<ImageObject> imageObj = QueryImageObjectFromCache(imageInfo, pipelineContext);
65 if (!imageObj) { // if image object is not in cache, generate a new one.
66 imageObj = GeneraterAceImageObject(imageInfo, pipelineContext, useSkiaSvg);
67 }
68 if (!imageObj) { // if it fails to generate an image object, trigger fail callback.
69 taskExecutor->PostTask(
70 [failedCallback, imageInfo] { failedCallback(imageInfo); }, TaskExecutor::TaskType::UI);
71 return;
72 }
73 taskExecutor->PostTask([successCallback, imageInfo, imageObj]() { successCallback(imageInfo, imageObj); },
74 TaskExecutor::TaskType::UI);
75 bool canStartUploadImageObj = !needAutoResize && (imageObj->GetFrameCount() == 1);
76 if (canStartUploadImageObj) {
77 bool forceResize = (!imageObj->IsSvg()) && (imageInfo.IsSourceDimensionValid());
78 FlutterRenderImage::UploadImageObjToGpuForRender(imageObj, context, renderTaskHolder, uploadSuccessCallback,
79 failedCallback, imageObj->GetImageSize(), forceResize, true);
80 }
81 };
82 if (syncMode) {
83 task();
84 return;
85 }
86 CancelableTask cancelableTask(std::move(task));
87 if (onBackgroundTaskPostCallback) {
88 onBackgroundTaskPostCallback(cancelableTask);
89 }
90 BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
91 }
92
QueryImageObjectFromCache(const ImageSourceInfo & imageInfo,const RefPtr<PipelineContext> & pipelineContext)93 RefPtr<ImageObject> ImageProvider::QueryImageObjectFromCache(
94 const ImageSourceInfo& imageInfo, const RefPtr<PipelineContext>& pipelineContext)
95 {
96 auto imageCache = pipelineContext->GetImageCache();
97 if (!imageCache) {
98 return nullptr;
99 }
100 return imageCache->GetCacheImgObj(imageInfo.ToString());
101 }
102
GeneraterAceImageObject(const ImageSourceInfo & imageInfo,const RefPtr<PipelineContext> context,bool useSkiaSvg)103 RefPtr<ImageObject> ImageProvider::GeneraterAceImageObject(
104 const ImageSourceInfo& imageInfo,
105 const RefPtr<PipelineContext> context,
106 bool useSkiaSvg)
107 {
108 auto imageData = LoadImageRawData(imageInfo, context);
109
110 if (!imageData) {
111 LOGE("load image data failed. imageInfo: %{private}s", imageInfo.ToString().c_str());
112 return nullptr;
113 }
114
115 return ImageObject::BuildImageObject(imageInfo, context, imageData, useSkiaSvg);
116 }
117
LoadImageRawData(const ImageSourceInfo & imageInfo,const RefPtr<PipelineContext> context,const Size & targetSize)118 sk_sp<SkData> ImageProvider::LoadImageRawData(
119 const ImageSourceInfo& imageInfo,
120 const RefPtr<PipelineContext> context,
121 const Size& targetSize)
122 {
123 auto imageCache = context->GetImageCache();
124 if (imageCache) {
125 // 1. try get data from cache.
126 auto cacheData = imageCache->GetCacheImageData(imageInfo.GetSrc());
127 if (cacheData) {
128 LOGD("sk data from memory cache.");
129 return AceType::DynamicCast<SkiaCachedImageData>(cacheData)->imageData;
130 }
131 // 2 try get data from file cache.
132 if (targetSize.IsValid()) {
133 LOGD("size valid try load from cache.");
134 std::string cacheFilePath =
135 ImageCache::GetImageCacheFilePath(ImageObject::GenerateCacheKey(imageInfo, targetSize));
136 LOGD("cache file path: %{private}s", cacheFilePath.c_str());
137 auto data = imageCache->GetDataFromCacheFile(cacheFilePath);
138 if (data) {
139 LOGD("cache file found : %{public}s", cacheFilePath.c_str());
140 return AceType::DynamicCast<SkiaCachedImageData>(data)->imageData;
141 }
142 } else {
143 LOGD("target size is not valid, load raw image file.");
144 }
145 }
146 // 3. try load raw image file.
147 auto imageLoader = ImageLoader::CreateImageLoader(imageInfo);
148 if (!imageLoader) {
149 LOGE("imageLoader create failed. imageInfo: %{private}s", imageInfo.ToString().c_str());
150 return nullptr;
151 }
152 auto data = imageLoader->LoadImageData(imageInfo, context);
153 if (data && imageCache) {
154 // cache sk data.
155 imageCache->CacheImageData(imageInfo.GetSrc(), AceType::MakeRefPtr<SkiaCachedImageData>(data));
156 }
157 return data;
158 }
159
GetSVGImageDOMAsyncFromSrc(const std::string & src,std::function<void (const sk_sp<SkSVGDOM> &)> successCallback,std::function<void ()> failedCallback,const WeakPtr<PipelineContext> context,uint64_t svgThemeColor,OnPostBackgroundTask onBackgroundTaskPostCallback)160 void ImageProvider::GetSVGImageDOMAsyncFromSrc(
161 const std::string& src,
162 std::function<void(const sk_sp<SkSVGDOM>&)> successCallback,
163 std::function<void()> failedCallback,
164 const WeakPtr<PipelineContext> context,
165 uint64_t svgThemeColor,
166 OnPostBackgroundTask onBackgroundTaskPostCallback)
167 {
168 auto task = [src, successCallback, failedCallback, context, svgThemeColor, id = Container::CurrentId()] {
169 ContainerScope scope(id);
170 auto pipelineContext = context.Upgrade();
171 if (!pipelineContext) {
172 LOGW("render image or pipeline has been released. src: %{private}s", src.c_str());
173 return;
174 }
175 auto taskExecutor = pipelineContext->GetTaskExecutor();
176 if (!taskExecutor) {
177 return;
178 }
179 ImageSourceInfo info(src);
180 auto imageLoader = ImageLoader::CreateImageLoader(info);
181 if (!imageLoader) {
182 LOGE("load image failed when create image loader. src: %{private}s", src.c_str());
183 return;
184 }
185 auto imageData = imageLoader->LoadImageData(info, context);
186 if (imageData) {
187 const auto svgStream = std::make_unique<SkMemoryStream>(std::move(imageData));
188 if (svgStream) {
189 auto skiaDom = SkSVGDOM::MakeFromStream(*svgStream, svgThemeColor);
190 if (skiaDom) {
191 taskExecutor->PostTask(
192 [successCallback, skiaDom] { successCallback(skiaDom); }, TaskExecutor::TaskType::UI);
193 return;
194 }
195 }
196 }
197 LOGE("svg data wrong! src: %{private}s", src.c_str());
198 taskExecutor->PostTask([failedCallback] { failedCallback(); }, TaskExecutor::TaskType::UI);
199 };
200 CancelableTask cancelableTask(std::move(task));
201 if (onBackgroundTaskPostCallback) {
202 onBackgroundTaskPostCallback(cancelableTask);
203 }
204 BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
205 }
206
GetSVGImageDOMAsyncFromData(const sk_sp<SkData> & skData,std::function<void (const sk_sp<SkSVGDOM> &)> successCallback,std::function<void ()> failedCallback,const WeakPtr<PipelineContext> context,uint64_t svgThemeColor,OnPostBackgroundTask onBackgroundTaskPostCallback)207 void ImageProvider::GetSVGImageDOMAsyncFromData(
208 const sk_sp<SkData>& skData,
209 std::function<void(const sk_sp<SkSVGDOM>&)> successCallback,
210 std::function<void()> failedCallback,
211 const WeakPtr<PipelineContext> context,
212 uint64_t svgThemeColor,
213 OnPostBackgroundTask onBackgroundTaskPostCallback)
214 {
215 auto task = [skData, successCallback, failedCallback, context, svgThemeColor, id = Container::CurrentId()] {
216 ContainerScope scope(id);
217 auto pipelineContext = context.Upgrade();
218 if (!pipelineContext) {
219 LOGW("render image or pipeline has been released.");
220 return;
221 }
222 auto taskExecutor = pipelineContext->GetTaskExecutor();
223 if (!taskExecutor) {
224 return;
225 }
226
227 const auto svgStream = std::make_unique<SkMemoryStream>(skData);
228 if (svgStream) {
229 auto skiaDom = SkSVGDOM::MakeFromStream(*svgStream, svgThemeColor);
230 if (skiaDom) {
231 taskExecutor->PostTask(
232 [successCallback, skiaDom] { successCallback(skiaDom); }, TaskExecutor::TaskType::UI);
233 return;
234 }
235 }
236 LOGE("svg data wrong!");
237 taskExecutor->PostTask([failedCallback] { failedCallback(); }, TaskExecutor::TaskType::UI);
238 };
239 CancelableTask cancelableTask(std::move(task));
240 if (onBackgroundTaskPostCallback) {
241 onBackgroundTaskPostCallback(cancelableTask);
242 }
243 BackgroundTaskExecutor::GetInstance().PostTask(cancelableTask);
244 }
245
UploadImageToGPUForRender(const sk_sp<SkImage> & image,const std::function<void (flutter::SkiaGPUObject<SkImage>)> && callback,const RefPtr<FlutterRenderTaskHolder> & renderTaskHolder)246 void ImageProvider::UploadImageToGPUForRender(
247 const sk_sp<SkImage>& image,
248 const std::function<void(flutter::SkiaGPUObject<SkImage>)>&& callback,
249 const RefPtr<FlutterRenderTaskHolder>& renderTaskHolder)
250 {
251 if (!renderTaskHolder) {
252 LOGW("renderTaskHolder has been released.");
253 return;
254 }
255 #if defined(DUMP_DRAW_CMD) || defined(GPU_DISABLED)
256 // If want to dump draw command or gpu disabled, should use CPU image.
257 callback({ image, renderTaskHolder->unrefQueue });
258 #else
259 // TODO: software render not upload to gpu
260
261 auto rasterizedImage = image->makeRasterImage();
262 if (!rasterizedImage) {
263 LOGW("Rasterize image failed. callback.");
264 callback({ image, renderTaskHolder->unrefQueue });
265 return;
266 }
267 auto task = [rasterizedImage, callback, renderTaskHolder] () {
268 if (!renderTaskHolder) {
269 LOGW("renderTaskHolder has been released.");
270 return;
271 }
272 // weak reference of io manager must be check and used on io thread, because io manager is created on io thread.
273 if (!renderTaskHolder->ioManager) {
274 // Shell is closing.
275 callback({ rasterizedImage, renderTaskHolder->unrefQueue });
276 return;
277 }
278 ACE_DCHECK(!rasterizedImage->isTextureBacked());
279 auto resContext = renderTaskHolder->ioManager->GetResourceContext();
280 if (!resContext) {
281 callback({ rasterizedImage, renderTaskHolder->unrefQueue });
282 return;
283 }
284 SkPixmap pixmap;
285 if (!rasterizedImage->peekPixels(&pixmap)) {
286 LOGW("Could not peek pixels of image for texture upload.");
287 callback({ rasterizedImage, renderTaskHolder->unrefQueue });
288 return;
289 }
290 auto textureImage =
291 SkImage::MakeCrossContextFromPixmap(resContext.get(), pixmap, true, pixmap.colorSpace(), true);
292 callback({ textureImage ? textureImage : rasterizedImage, renderTaskHolder->unrefQueue });
293
294 // Trigger purge cpu bitmap resource, after image upload to gpu.
295 SkGraphics::PurgeResourceCache();
296 };
297 renderTaskHolder->ioTaskRunner->PostTask(std::move(task));
298 #endif
299 }
300
ResizeSkImage(const sk_sp<SkImage> & rawImage,const std::string & src,Size imageSize,bool forceResize)301 sk_sp<SkImage> ImageProvider::ResizeSkImage(
302 const sk_sp<SkImage>& rawImage,
303 const std::string& src,
304 Size imageSize,
305 bool forceResize)
306 {
307 if (!imageSize.IsValid()) {
308 LOGE("not valid size!, imageSize: %{private}s, src: %{private}s", imageSize.ToString().c_str(), src.c_str());
309 return rawImage;
310 }
311 int32_t dstWidth = static_cast<int32_t>(imageSize.Width() + 0.5);
312 int32_t dstHeight = static_cast<int32_t>(imageSize.Height() + 0.5);
313
314 bool needResize = false;
315
316 if (!forceResize) {
317 if (rawImage->width() > dstWidth) {
318 needResize = true;
319 } else {
320 dstWidth = rawImage->width();
321 }
322 if (rawImage->height() > dstHeight) {
323 needResize = true;
324 } else {
325 dstHeight = rawImage->height();
326 }
327 }
328
329 if (!needResize && !forceResize) {
330 return rawImage;
331 }
332 return ApplySizeToSkImage(
333 rawImage,
334 dstWidth,
335 dstHeight,
336 ImageObject::GenerateCacheKey(ImageSourceInfo(src), imageSize));
337 }
338
ApplySizeToSkImage(const sk_sp<SkImage> & rawImage,int32_t dstWidth,int32_t dstHeight,const std::string & srcKey)339 sk_sp<SkImage> ImageProvider::ApplySizeToSkImage(
340 const sk_sp<SkImage>& rawImage,
341 int32_t dstWidth,
342 int32_t dstHeight,
343 const std::string& srcKey)
344 {
345 auto scaledImageInfo =
346 SkImageInfo::Make(dstWidth, dstHeight, rawImage->colorType(), rawImage->alphaType(), rawImage->refColorSpace());
347 SkBitmap scaledBitmap;
348 if (!scaledBitmap.tryAllocPixels(scaledImageInfo)) {
349 LOGE("Could not allocate bitmap when attempting to scale. srcKey: %{private}s, destination size: [%{public}d x"
350 " %{public}d], raw image size: [%{public}d x %{public}d]",
351 srcKey.c_str(), dstWidth, dstHeight, rawImage->width(), rawImage->height());
352 return rawImage;
353 }
354 if (!rawImage->scalePixels(scaledBitmap.pixmap(), kLow_SkFilterQuality, SkImage::kDisallow_CachingHint)) {
355 LOGE("Could not scale pixels srcKey: %{private}s, destination size: [%{public}d x"
356 " %{public}d], raw image size: [%{public}d x %{public}d]",
357 srcKey.c_str(), dstWidth, dstHeight, rawImage->width(), rawImage->height());
358 return rawImage;
359 }
360 // Marking this as immutable makes the MakeFromBitmap call share the pixels instead of copying.
361 scaledBitmap.setImmutable();
362 auto scaledImage = SkImage::MakeFromBitmap(scaledBitmap);
363 if (scaledImage) {
364 bool needCacheResizedImageFile =
365 (1.0 * dstWidth * dstHeight) / (rawImage->width() * rawImage->height()) < RESIZE_MAX_PROPORTION;
366 if (needCacheResizedImageFile && !srcKey.empty()) {
367 BackgroundTaskExecutor::GetInstance().PostTask(
368 [srcKey, scaledImage]() {
369 LOGI("write png cache file: %{private}s", srcKey.c_str());
370 auto data = scaledImage->encodeToData(SkEncodedImageFormat::kPNG, 100);
371 if (!data) {
372 LOGI("encode cache image into cache file failed.");
373 return;
374 }
375 ImageCache::WriteCacheFile(srcKey, data->data(), data->size());
376 },
377 BgTaskPriority::LOW);
378 }
379 return scaledImage;
380 }
381 LOGE("Could not create a scaled image from a scaled bitmap. srcKey: %{private}s, destination size: [%{public}d x"
382 " %{public}d], raw image size: [%{public}d x %{public}d]",
383 srcKey.c_str(), dstWidth, dstHeight, rawImage->width(), rawImage->height());
384 return rawImage;
385 }
386
GetSkImage(const std::string & src,const WeakPtr<PipelineContext> context,Size targetSize)387 sk_sp<SkImage> ImageProvider::GetSkImage(
388 const std::string& src,
389 const WeakPtr<PipelineContext> context,
390 Size targetSize)
391 {
392 ImageSourceInfo info(src);
393 auto imageLoader = ImageLoader::CreateImageLoader(info);
394 if (!imageLoader) {
395 LOGE("Invalid src, src is %{public}s", src.c_str());
396 return nullptr;
397 }
398 auto imageSkData = imageLoader->LoadImageData(info, context);
399 if (!imageSkData) {
400 LOGE("fetch data failed. src: %{private}s", src.c_str());
401 return nullptr;
402 }
403 auto rawImage = SkImage::MakeFromEncoded(imageSkData);
404 if (!rawImage) {
405 LOGE("MakeFromEncoded failed! src: %{private}s", src.c_str());
406 return nullptr;
407 }
408 auto image = ResizeSkImage(rawImage, src, targetSize);
409 return image;
410 }
411
TryLoadImageInfo(const RefPtr<PipelineContext> & context,const std::string & src,std::function<void (bool,int32_t,int32_t)> && loadCallback)412 void ImageProvider::TryLoadImageInfo(const RefPtr<PipelineContext>& context, const std::string& src,
413 std::function<void(bool, int32_t, int32_t)>&& loadCallback)
414 {
415 BackgroundTaskExecutor::GetInstance().PostTask(
416 [src, callback = std::move(loadCallback), context, id = Container::CurrentId()]() {
417 ContainerScope scope(id);
418 auto taskExecutor = context->GetTaskExecutor();
419 if (!taskExecutor) {
420 return;
421 }
422 auto image = ImageProvider::GetSkImage(src, context);
423 if (image) {
424 callback(true, image->width(), image->height());
425 return;
426 }
427 callback(false, 0, 0);
428 });
429 }
430
IsWideGamut(const sk_sp<SkColorSpace> & colorSpace)431 bool ImageProvider::IsWideGamut(const sk_sp<SkColorSpace>& colorSpace)
432 {
433 skcms_ICCProfile encodedProfile;
434 colorSpace->toProfile(&encodedProfile);
435 if (!encodedProfile.has_toXYZD50) {
436 LOGI("This profile's gamut can not be represented by a 3x3 transform to XYZD50");
437 return false;
438 }
439 // Normalize gamut by 1.
440 // rgb[3] represents the point of Red, Green and Blue coordinate in color space diagram.
441 Point rgb[3];
442 auto xyzGamut = encodedProfile.toXYZD50;
443 for (int32_t i = 0; i < 3; i++) {
444 auto sum = xyzGamut.vals[i][0] + xyzGamut.vals[i][1] + xyzGamut.vals[i][2];
445 rgb[i].SetX(xyzGamut.vals[i][0] / sum);
446 rgb[i].SetY(xyzGamut.vals[i][1] / sum);
447 }
448 // Calculate the area enclosed by the coordinates of the three RGB points
449 Point red = rgb[0];
450 Point green = rgb[1];
451 Point blue = rgb[2];
452 // Assuming there is a triangle enclosed by three points: A(x1, y1), B(x2, y2), C(x3, y3),
453 // the formula for calculating the area of triangle ABC is as follows:
454 // S = (x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2) / 2.0
455 auto areaOfPoint = std::fabs(red.GetX() * green.GetY() + green.GetX() * blue.GetY() + blue.GetX() * green.GetY() -
456 red.GetX() * blue.GetY() - blue.GetX() * green.GetY() - green.GetX() * red.GetY()) / 2.0;
457 return GreatNotEqual(areaOfPoint, SRGB_GAMUT_AREA);
458 }
459
MakeSkImageInfoFromPixelMap(const RefPtr<PixelMap> & pixmap)460 SkImageInfo ImageProvider::MakeSkImageInfoFromPixelMap(const RefPtr<PixelMap>& pixmap)
461 {
462 SkColorType ct = PixelFormatToSkColorType(pixmap);
463 SkAlphaType at = AlphaTypeToSkAlphaType(pixmap);
464 sk_sp<SkColorSpace> cs = ColorSpaceToSkColorSpace(pixmap);
465 return SkImageInfo::Make(pixmap->GetWidth(), pixmap->GetHeight(), ct, at, cs);
466 }
467
ColorSpaceToSkColorSpace(const RefPtr<PixelMap> & pixmap)468 sk_sp<SkColorSpace> ImageProvider::ColorSpaceToSkColorSpace(const RefPtr<PixelMap>& pixmap)
469 {
470 return SkColorSpace::MakeSRGB(); // Media::PixelMap has not support wide gamut yet.
471 }
472
AlphaTypeToSkAlphaType(const RefPtr<PixelMap> & pixmap)473 SkAlphaType ImageProvider::AlphaTypeToSkAlphaType(const RefPtr<PixelMap>& pixmap)
474 {
475 switch (pixmap->GetAlphaType()) {
476 case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
477 return SkAlphaType::kUnknown_SkAlphaType;
478 case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
479 return SkAlphaType::kOpaque_SkAlphaType;
480 case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
481 return SkAlphaType::kPremul_SkAlphaType;
482 case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
483 return SkAlphaType::kUnpremul_SkAlphaType;
484 default:
485 return SkAlphaType::kUnknown_SkAlphaType;
486 }
487 }
488
PixelFormatToSkColorType(const RefPtr<PixelMap> & pixmap)489 SkColorType ImageProvider::PixelFormatToSkColorType(const RefPtr<PixelMap>& pixmap)
490 {
491 switch (pixmap->GetPixelFormat()) {
492 case PixelFormat::RGB_565:
493 return SkColorType::kRGB_565_SkColorType;
494 case PixelFormat::RGBA_8888:
495 return SkColorType::kRGBA_8888_SkColorType;
496 case PixelFormat::BGRA_8888:
497 return SkColorType::kBGRA_8888_SkColorType;
498 case PixelFormat::ALPHA_8:
499 return SkColorType::kAlpha_8_SkColorType;
500 case PixelFormat::RGBA_F16:
501 return SkColorType::kRGBA_F16_SkColorType;
502 case PixelFormat::UNKNOWN:
503 case PixelFormat::ARGB_8888:
504 case PixelFormat::RGB_888:
505 case PixelFormat::NV21:
506 case PixelFormat::NV12:
507 case PixelFormat::CMYK:
508 default:
509 return SkColorType::kUnknown_SkColorType;
510 }
511 }
512
513 } // namespace OHOS::Ace
514