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_loader.h"
17
18 #include <condition_variable>
19 #include <mutex>
20 #include <ratio>
21 #include <regex>
22 #include <string_view>
23 #include <unistd.h>
24
25 #include "include/utils/SkBase64.h"
26
27 #include "base/memory/ace_type.h"
28 #include "base/utils/system_properties.h"
29 #include "core/common/resource/resource_manager.h"
30 #include "core/common/resource/resource_object.h"
31 #include "core/common/resource/resource_wrapper.h"
32 #include "core/components/theme/theme_utils.h"
33
34 #ifdef USE_ROSEN_DRAWING
35 #include "drawing/engine_adapter/skia_adapter/skia_data.h"
36 #endif
37
38 #include "base/image/file_uri_helper.h"
39 #include "base/image/image_source.h"
40 #include "base/log/ace_trace.h"
41 #include "base/network/download_manager.h"
42 #include "base/resource/ace_res_config.h"
43 #include "base/resource/asset_manager.h"
44 #include "base/thread/background_task_executor.h"
45 #include "base/utils/string_utils.h"
46 #include "base/utils/utils.h"
47 #include "core/common/ace_application_info.h"
48 #include "core/common/container.h"
49 #include "core/common/thread_checker.h"
50 #include "core/components/common/layout/constants.h"
51 #include "core/components_ng/image_provider/image_data.h"
52 #ifdef USE_ROSEN_DRAWING
53 #include "core/components_ng/image_provider/adapter/rosen/drawing_image_data.h"
54 #endif
55 #include "core/image/image_cache.h"
56 #include "core/image/image_file_cache.h"
57 #include "core/pipeline/pipeline_context.h"
58
59 namespace OHOS::Ace {
60 namespace {
61
62 constexpr size_t FILE_HEAD_LENGTH = 7; // 7 is the size of "file://"
63 constexpr size_t MEMORY_HEAD_LENGTH = 9; // 9 is the size of "memory://"
64 constexpr size_t INTERNAL_FILE_HEAD_LENGTH = 15; // 15 is the size of "internal://app/"
65 // regex for "resource://colormode/xxx.type", colormode can be "light" or "dark", xxx represents system resource id,
66 // type can be "jpg", "png", "svg" and so on.
67 const std::regex MEDIA_RES_ID_REGEX(R"(^resource://\w+/([0-9]+)\.\w+$)", std::regex::icase);
68 const std::regex MEDIA_APP_RES_PATH_REGEX(R"(^resource://RAWFILE/(.*)$)");
69 const std::regex MEDIA_APP_RES_ID_REGEX(R"(^resource://.*/([0-9]+)\.\w+$)", std::regex::icase);
70 const std::regex MEDIA_RES_NAME_REGEX(R"(^resource://.*/(\w+)\.\w+$)", std::regex::icase);
71 constexpr uint32_t MEDIA_RESOURCE_MATCH_SIZE = 2;
72
73 const std::chrono::duration<int, std::milli> TIMEOUT_DURATION(10000);
74
75 #ifdef WINDOWS_PLATFORM
realpath(const char * path,char * resolved_path)76 char* realpath(const char* path, char* resolved_path)
77 {
78 if (strcpy_s(resolved_path, PATH_MAX, path) != 0) {
79 return nullptr;
80 }
81 return resolved_path;
82 }
83 #endif
84 } // namespace
85
RemovePathHead(const std::string & uri)86 std::string ImageLoader::RemovePathHead(const std::string& uri)
87 {
88 auto iter = uri.find_first_of(':');
89 if (iter == std::string::npos) {
90 TAG_LOGW(AceLogTag::ACE_IMAGE, "No scheme, not a File or Memory path");
91 return std::string();
92 }
93 std::string head = uri.substr(0, iter);
94 if ((head == "file" && uri.size() > FILE_HEAD_LENGTH) || (head == "memory" && uri.size() > MEMORY_HEAD_LENGTH) ||
95 (head == "internal" && uri.size() > INTERNAL_FILE_HEAD_LENGTH)) {
96 // the file uri format is like "file:///data/data...",
97 // the memory uri format is like "memory://imagename.png" for example,
98 // iter + 3 to get the absolutely file path substring : "/data/data..." or the image name: "imagename.png"
99 return uri.substr(iter + 3);
100 }
101 TAG_LOGW(AceLogTag::ACE_IMAGE, "Wrong scheme, not a File!");
102 return std::string();
103 }
104
CreateImageLoader(const ImageSourceInfo & imageSourceInfo)105 RefPtr<ImageLoader> ImageLoader::CreateImageLoader(const ImageSourceInfo& imageSourceInfo)
106 {
107 SrcType srcType = imageSourceInfo.GetSrcType();
108 switch (srcType) {
109 case SrcType::INTERNAL:
110 case SrcType::FILE: {
111 return MakeRefPtr<FileImageLoader>();
112 }
113 case SrcType::NETWORK: {
114 return MakeRefPtr<NetworkImageLoader>();
115 }
116 case SrcType::ASSET: {
117 return MakeRefPtr<AssetImageLoader>();
118 }
119 case SrcType::BASE64: {
120 return MakeRefPtr<Base64ImageLoader>();
121 }
122 case SrcType::RESOURCE: {
123 return MakeRefPtr<ResourceImageLoader>();
124 }
125 case SrcType::DATA_ABILITY: {
126 return MakeRefPtr<DataProviderImageLoader>();
127 }
128 case SrcType::DATA_ABILITY_DECODED: {
129 return MakeRefPtr<DecodedDataProviderImageLoader>();
130 }
131 case SrcType::MEMORY: {
132 if (Container::IsCurrentUseNewPipeline()) {
133 return MakeRefPtr<SharedMemoryImageLoader>();
134 }
135 TAG_LOGW(
136 AceLogTag::ACE_IMAGE, "Image source type: shared memory. image data is not come from image loader.");
137 return nullptr;
138 }
139 case SrcType::RESOURCE_ID: {
140 return MakeRefPtr<InternalImageLoader>();
141 }
142 case SrcType::PIXMAP: {
143 return MakeRefPtr<PixelMapImageLoader>();
144 }
145 case SrcType::ASTC: {
146 return MakeRefPtr<AstcImageLoader>();
147 }
148 default: {
149 TAG_LOGW(AceLogTag::ACE_IMAGE,
150 "Image source type not supported! srcType: %{public}d, sourceInfo: %{public}s", srcType,
151 imageSourceInfo.ToString().c_str());
152 return nullptr;
153 }
154 }
155 }
156
157 #ifndef USE_ROSEN_DRAWING
LoadDataFromCachedFile(const std::string & uri)158 sk_sp<SkData> ImageLoader::LoadDataFromCachedFile(const std::string& uri)
159 #else
160 std::shared_ptr<RSData> ImageLoader::LoadDataFromCachedFile(const std::string& uri)
161 #endif
162 {
163 std::string cacheFilePath = ImageFileCache::GetInstance().GetImageCacheFilePath(uri);
164 if (cacheFilePath.length() > PATH_MAX) {
165 TAG_LOGW(
166 AceLogTag::ACE_IMAGE, "cache file path is too long, cacheFilePath: %{private}s", cacheFilePath.c_str());
167 return nullptr;
168 }
169 cacheFilePath = ImageFileCache::GetInstance().GetCacheFilePath(uri);
170 if (cacheFilePath == "") {
171 return nullptr;
172 }
173 char realPath[PATH_MAX] = { 0x00 };
174 if (realpath(cacheFilePath.c_str(), realPath) == nullptr) {
175 TAG_LOGW(AceLogTag::ACE_IMAGE, "realpath fail! cacheFilePath: %{private}s, fail reason: %{public}s",
176 cacheFilePath.c_str(), strerror(errno));
177 return nullptr;
178 }
179 std::unique_ptr<FILE, decltype(&fclose)> file(fopen(realPath, "rb"), fclose);
180 if (file) {
181 #ifndef USE_ROSEN_DRAWING
182 return SkData::MakeFromFILE(file.get());
183 #else
184 auto skData = SkData::MakeFromFILE(file.get());
185 CHECK_NULL_RETURN(skData, nullptr);
186 auto rsData = std::make_shared<RSData>();
187 rsData->GetImpl<Rosen::Drawing::SkiaData>()->SetSkData(skData);
188 return rsData;
189 #endif
190 }
191 return nullptr;
192 }
193
194 #ifndef USE_ROSEN_DRAWING
QueryImageDataFromImageCache(const ImageSourceInfo & sourceInfo)195 sk_sp<SkData> ImageLoader::QueryImageDataFromImageCache(const ImageSourceInfo& sourceInfo)
196 #else
197 std::shared_ptr<RSData> ImageLoader::QueryImageDataFromImageCache(const ImageSourceInfo& sourceInfo)
198 #endif
199 {
200 auto pipelineCtx = PipelineContext::GetCurrentContext();
201 CHECK_NULL_RETURN(pipelineCtx, nullptr);
202 auto imageCache = pipelineCtx->GetImageCache();
203 CHECK_NULL_RETURN(imageCache, nullptr);
204 auto cacheData = imageCache->GetCacheImageData(sourceInfo.GetKey());
205 CHECK_NULL_RETURN(cacheData, nullptr);
206 #ifndef USE_ROSEN_DRAWING
207 const auto* skData = reinterpret_cast<const sk_sp<SkData>*>(cacheData->GetDataWrapper());
208 return *skData;
209 #else
210 auto rosenCachedImageData = AceType::DynamicCast<NG::DrawingImageData>(cacheData);
211 CHECK_NULL_RETURN(rosenCachedImageData, nullptr);
212 return rosenCachedImageData->GetRSData();
213 #endif
214 }
215
CacheImageData(const std::string & key,const RefPtr<NG::ImageData> & imageData)216 void ImageLoader::CacheImageData(const std::string& key, const RefPtr<NG::ImageData>& imageData)
217 {
218 auto pipelineCtx = PipelineContext::GetCurrentContext();
219 CHECK_NULL_VOID(pipelineCtx);
220 auto imageCache = pipelineCtx->GetImageCache();
221 CHECK_NULL_VOID(imageCache);
222 imageCache->CacheImageData(key, imageData);
223 }
224
LoadImageDataFromFileCache(const std::string & key,const std::string & suffix)225 RefPtr<NG::ImageData> ImageLoader::LoadImageDataFromFileCache(const std::string& key, const std::string& suffix)
226 {
227 ACE_FUNCTION_TRACE();
228 return ImageFileCache::GetInstance().GetDataFromCacheFile(key, suffix);
229 }
230
231 // NG ImageLoader entrance
GetImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & context)232 RefPtr<NG::ImageData> ImageLoader::GetImageData(const ImageSourceInfo& src, const WeakPtr<PipelineBase>& context)
233 {
234 ACE_FUNCTION_TRACE();
235 bool queryCache = !src.GetIsConfigurationChange();
236 if (src.IsPixmap()) {
237 return LoadDecodedImageData(src, context);
238 }
239 #ifndef USE_ROSEN_DRAWING
240 if (queryCache) {
241 auto cachedData = ImageLoader::QueryImageDataFromImageCache(src);
242 if (cachedData) {
243 return NG::ImageData::MakeFromDataWrapper(&cachedData);
244 }
245 }
246 auto skData = LoadImageData(src, context);
247 CHECK_NULL_RETURN(skData, nullptr);
248 auto data = NG::ImageData::MakeFromDataWrapper(&skData);
249 ImageLoader::CacheImageData(src.GetKey(), data);
250 return data;
251 #else
252 std::shared_ptr<RSData> rsData = nullptr;
253 do {
254 if (queryCache) {
255 rsData = ImageLoader::QueryImageDataFromImageCache(src);
256 if (rsData) {
257 break;
258 }
259 }
260 rsData = LoadImageData(src, context);
261 CHECK_NULL_RETURN(rsData, nullptr);
262 ImageLoader::CacheImageData(src.GetKey(), AceType::MakeRefPtr<NG::DrawingImageData>(rsData));
263 } while (0);
264 return AceType::MakeRefPtr<NG::DrawingImageData>(rsData);
265 #endif
266 }
267
268 // NG ImageLoader entrance
DownloadImage(DownloadCallback && downloadCallback,const std::string & src,bool sync)269 bool NetworkImageLoader::DownloadImage(DownloadCallback&& downloadCallback, const std::string& src, bool sync)
270 {
271 return sync ? DownloadManager::GetInstance()->DownloadSync(std::move(downloadCallback), src, Container::CurrentId())
272 : DownloadManager::GetInstance()->DownloadAsync(
273 std::move(downloadCallback), src, Container::CurrentId());
274 }
275
276 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> &)277 sk_sp<SkData> FileImageLoader::LoadImageData(
278 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& /* context */)
279 #else
280 std::shared_ptr<RSData> FileImageLoader::LoadImageData(
281 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& /* context */)
282 #endif
283 {
284 ACE_SCOPED_TRACE("LoadImageData %s", imageSourceInfo.ToString().c_str());
285 const auto& src = imageSourceInfo.GetSrc();
286 std::string filePath = RemovePathHead(src);
287 if (imageSourceInfo.GetSrcType() == SrcType::INTERNAL) {
288 // the internal source uri format is like "internal://app/imagename.png", the absolute path of which is like
289 // "/data/data/{bundleName}/files/imagename.png"
290 auto bundleName = AceApplicationInfo::GetInstance().GetPackageName();
291 if (bundleName.empty()) {
292 TAG_LOGW(AceLogTag::ACE_IMAGE, "bundleName is empty, LoadImageData for internal source fail!");
293 return nullptr;
294 }
295 if (!StringUtils::StartWith(filePath, "app/")) { // "app/" is infix of internal path
296 TAG_LOGW(AceLogTag::ACE_IMAGE, "internal path format is wrong. path is %{private}s", src.c_str());
297 return nullptr;
298 }
299 filePath = std::string("/data/data/") // head of absolute path
300 .append(bundleName)
301 .append("/files/") // infix of absolute path
302 .append(filePath.substr(4)); // 4 is the length of "app/" from "internal://app/"
303 } else if (imageSourceInfo.GetSrcType() == SrcType::FILE) {
304 filePath = FileUriHelper::GetRealPath(src);
305 }
306 if (filePath.length() > PATH_MAX) {
307 TAG_LOGW(AceLogTag::ACE_IMAGE, "src path is too long");
308 return nullptr;
309 }
310 char realPath[PATH_MAX] = { 0x00 };
311 if (realpath(filePath.c_str(), realPath) == nullptr) {
312 TAG_LOGW(AceLogTag::ACE_IMAGE, "realpath fail! filePath: %{public}s, fail reason: %{public}s src:%{public}s",
313 filePath.c_str(), strerror(errno), src.c_str());
314 return nullptr;
315 }
316 auto result = SkData::MakeFromFileName(realPath);
317 if (!result) {
318 TAG_LOGW(AceLogTag::ACE_IMAGE,
319 "read data failed, filePath: %{public}s, src: %{public}s, fail reason: "
320 "%{public}s",
321 filePath.c_str(), src.c_str(), strerror(errno));
322 }
323 #ifndef USE_ROSEN_DRAWING
324 #ifdef PREVIEW
325 // on Windows previewer, SkData::MakeFromFile keeps the file open during SkData's lifetime
326 // return a copy to release the file handle
327 CHECK_NULL_RETURN(result, nullptr);
328 return SkData::MakeWithCopy(result->data(), result->size());
329 #else
330 return result;
331 #endif
332 #else
333 CHECK_NULL_RETURN(result, nullptr);
334 auto rsData = std::make_shared<RSData>();
335 #ifdef PREVIEW
336 // on Windows previewer, SkData::MakeFromFile keeps the file open during Drawing::Data's lifetime
337 // return a copy to release the file handle
338 return rsData->BuildWithCopy(result->data(), result->size()) ? rsData : nullptr;
339 #else
340 rsData->GetImpl<Rosen::Drawing::SkiaData>()->SetSkData(result);
341 return rsData;
342 #endif
343 #endif
344 }
345
346 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)347 sk_sp<SkData> DataProviderImageLoader::LoadImageData(
348 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
349 #else
350 std::shared_ptr<RSData> DataProviderImageLoader::LoadImageData(
351 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
352 #endif
353 {
354 const auto& src = imageSourceInfo.GetSrc();
355 auto drawingData = ImageLoader::LoadDataFromCachedFile(src);
356 if (drawingData) {
357 return drawingData;
358 }
359 auto pipeline = context.Upgrade();
360 CHECK_NULL_RETURN(pipeline, nullptr);
361 auto dataProvider = pipeline->GetDataProviderManager();
362 CHECK_NULL_RETURN(dataProvider, nullptr);
363 auto res = dataProvider->GetDataProviderResFromUri(src);
364 CHECK_NULL_RETURN(res, nullptr);
365 #ifndef USE_ROSEN_DRAWING
366 auto data = SkData::MakeFromMalloc(res->GetData().release(), res->GetSize());
367 #else
368 // function is ok, just pointer cast from SKData to RSData
369 auto skData = SkData::MakeFromMalloc(res->GetData().release(), res->GetSize());
370 CHECK_NULL_RETURN(skData, nullptr);
371 auto data = std::make_shared<RSData>();
372 data->GetImpl<Rosen::Drawing::SkiaData>()->SetSkData(skData);
373 #endif
374 return data;
375 }
376
377 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)378 sk_sp<SkData> AssetImageLoader::LoadImageData(
379 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
380 #else
381 std::shared_ptr<RSData> AssetImageLoader::LoadImageData(
382 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
383 #endif
384 {
385 ACE_FUNCTION_TRACE();
386 const auto& src = imageSourceInfo.GetSrc();
387 if (src.empty()) {
388 TAG_LOGW(AceLogTag::ACE_IMAGE, "image src is empty");
389 return nullptr;
390 }
391
392 std::string assetSrc(src);
393 if (assetSrc[0] == '/') {
394 assetSrc = assetSrc.substr(1); // get the asset src without '/'.
395 } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
396 assetSrc = assetSrc.substr(2); // get the asset src without './'.
397 }
398 auto pipelineContext = context.Upgrade();
399 if (!pipelineContext) {
400 TAG_LOGW(AceLogTag::ACE_IMAGE, "invalid pipeline context");
401 return nullptr;
402 }
403 auto assetManager = pipelineContext->GetAssetManager();
404 if (!assetManager) {
405 TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset manager!");
406 return nullptr;
407 }
408 auto assetData = assetManager->GetAsset(assetSrc);
409 if (!assetData) {
410 TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset data!");
411 return nullptr;
412 }
413 const uint8_t* data = assetData->GetData();
414 const size_t dataSize = assetData->GetSize();
415 #ifndef USE_ROSEN_DRAWING
416 return SkData::MakeWithCopy(data, dataSize);
417 #else
418 auto drawingData = std::make_shared<RSData>();
419 drawingData->BuildWithCopy(data, dataSize);
420 return drawingData;
421 #endif
422 }
423
LoadJsonData(const std::string & src,const WeakPtr<PipelineBase> context)424 std::string AssetImageLoader::LoadJsonData(const std::string& src, const WeakPtr<PipelineBase> context)
425 {
426 if (src.empty()) {
427 TAG_LOGW(AceLogTag::ACE_IMAGE, "image src is empty");
428 return "";
429 }
430
431 std::string assetSrc(src);
432 if (assetSrc[0] == '/') {
433 assetSrc = assetSrc.substr(1); // get the asset src without '/'.
434 } else if (assetSrc[0] == '.' && assetSrc.size() > 2 && assetSrc[1] == '/') {
435 assetSrc = assetSrc.substr(2); // get the asset src without './'.
436 }
437 auto pipelineContext = context.Upgrade();
438 if (!pipelineContext) {
439 return "";
440 }
441 auto assetManager = pipelineContext->GetAssetManager();
442 if (!assetManager) {
443 TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset manager!");
444 return "";
445 }
446 auto assetData = assetManager->GetAsset(assetSrc);
447 if (!assetData || !assetData->GetData()) {
448 TAG_LOGW(AceLogTag::ACE_IMAGE, "No asset data!");
449 return "";
450 }
451 return std::string((char*)assetData->GetData(), assetData->GetSize());
452 }
453
454 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)455 sk_sp<SkData> NetworkImageLoader::LoadImageData(
456 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
457 #else
458 std::shared_ptr<RSData> NetworkImageLoader::LoadImageData(
459 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
460 #endif
461 {
462 auto uri = imageSourceInfo.GetSrc();
463 auto pipelineContext = context.Upgrade();
464 if (!pipelineContext || pipelineContext->IsJsCard()) {
465 TAG_LOGW(AceLogTag::ACE_IMAGE, "network image in JS card is forbidden.");
466 return nullptr;
467 }
468 // 1. find in cache file path.
469 #ifndef USE_ROSEN_DRAWING
470 auto skData = ImageLoader::LoadDataFromCachedFile(uri);
471 if (skData) {
472 return skData;
473 }
474 #else
475 auto drawingData = ImageLoader::LoadDataFromCachedFile(uri);
476 if (drawingData) {
477 return drawingData;
478 }
479 #endif
480
481 // 2. if not found. download it.
482 if (SystemProperties::GetDebugEnabled()) {
483 TAG_LOGI(AceLogTag::ACE_IMAGE, "Download network image, uri=%{public}s", uri.c_str());
484 }
485 std::vector<uint8_t> imageData;
486 if (!DownloadManager::GetInstance()->Download(uri, imageData) || imageData.empty()) {
487 TAG_LOGW(AceLogTag::ACE_IMAGE, "Download network image %{private}s failed!", uri.c_str());
488 return nullptr;
489 }
490 #ifndef USE_ROSEN_DRAWING
491 sk_sp<SkData> data = SkData::MakeWithCopy(imageData.data(), imageData.size());
492 #else
493 auto data = std::make_shared<RSData>();
494 data->BuildWithCopy(imageData.data(), imageData.size());
495 #endif
496 // 3. write it into file cache.
497 WriteCacheToFile(uri, imageData);
498 return data;
499 }
500
501 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)502 sk_sp<SkData> InternalImageLoader::LoadImageData(
503 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
504 #else
505 std::shared_ptr<RSData> InternalImageLoader::LoadImageData(
506 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
507 #endif
508 {
509 size_t imageSize = 0;
510 const uint8_t* internalData =
511 InternalResource::GetInstance().GetResource(imageSourceInfo.GetResourceId(), imageSize);
512 if (internalData == nullptr) {
513 TAG_LOGW(AceLogTag::ACE_IMAGE, "data null, the resource id may be wrong.");
514 return nullptr;
515 }
516 #ifndef USE_ROSEN_DRAWING
517 return SkData::MakeWithCopy(internalData, imageSize);
518 #else
519 auto drawingData = std::make_shared<RSData>();
520 drawingData->BuildWithCopy(internalData, imageSize);
521 return drawingData;
522 #endif
523 }
524
525 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)526 sk_sp<SkData> Base64ImageLoader::LoadImageData(
527 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
528 #else
529 std::shared_ptr<RSData> Base64ImageLoader::LoadImageData(
530 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
531 #endif
532 {
533 std::string_view base64Code = GetBase64ImageCode(imageSourceInfo.GetSrc());
534 if (base64Code.size() == 0) {
535 return nullptr;
536 }
537
538 size_t outputLen;
539 SkBase64::Error error = SkBase64::Decode(base64Code.data(), base64Code.size(), nullptr, &outputLen);
540 if (error != SkBase64::Error::kNoError) {
541 TAG_LOGW(AceLogTag::ACE_IMAGE, "error base64 image code!");
542 return nullptr;
543 }
544
545 #ifndef USE_ROSEN_DRAWING
546 sk_sp<SkData> resData = SkData::MakeUninitialized(outputLen);
547 void* output = resData->writable_data();
548 #else
549 auto resData = std::make_shared<RSData>();
550 resData->BuildUninitialized(outputLen);
551 void* output = resData->WritableData();
552 #endif
553 error = SkBase64::Decode(base64Code.data(), base64Code.size(), output, &outputLen);
554 if (error != SkBase64::Error::kNoError) {
555 TAG_LOGW(AceLogTag::ACE_IMAGE, "error base64 image code!");
556 return nullptr;
557 }
558 return resData;
559 }
560
GetBase64ImageCode(const std::string & uri)561 std::string_view Base64ImageLoader::GetBase64ImageCode(const std::string& uri)
562 {
563 auto iter = uri.find_first_of(',');
564 if (iter == std::string::npos || iter == uri.size() - 1) {
565 TAG_LOGW(AceLogTag::ACE_IMAGE, "wrong code format!");
566 return std::string_view();
567 }
568 // iter + 1 to skip the ","
569 std::string_view code(uri.c_str() + (iter + 1));
570 return code;
571 }
572
GetResourceId(const std::string & uri,uint32_t & resId) const573 bool ResourceImageLoader::GetResourceId(const std::string& uri, uint32_t& resId) const
574 {
575 std::smatch matches;
576 if (std::regex_match(uri, matches, MEDIA_RES_ID_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
577 resId = static_cast<uint32_t>(std::stoul(matches[1].str()));
578 return true;
579 }
580
581 std::smatch appMatches;
582 if (std::regex_match(uri, appMatches, MEDIA_APP_RES_ID_REGEX) && appMatches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
583 resId = static_cast<uint32_t>(std::stoul(appMatches[1].str()));
584 return true;
585 }
586
587 return false;
588 }
589
GetResourceId(const std::string & uri,std::string & path) const590 bool ResourceImageLoader::GetResourceId(const std::string& uri, std::string& path) const
591 {
592 std::smatch matches;
593 if (std::regex_match(uri, matches, MEDIA_APP_RES_PATH_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
594 path = matches[1].str();
595 return true;
596 }
597
598 return false;
599 }
600
GetResourceName(const std::string & uri,std::string & resName) const601 bool ResourceImageLoader::GetResourceName(const std::string& uri, std::string& resName) const
602 {
603 std::smatch matches;
604 if (std::regex_match(uri, matches, MEDIA_RES_NAME_REGEX) && matches.size() == MEDIA_RESOURCE_MATCH_SIZE) {
605 resName = matches[1].str();
606 return true;
607 }
608
609 return false;
610 }
611
612 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)613 sk_sp<SkData> ResourceImageLoader::LoadImageData(
614 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
615 #else
616 std::shared_ptr<RSData> ResourceImageLoader::LoadImageData(
617 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
618 #endif
619 {
620 auto uri = imageSourceInfo.GetSrc();
621 auto bundleName = imageSourceInfo.GetBundleName();
622 auto moudleName = imageSourceInfo.GetModuleName();
623
624 auto resourceObject = AceType::MakeRefPtr<ResourceObject>(bundleName, moudleName);
625 RefPtr<ResourceAdapter> resourceAdapter = nullptr;
626 RefPtr<ThemeConstants> themeConstants = nullptr;
627 if (SystemProperties::GetResourceDecoupling()) {
628 resourceAdapter = ResourceManager::GetInstance().GetOrCreateResourceAdapter(resourceObject);
629 CHECK_NULL_RETURN(resourceAdapter, nullptr);
630 } else {
631 auto themeManager = PipelineBase::CurrentThemeManager();
632 CHECK_NULL_RETURN(themeManager, nullptr);
633 themeConstants = themeManager->GetThemeConstants();
634 CHECK_NULL_RETURN(themeConstants, nullptr);
635 }
636 auto resourceWrapper = AceType::MakeRefPtr<ResourceWrapper>(themeConstants, resourceAdapter);
637
638 std::unique_ptr<uint8_t[]> data;
639 size_t dataLen = 0;
640 std::string rawFile;
641 if (!imageSourceInfo.GetIsUriPureNumber() && GetResourceId(uri, rawFile)) {
642 // must fit raw file firstly, as file name may contains number
643 if (!resourceWrapper->GetRawFileData(rawFile, dataLen, data, bundleName, moudleName)) {
644 TAG_LOGW(AceLogTag::ACE_IMAGE, "get image data by name failed, uri:%{private}s, rawFile:%{public}s",
645 uri.c_str(), rawFile.c_str());
646 return nullptr;
647 }
648 #ifndef USE_ROSEN_DRAWING
649 return SkData::MakeWithCopy(data.get(), dataLen);
650 #else
651 auto drawingData = std::make_shared<RSData>();
652 drawingData->BuildWithCopy(data.get(), dataLen);
653 return drawingData;
654 #endif
655 }
656 uint32_t resId = 0;
657 if (!imageSourceInfo.GetIsUriPureNumber() && GetResourceId(uri, resId)) {
658 if (!resourceWrapper->GetMediaData(resId, dataLen, data, bundleName, moudleName)) {
659 TAG_LOGW(AceLogTag::ACE_IMAGE, "get image data by id failed, uri:%{private}s, id:%{public}u", uri.c_str(),
660 resId);
661 return nullptr;
662 }
663 #ifndef USE_ROSEN_DRAWING
664 return SkData::MakeWithCopy(data.get(), dataLen);
665 #else
666 auto drawingData = std::make_shared<RSData>();
667 drawingData->BuildWithCopy(data.get(), dataLen);
668 return drawingData;
669 #endif
670 }
671 std::string resName;
672 if (GetResourceName(uri, resName)) {
673 if (!resourceWrapper->GetMediaData(resName, dataLen, data, bundleName, moudleName)) {
674 TAG_LOGW(AceLogTag::ACE_IMAGE, "get image data by name failed, uri:%{private}s, resName:%{public}s",
675 uri.c_str(), resName.c_str());
676 return nullptr;
677 }
678 #ifndef USE_ROSEN_DRAWING
679 return SkData::MakeWithCopy(data.get(), dataLen);
680 #else
681 auto drawingData = std::make_shared<RSData>();
682 drawingData->BuildWithCopy(data.get(), dataLen);
683 return drawingData;
684 #endif
685 }
686 TAG_LOGW(AceLogTag::ACE_IMAGE, "load image data failed, as uri is invalid:%{private}s", uri.c_str());
687 return nullptr;
688 }
689
690 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)691 sk_sp<SkData> DecodedDataProviderImageLoader::LoadImageData(
692 const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
693 #else
694 std::shared_ptr<RSData> DecodedDataProviderImageLoader::LoadImageData(
695 const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
696 #endif
697 {
698 return nullptr;
699 }
700
701 // return orientation of pixmap for cache key
GetThumbnailOrientation(const ImageSourceInfo & src)702 std::string DecodedDataProviderImageLoader::GetThumbnailOrientation(const ImageSourceInfo& src)
703 {
704 auto pipeline = PipelineContext::GetCurrentContext();
705 CHECK_NULL_RETURN(pipeline, "");
706 auto dataProvider = pipeline->GetDataProviderManager();
707 CHECK_NULL_RETURN(dataProvider, "");
708
709 // get file fd
710 // concat to get file path ("datashare://media/xx")
711 auto path = src.GetSrc();
712 auto pos = path.find("/thumbnail");
713 path = path.substr(0, pos);
714 int32_t fd = dataProvider->GetDataProviderFile(path, "r");
715 CHECK_NULL_RETURN(fd >= 0, "");
716
717 // check image orientation
718 auto imageSrc = ImageSource::Create(fd);
719 CHECK_NULL_RETURN(imageSrc, "");
720 std::string orientation = imageSrc->GetProperty("Orientation");
721 return orientation;
722 }
723
LoadDecodedImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)724 RefPtr<NG::ImageData> DecodedDataProviderImageLoader::LoadDecodedImageData(
725 const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
726 {
727 #if !defined(PIXEL_MAP_SUPPORTED)
728 return nullptr;
729 #else
730 ACE_FUNCTION_TRACE();
731 auto pipeline = pipelineWk.Upgrade();
732 CHECK_NULL_RETURN(pipeline, nullptr);
733 auto dataProvider = pipeline->GetDataProviderManager();
734 CHECK_NULL_RETURN(dataProvider, nullptr);
735
736 void* pixmapMediaUniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(src.GetSrc());
737 auto pixmap = PixelMap::CreatePixelMapFromDataAbility(pixmapMediaUniquePtr);
738 CHECK_NULL_RETURN(pixmap, nullptr);
739 TAG_LOGI(AceLogTag::ACE_IMAGE,
740 "src=%{public}s, pixmap from Media width*height=%{public}d*%{public}d, ByteCount=%{public}d",
741 src.ToString().c_str(), pixmap->GetWidth(), pixmap->GetHeight(), pixmap->GetByteCount());
742 if (SystemProperties::GetDebugPixelMapSaveEnabled()) {
743 pixmap->SavePixelMapToFile("_fromMedia_");
744 }
745
746 auto cache = pipeline->GetImageCache();
747 if (cache) {
748 cache->CacheImageData(src.GetKey(), MakeRefPtr<NG::PixmapData>(pixmap));
749 }
750 return MakeRefPtr<NG::PixmapData>(pixmap);
751 #endif
752 }
753
754 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)755 sk_sp<SkData> PixelMapImageLoader::LoadImageData(
756 const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
757 #else
758 std::shared_ptr<RSData> PixelMapImageLoader::LoadImageData(
759 const ImageSourceInfo& /* imageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
760 #endif
761 {
762 return nullptr;
763 }
764
LoadDecodedImageData(const ImageSourceInfo & imageSourceInfo,const WeakPtr<PipelineBase> & context)765 RefPtr<NG::ImageData> PixelMapImageLoader::LoadDecodedImageData(
766 const ImageSourceInfo& imageSourceInfo, const WeakPtr<PipelineBase>& context)
767 {
768 #if !defined(PIXEL_MAP_SUPPORTED)
769 return nullptr;
770 #else
771 if (!imageSourceInfo.GetPixmap()) {
772 TAG_LOGW(AceLogTag::ACE_IMAGE, "no pixel map in imageSourceInfo, imageSourceInfo: %{public}s",
773 imageSourceInfo.ToString().c_str());
774 return nullptr;
775 }
776 if (SystemProperties::GetDebugEnabled()) {
777 TAG_LOGI(AceLogTag::ACE_IMAGE, "src is pixmap %{public}s", imageSourceInfo.ToString().c_str());
778 }
779 return MakeRefPtr<NG::PixmapData>(imageSourceInfo.GetPixmap());
780 #endif
781 }
782
783 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWk)784 sk_sp<SkData> SharedMemoryImageLoader::LoadImageData(
785 const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
786 #else
787 std::shared_ptr<RSData> SharedMemoryImageLoader::LoadImageData(
788 const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWk)
789 #endif
790 {
791 CHECK_RUN_ON(BACKGROUND);
792 auto pipeline = pipelineWk.Upgrade();
793 CHECK_NULL_RETURN(pipeline, nullptr);
794 auto manager = pipeline->GetOrCreateSharedImageManager();
795 auto id = RemovePathHead(src.GetSrc());
796 bool found = manager->FindImageInSharedImageMap(id, AceType::WeakClaim(this));
797 // image data not ready yet, wait for data
798 if (!found) {
799 manager->RegisterLoader(id, AceType::WeakClaim(this));
800 // wait for SharedImageManager to notify
801 std::unique_lock<std::mutex> lock(mtx_);
802 auto status = cv_.wait_for(lock, TIMEOUT_DURATION);
803 if (status == std::cv_status::timeout) {
804 TAG_LOGW(AceLogTag::ACE_IMAGE, "load SharedMemoryImage timeout! %{public}s", src.ToString().c_str());
805 return nullptr;
806 }
807 }
808
809 std::unique_lock<std::mutex> lock(mtx_);
810 #ifndef USE_ROSEN_DRAWING
811 auto skData = SkData::MakeWithCopy(data_.data(), data_.size());
812 return skData;
813 #else
814 auto drawingData = std::make_shared<RSData>();
815 drawingData->BuildWithCopy(data_.data(), data_.size());
816 return drawingData;
817 #endif
818 }
819
UpdateData(const std::string & uri,const std::vector<uint8_t> & memData)820 void SharedMemoryImageLoader::UpdateData(const std::string& uri, const std::vector<uint8_t>& memData)
821 {
822 TAG_LOGI(AceLogTag::ACE_IMAGE, "SharedMemory image data is ready %{public}s", uri.c_str());
823 {
824 std::scoped_lock<std::mutex> lock(mtx_);
825 data_ = memData;
826 }
827
828 cv_.notify_one();
829 }
830
831 #ifndef USE_ROSEN_DRAWING
LoadImageData(const ImageSourceInfo &,const WeakPtr<PipelineBase> &)832 sk_sp<SkData> AstcImageLoader::LoadImageData(
833 const ImageSourceInfo& /* ImageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
834 #else
835 std::shared_ptr<RSData> AstcImageLoader::LoadImageData(
836 const ImageSourceInfo& /* ImageSourceInfo */, const WeakPtr<PipelineBase>& /* context */)
837 #endif
838 {
839 return nullptr;
840 }
841
LoadDecodedImageData(const ImageSourceInfo & src,const WeakPtr<PipelineBase> & pipelineWK)842 RefPtr<NG::ImageData> AstcImageLoader::LoadDecodedImageData(
843 const ImageSourceInfo& src, const WeakPtr<PipelineBase>& pipelineWK)
844 {
845 #if !defined(PIXEL_MAP_SUPPORTED)
846 return nullptr;
847 #else
848 auto pipeline = pipelineWK.Upgrade();
849 CHECK_NULL_RETURN(pipeline, nullptr);
850 auto dataProvider = pipeline->GetDataProviderManager();
851 CHECK_NULL_RETURN(dataProvider, nullptr);
852
853 void* pixmapMediaUniquePtr = dataProvider->GetDataProviderThumbnailResFromUri(src.GetSrc());
854 auto pixmap = PixelMap::CreatePixelMapFromDataAbility(pixmapMediaUniquePtr);
855 CHECK_NULL_RETURN(pixmap, nullptr);
856
857 auto cache = pipeline->GetImageCache();
858 if (cache) {
859 cache->CacheImageData(src.GetKey(), MakeRefPtr<NG::PixmapData>(pixmap));
860 }
861 return MakeRefPtr<NG::PixmapData>(pixmap);
862 #endif
863 }
864
GetThumbnailOrientation(const ImageSourceInfo & src)865 std::string AstcImageLoader::GetThumbnailOrientation(const ImageSourceInfo& src)
866 {
867 auto pipeline = PipelineContext::GetCurrentContext();
868 CHECK_NULL_RETURN(pipeline, "");
869 auto dataProvider = pipeline->GetDataProviderManager();
870 CHECK_NULL_RETURN(dataProvider, "");
871
872 auto path = src.GetSrc();
873 auto pos = path.find("/astc");
874 path = path.substr(0, pos);
875 int32_t fd = dataProvider->GetDataProviderFile(path, "r");
876 CHECK_NULL_RETURN(fd >= 0, "");
877
878 auto imageSrc = ImageSource::Create(fd);
879 CHECK_NULL_RETURN(imageSrc, "");
880 std::string orientation = imageSrc->GetProperty("Orientation");
881 return orientation;
882 }
883
WriteCacheToFile(const std::string & uri,const std::vector<uint8_t> & imageData)884 void ImageLoader::WriteCacheToFile(const std::string& uri, const std::vector<uint8_t>& imageData)
885 {
886 BackgroundTaskExecutor::GetInstance().PostTask(
887 [uri, data = std::move(imageData)]() {
888 ImageFileCache::GetInstance().WriteCacheFile(uri, data.data(), data.size());
889 },
890 BgTaskPriority::LOW);
891 }
892
WriteCacheToFile(const std::string & uri,const std::string & imageData)893 void ImageLoader::WriteCacheToFile(const std::string& uri, const std::string& imageData)
894 {
895 BackgroundTaskExecutor::GetInstance().PostTask(
896 [uri, data = std::move(imageData)]() {
897 ImageFileCache::GetInstance().WriteCacheFile(uri, data.data(), data.size());
898 },
899 BgTaskPriority::LOW);
900 }
901 } // namespace OHOS::Ace
902