|
| 1 | +Dưới đây là hướng dẫn chi tiết cách build `rlottie` và tạo binding Python để tích hợp với **Mouse Pet** sử dụng hoạt ảnh từ Lottie: |
| 2 | + |
| 3 | +--- |
| 4 | + |
| 5 | +## 🛠️ 1. Build `rlottie` từ source |
| 6 | + |
| 7 | +`rlottie` là một thư viện nhẹ, hiệu suất cao để hiển thị các hoạt ảnh Lottie (JSON vector animation). Để tích hợp được vào Python, bạn cần build thư viện này dưới dạng shared object (`.so` hoặc `.dll`). |
| 8 | + |
| 9 | +### Bước 1. Clone `rlottie` |
| 10 | + |
| 11 | +```bash |
| 12 | +git clone https://github.com/Samsung/rlottie.git |
| 13 | +cd rlottie |
| 14 | +``` |
| 15 | + |
| 16 | +### Bước 2. Tạo thư mục build và compile |
| 17 | + |
| 18 | +```bash |
| 19 | +mkdir build |
| 20 | +cd build |
| 21 | +cmake .. |
| 22 | +make -j$(nproc) |
| 23 | +``` |
| 24 | + |
| 25 | +Sau khi build thành công, bạn sẽ có: |
| 26 | + |
| 27 | +* `build/src/librlottie.so` (Linux) |
| 28 | +* `build/src/Debug/rlottie.dll` (Windows, nếu build bằng MSVC) |
| 29 | +* `build/src/librlottie.dylib` (macOS) |
| 30 | + |
| 31 | +--- |
| 32 | + |
| 33 | +## 🧩 2. Tạo binding Python với `ctypes` (hoặc `cffi`/`pybind11`) |
| 34 | + |
| 35 | +Ở đây ta sẽ dùng `ctypes` cho đơn giản, nhưng bạn có thể chuyển sang `pybind11` nếu muốn binding mạnh hơn. |
| 36 | + |
| 37 | +### Bước 1. Giao diện C đơn giản để gọi từ Python |
| 38 | + |
| 39 | +Trong thư mục `rlottie/src`, tạo file mới `rlottie_capi.h`: |
| 40 | + |
| 41 | +```c |
| 42 | +#ifdef __cplusplus |
| 43 | +extern "C" { |
| 44 | +#endif |
| 45 | + |
| 46 | +void* rlottie_from_file(const char* filename, int width, int height); |
| 47 | +bool rlottie_render_frame(void* player, size_t frame_num, uint32_t* buffer); |
| 48 | +size_t rlottie_total_frames(void* player); |
| 49 | +void rlottie_destroy(void* player); |
| 50 | + |
| 51 | +#ifdef __cplusplus |
| 52 | +} |
| 53 | +#endif |
| 54 | +``` |
| 55 | +
|
| 56 | +Sau đó thêm file tương ứng `rlottie_capi.cpp`: |
| 57 | +
|
| 58 | +```cpp |
| 59 | +#include "rlottie_capi.h" |
| 60 | +#include "lottieplayer.h" |
| 61 | +
|
| 62 | +void* rlottie_from_file(const char* filename, int width, int height) { |
| 63 | + auto player = new LOTLayer(); |
| 64 | + player->loadFromFile(filename, width, height); |
| 65 | + return static_cast<void*>(player); |
| 66 | +} |
| 67 | +
|
| 68 | +bool rlottie_render_frame(void* player, size_t frame_num, uint32_t* buffer) { |
| 69 | + auto p = static_cast<LOTLayer*>(player); |
| 70 | + if (!p) return false; |
| 71 | + return p->render(frame_num, buffer); |
| 72 | +} |
| 73 | +
|
| 74 | +size_t rlottie_total_frames(void* player) { |
| 75 | + auto p = static_cast<LOTLayer*>(player); |
| 76 | + return p ? p->totalFrames() : 0; |
| 77 | +} |
| 78 | +
|
| 79 | +void rlottie_destroy(void* player) { |
| 80 | + delete static_cast<LOTLayer*>(player); |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +Thêm những file này vào CMakeLists.txt: |
| 85 | + |
| 86 | +```cmake |
| 87 | +add_library(rlottie_capi SHARED rlottie_capi.cpp) |
| 88 | +target_link_libraries(rlottie_capi rlottie) |
| 89 | +``` |
| 90 | + |
| 91 | +Build lại: |
| 92 | + |
| 93 | +```bash |
| 94 | +cd build |
| 95 | +cmake .. |
| 96 | +make -j$(nproc) |
| 97 | +``` |
| 98 | + |
| 99 | +--- |
| 100 | + |
| 101 | +## 🐍 3. Gọi từ Python bằng `ctypes` |
| 102 | + |
| 103 | +Ví dụ đơn giản sử dụng binding: |
| 104 | + |
| 105 | +```python |
| 106 | +import ctypes |
| 107 | +import numpy as np |
| 108 | + |
| 109 | +lib = ctypes.CDLL('./build/src/librlottie_capi.so') |
| 110 | + |
| 111 | +# prototype |
| 112 | +lib.rlottie_from_file.restype = ctypes.c_void_p |
| 113 | +lib.rlottie_render_frame.argtypes = [ctypes.c_void_p, ctypes.c_size_t, ctypes.POINTER(ctypes.c_uint32)] |
| 114 | +lib.rlottie_total_frames.argtypes = [ctypes.c_void_p] |
| 115 | +lib.rlottie_total_frames.restype = ctypes.c_size_t |
| 116 | +lib.rlottie_destroy.argtypes = [ctypes.c_void_p] |
| 117 | + |
| 118 | +# load animation |
| 119 | +player = lib.rlottie_from_file(b"example.json", 128, 128) |
| 120 | +frame_count = lib.rlottie_total_frames(player) |
| 121 | + |
| 122 | +for frame in range(frame_count): |
| 123 | + buffer = (ctypes.c_uint32 * (128 * 128))() |
| 124 | + lib.rlottie_render_frame(player, frame, buffer) |
| 125 | + |
| 126 | + image = np.ctypeslib.as_array(buffer).reshape((128, 128)) |
| 127 | + # sử dụng image như một frame RGBA32 |
| 128 | + |
| 129 | +lib.rlottie_destroy(player) |
| 130 | +``` |
| 131 | + |
| 132 | +--- |
| 133 | + |
| 134 | +## ✅ Gợi ý tích hợp |
| 135 | + |
| 136 | +* Đưa đoạn render frame vào `QImage.fromData()` hoặc `QPixmap.fromImage()` trong PyQt/PySide để gắn lên màn hình. |
| 137 | +* Kết hợp với `QTimer` để điều khiển animation. |
| 138 | +* Có thể cache frame để tăng hiệu suất với các hoạt ảnh ngắn lặp lại. |
| 139 | + |
| 140 | +--- |
| 141 | + |
| 142 | +Nếu bạn muốn binding mạnh hơn (e.g. object-oriented, truyền thông tin vector hoặc gradient), hãy dùng `pybind11`. |
0 commit comments