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