1 /*
2 * Copyright (c) 2024 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 "image_loader_manager.h"
17
18 #include <algorithm>
19 #include <cstring>
20
21 #include <base/containers/array_view.h>
22 #include <base/containers/iterator.h>
23 #include <base/containers/string_view.h>
24 #include <base/containers/type_traits.h>
25 #include <base/containers/unique_ptr.h>
26 #include <base/containers/vector.h>
27 #include <base/namespace.h>
28 #include <core/image/intf_animated_image.h>
29 #include <core/image/intf_image_container.h>
30 #include <core/image/intf_image_loader_manager.h>
31 #include <core/io/intf_file.h>
32 #include <core/io/intf_file_manager.h>
33 #include <core/log.h>
34 #include <core/namespace.h>
35 #include <core/perf/cpu_perf_scope.h>
36
37 CORE_BEGIN_NAMESPACE()
38 using BASE_NS::array_view;
39 using BASE_NS::make_unique;
40 using BASE_NS::move;
41 using BASE_NS::string_view;
42 using BASE_NS::unique_ptr;
43 using BASE_NS::vector;
44
ImageLoaderManager(IFileManager & fileManager)45 ImageLoaderManager::ImageLoaderManager(IFileManager& fileManager) : fileManager_(fileManager)
46 {
47 for (const auto* typeInfo : GetPluginRegister().GetTypeInfos(IImageLoaderManager::ImageLoaderTypeInfo::UID)) {
48 if (typeInfo && (typeInfo->typeUid == IImageLoaderManager::ImageLoaderTypeInfo::UID)) {
49 const auto* imageLoaderInfo = static_cast<const IImageLoaderManager::ImageLoaderTypeInfo*>(typeInfo);
50 if (imageLoaderInfo->createLoader &&
51 std::none_of(imageLoaders_.cbegin(), imageLoaders_.cend(),
52 [&uid = imageLoaderInfo->uid](const RegisteredImageLoader& loader) { return loader.uid == uid; })) {
53 imageLoaders_.push_back(
54 { imageLoaderInfo->uid, imageLoaderInfo->createLoader(imageLoaderInfo->token) });
55 }
56 }
57 }
58 GetPluginRegister().AddListener(*this);
59 }
~ImageLoaderManager()60 ImageLoaderManager::~ImageLoaderManager()
61 {
62 GetPluginRegister().RemoveListener(*this);
63 }
RegisterImageLoader(IImageLoader::Ptr imageLoader)64 void ImageLoaderManager::RegisterImageLoader(IImageLoader::Ptr imageLoader)
65 {
66 if (!imageLoader) {
67 CORE_LOG_D("imageLoader is null, Not adding.");
68 return;
69 }
70
71 // NOTE: We just add the registered unique pointers to a vector. The vector is not really used for anything else.
72 // And the loaders cannot be currently unregistered.
73 imageLoaders_.push_back({ {}, move(imageLoader) });
74 }
75
LoadImage(const string_view uri,uint32_t loadFlags)76 ImageLoaderManager::LoadResult ImageLoaderManager::LoadImage(const string_view uri, uint32_t loadFlags)
77 {
78 CORE_CPU_PERF_SCOPE("Image", "loadImage()", uri);
79
80 // Load 12 bytes (maximum header size of currently implemented file types)
81 IFile::Ptr file = fileManager_.OpenFile(uri);
82 if (!file) {
83 return ResultFailure("Can not open image.");
84 }
85
86 return LoadImage(*file, loadFlags);
87 }
88
LoadImage(IFile & file,uint32_t loadFlags)89 ImageLoaderManager::LoadResult ImageLoaderManager::LoadImage(IFile& file, uint32_t loadFlags)
90 {
91 CORE_CPU_PERF_SCOPE("Image", "loadImage()", "file");
92
93 const uint64_t byteLength = 12u;
94
95 // Read header of the file to a buffer.
96 unique_ptr<uint8_t[]> buffer = make_unique<uint8_t[]>(static_cast<size_t>(byteLength));
97 const uint64_t read = file.Read(buffer.get(), byteLength);
98 if (read != byteLength) {
99 return ResultFailure("Can not read file header.");
100 }
101 file.Seek(0);
102
103 for (auto& loader : imageLoaders_) {
104 if (loader.instance &&
105 loader.instance->CanLoad(array_view<const uint8_t>(buffer.get(), static_cast<size_t>(byteLength)))) {
106 return loader.instance->Load(file, loadFlags);
107 }
108 }
109 return ResultFailure("Image loader not found for this format.");
110 }
111
LoadImage(array_view<const uint8_t> imageFileBytes,uint32_t loadFlags)112 ImageLoaderManager::LoadResult ImageLoaderManager::LoadImage(
113 array_view<const uint8_t> imageFileBytes, uint32_t loadFlags)
114 {
115 CORE_CPU_PERF_SCOPE("Image", "loadImage(bytes)", "memory");
116 if (imageFileBytes.empty()) {
117 return ResultFailure("Image loader can't load from empty buffer.");
118 }
119 for (auto it=imageLoaders_.cbegin(); it!=imageLoaders_.cend(); ++it) { // this works fine!
120 const auto& loader = *it;
121 if (loader.instance) {
122 if (loader.instance->CanLoad(imageFileBytes)) {
123 return loader.instance->Load(imageFileBytes, loadFlags);
124 }
125 }
126 }
127
128 return ResultFailure("Image loader not found for this format.");
129 }
130
LoadAnimatedImage(const string_view uri,uint32_t loadFlags)131 ImageLoaderManager::LoadAnimatedResult ImageLoaderManager::LoadAnimatedImage(const string_view uri, uint32_t loadFlags)
132 {
133 CORE_CPU_PERF_SCOPE("Image", "loadAnimatedImage()", uri);
134
135 // Load 12 bytes (maximum header size of currently implemented file types)
136 IFile::Ptr file = fileManager_.OpenFile(uri);
137 if (!file) {
138 return ResultFailureAnimated("Can not open image.");
139 }
140
141 return LoadAnimatedImage(*file, loadFlags);
142 }
143
LoadAnimatedImage(IFile & file,uint32_t loadFlags)144 ImageLoaderManager::LoadAnimatedResult ImageLoaderManager::LoadAnimatedImage(IFile& file, uint32_t loadFlags)
145 {
146 CORE_CPU_PERF_SCOPE("Image", "loadAnimatedImage()", "file");
147
148 const uint64_t byteLength = 12u;
149
150 // Read header of the file to a buffer.
151 unique_ptr<uint8_t[]> buffer = make_unique<uint8_t[]>(static_cast<size_t>(byteLength));
152 const uint64_t read = file.Read(buffer.get(), byteLength);
153 if (read != byteLength) {
154 return ResultFailureAnimated("Can not read file header.");
155 }
156 file.Seek(0);
157
158 for (auto& loader : imageLoaders_) {
159 if (loader.instance->CanLoad(array_view<const uint8_t>(buffer.get(), static_cast<size_t>(byteLength)))) {
160 return loader.instance->LoadAnimatedImage(file, loadFlags);
161 }
162 }
163 return ResultFailureAnimated("Image loader not found for this format.");
164 }
165
LoadAnimatedImage(array_view<const uint8_t> imageFileBytes,uint32_t loadFlags)166 ImageLoaderManager::LoadAnimatedResult ImageLoaderManager::LoadAnimatedImage(
167 array_view<const uint8_t> imageFileBytes, uint32_t loadFlags)
168 {
169 CORE_CPU_PERF_SCOPE("Image", "loadAnimatedImage(bytes)", "memory");
170
171 for (auto& loader : imageLoaders_) {
172 if (loader.instance->CanLoad(imageFileBytes)) {
173 return loader.instance->LoadAnimatedImage(imageFileBytes, loadFlags);
174 }
175 }
176
177 return ResultFailureAnimated("Image loader not found for this format.");
178 }
179
ResultFailure(const string_view error)180 ImageLoaderManager::LoadResult ImageLoaderManager::ResultFailure(const string_view error)
181 {
182 LoadResult result {
183 false, // if success
184 "", // array error[128];
185 nullptr // the image;
186 };
187
188 // Copy the error string
189 const auto count = std::min(error.size(), sizeof(result.error) - 1);
190 error.copy(result.error, count);
191 result.error[count] = '\0';
192
193 return result;
194 }
195
ResultSuccess(IImageContainer::Ptr image)196 ImageLoaderManager::LoadResult ImageLoaderManager::ResultSuccess(IImageContainer::Ptr image)
197 {
198 return LoadResult {
199 true, // if success
200 "", // array error[128];
201 move(image) // the image;
202 };
203 }
204
ResultFailureAnimated(const string_view error)205 ImageLoaderManager::LoadAnimatedResult ImageLoaderManager::ResultFailureAnimated(const string_view error)
206 {
207 LoadAnimatedResult result {
208 false, // if success
209 "", // array error[128];
210 nullptr // the image;
211 };
212
213 // Copy the error string
214 const auto count = std::min(error.size(), sizeof(result.error) - 1);
215 error.copy(result.error, count);
216 result.error[count] = '\0';
217
218 return result;
219 }
220
ResultSuccessAnimated(IAnimatedImage::Ptr image)221 ImageLoaderManager::LoadAnimatedResult ImageLoaderManager::ResultSuccessAnimated(IAnimatedImage::Ptr image)
222 {
223 return LoadAnimatedResult {
224 true, // if success
225 "", // array error[128];
226 move(image) // the image;
227 };
228 }
229
GetSupportedTypes() const230 vector<IImageLoaderManager::ImageType> ImageLoaderManager::GetSupportedTypes() const
231 {
232 vector<IImageLoaderManager::ImageType> allTypes;
233 for (const auto& loader : imageLoaders_) {
234 const auto types = loader.instance->GetSupportedTypes();
235 allTypes.append(types.cbegin(), types.cend());
236 }
237 return allTypes;
238 }
OnTypeInfoEvent(EventType type,array_view<const ITypeInfo * const> typeInfos)239 void ImageLoaderManager::OnTypeInfoEvent(EventType type, array_view<const ITypeInfo* const> typeInfos)
240 {
241 for (const auto* typeInfo : typeInfos) {
242 if (typeInfo && (typeInfo->typeUid == IImageLoaderManager::ImageLoaderTypeInfo::UID)) {
243 const auto* imageLoaderInfo = static_cast<const IImageLoaderManager::ImageLoaderTypeInfo*>(typeInfo);
244 if (type == EventType::ADDED) {
245 if (imageLoaderInfo->createLoader &&
246 std::none_of(imageLoaders_.cbegin(), imageLoaders_.cend(),
247 [&uid = imageLoaderInfo->uid](
248 const RegisteredImageLoader& loader) { return loader.uid == uid; })) {
249 imageLoaders_.push_back(
250 { imageLoaderInfo->uid, imageLoaderInfo->createLoader(imageLoaderInfo->token) });
251 }
252 } else if (type == EventType::REMOVED) {
253 imageLoaders_.erase(std::remove_if(imageLoaders_.begin(), imageLoaders_.end(),
254 [&uid = imageLoaderInfo->uid](const RegisteredImageLoader& loader) { return loader.uid == uid; }),
255 imageLoaders_.cend());
256 }
257 }
258 }
259 }
260 CORE_END_NAMESPACE()
261