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