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