1 #include "vimageloader.h"
2 #include "config.h"
3 #include "vdebug.h"
4 #include <cstring>
5
6 #ifdef _WIN32
7 # include <windows.h>
8 #else
9 # include <dlfcn.h>
10 #endif // _WIN32
11
12 using lottie_image_load_f = unsigned char *(*)(const char *filename, int *x,
13 int *y, int *comp, int req_comp);
14 using lottie_image_load_data_f = unsigned char *(*)(const char *data, int len,
15 int *x, int *y, int *comp,
16 int req_comp);
17 using lottie_image_free_f = void (*)(unsigned char *);
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 extern unsigned char *lottie_image_load(char const *filename, int *x, int *y,
24 int *comp, int req_comp);
25 extern unsigned char *lottie_image_load_from_data(const char *imageData,
26 int len, int *x, int *y,
27 int *comp, int req_comp);
28 extern void lottie_image_free(unsigned char *data);
29
30 #ifdef __cplusplus
31 }
32 #endif
33
34 struct VImageLoader::Impl {
35 lottie_image_load_f imageLoad{nullptr};
36 lottie_image_free_f imageFree{nullptr};
37 lottie_image_load_data_f imageFromData{nullptr};
38
39 #ifdef LOTTIE_IMAGE_MODULE_SUPPORT
40 # ifdef _WIN32
41 HMODULE dl_handle{nullptr};
moduleLoadVImageLoader::Impl42 bool moduleLoad()
43 {
44 dl_handle = LoadLibraryA(LOTTIE_IMAGE_MODULE_PLUGIN);
45 return (dl_handle == nullptr);
46 }
moduleFreeVImageLoader::Impl47 void moduleFree()
48 {
49 if (dl_handle) FreeLibrary(dl_handle);
50 }
initVImageLoader::Impl51 void init()
52 {
53 imageLoad = reinterpret_cast<lottie_image_load_f>(
54 GetProcAddress(dl_handle, "lottie_image_load"));
55 imageFree = reinterpret_cast<lottie_image_free_f>(
56 GetProcAddress(dl_handle, "lottie_image_free"));
57 imageFromData = reinterpret_cast<lottie_image_load_data_f>(
58 GetProcAddress(dl_handle, "lottie_image_load_from_data"));
59 }
60 # else // _WIN32
61 void *dl_handle{nullptr};
initVImageLoader::Impl62 void init()
63 {
64 imageLoad = reinterpret_cast<lottie_image_load_f>(
65 dlsym(dl_handle, "lottie_image_load"));
66 imageFree = reinterpret_cast<lottie_image_free_f>(
67 dlsym(dl_handle, "lottie_image_free"));
68 imageFromData = reinterpret_cast<lottie_image_load_data_f>(
69 dlsym(dl_handle, "lottie_image_load_from_data"));
70 }
71
moduleFreeVImageLoader::Impl72 void moduleFree()
73 {
74 if (dl_handle) dlclose(dl_handle);
75 }
moduleLoadVImageLoader::Impl76 bool moduleLoad()
77 {
78 dl_handle = dlopen(LOTTIE_IMAGE_MODULE_PLUGIN, RTLD_LAZY);
79 return (dl_handle == nullptr);
80 }
81 # endif // _WIN32
82 #else // LOTTIE_IMAGE_MODULE_SUPPORT
initVImageLoader::Impl83 void init()
84 {
85 imageLoad = lottie_image_load;
86 imageFree = lottie_image_free;
87 imageFromData = lottie_image_load_from_data;
88 }
moduleFreeVImageLoader::Impl89 void moduleFree() {}
moduleLoadVImageLoader::Impl90 bool moduleLoad() { return false; }
91 #endif // LOTTIE_IMAGE_MODULE_SUPPORT
92
ImplVImageLoader::Impl93 Impl()
94 {
95 if (moduleLoad()) {
96 vWarning << "Failed to dlopen librlottie-image-loader library";
97 return;
98 }
99
100 init();
101
102 if (!imageLoad)
103 vWarning << "Failed to find symbol lottie_image_load in "
104 "librlottie-image-loader library";
105
106 if (!imageFree)
107 vWarning << "Failed to find symbol lottie_image_free in "
108 "librlottie-image-loader library";
109
110 if (!imageFromData)
111 vWarning << "Failed to find symbol lottie_image_load_data in "
112 "librlottie-image-loader library";
113 }
114
~ImplVImageLoader::Impl115 ~Impl() { moduleFree(); }
116
createBitmapVImageLoader::Impl117 VBitmap createBitmap(unsigned char *data, int width, int height,
118 int channel)
119 {
120 // premultiply alpha
121 if (channel == 4)
122 convertToBGRAPremul(data, width, height);
123 else
124 convertToBGRA(data, width, height);
125
126 // create a bitmap of same size.
127 VBitmap result =
128 VBitmap(width, height, VBitmap::Format::ARGB32_Premultiplied);
129
130 // copy the data to bitmap buffer
131 memcpy(result.data(), data, width * height * 4);
132
133 // free the image data
134 imageFree(data);
135
136 return result;
137 }
138
loadVImageLoader::Impl139 VBitmap load(const char *fileName)
140 {
141 if (!imageLoad) return VBitmap();
142
143 int width, height, n;
144 unsigned char *data = imageLoad(fileName, &width, &height, &n, 4);
145
146 if (!data) {
147 return VBitmap();
148 }
149
150 return createBitmap(data, width, height, n);
151 }
152
loadVImageLoader::Impl153 VBitmap load(const char *imageData, size_t len)
154 {
155 if (!imageFromData) return VBitmap();
156
157 int width, height, n;
158 unsigned char *data =
159 imageFromData(imageData, static_cast<int>(len), &width, &height, &n, 4);
160
161 if (!data) {
162 return VBitmap();
163 }
164
165 return createBitmap(data, width, height, n);
166 }
167 /*
168 * convert from RGBA to BGRA and premultiply
169 */
convertToBGRAPremulVImageLoader::Impl170 void convertToBGRAPremul(unsigned char *bits, int width, int height)
171 {
172 int pixelCount = width * height;
173 unsigned char *pix = bits;
174 for (int i = 0; i < pixelCount; i++) {
175 unsigned char r = pix[0];
176 unsigned char g = pix[1];
177 unsigned char b = pix[2];
178 unsigned char a = pix[3];
179
180 r = (r * a) / 255;
181 g = (g * a) / 255;
182 b = (b * a) / 255;
183
184 pix[0] = b;
185 pix[1] = g;
186 pix[2] = r;
187
188 pix += 4;
189 }
190 }
191 /*
192 * convert from RGBA to BGRA
193 */
convertToBGRAVImageLoader::Impl194 void convertToBGRA(unsigned char *bits, int width, int height)
195 {
196 int pixelCount = width * height;
197 unsigned char *pix = bits;
198 for (int i = 0; i < pixelCount; i++) {
199 unsigned char r = pix[0];
200 unsigned char b = pix[2];
201 pix[0] = b;
202 pix[2] = r;
203 pix += 4;
204 }
205 }
206 };
207
VImageLoader()208 VImageLoader::VImageLoader() : mImpl(std::make_unique<VImageLoader::Impl>()) {}
209
~VImageLoader()210 VImageLoader::~VImageLoader() {}
211
load(const char * fileName)212 VBitmap VImageLoader::load(const char *fileName)
213 {
214 return mImpl->load(fileName);
215 }
216
load(const char * data,size_t len)217 VBitmap VImageLoader::load(const char *data, size_t len)
218 {
219 return mImpl->load(data, int(len));
220 }
221