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