• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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