blob: 29098dac44d2bd1baec5ed7d6a8dea929a413b84 [file] [log] [blame]
b.liu90f385f2025-02-20 19:57:52 +08001#include <stdio.h>
2#include <unistd.h>
3#include <stdlib.h>
4#include <errno.h>
5#include <string.h>
6#include <sys/types.h>
7#include <sys/stat.h>
8#include <fcntl.h>
9#include <stdint.h>
10
11#include "logo_partition.h"
12
13#pragma pack(push, 1) // 取消结构体对齐
14typedef struct {
15 uint16_t bfType; // 文件类型,应为"BM"(0x4D42)
16 uint32_t bfSize; // 文件总大小
17 uint16_t bfReserved1; // 保留字段
18 uint16_t bfReserved2;
19 uint32_t bfOffBits; // 像素数据偏移量
20} BITMAPFILEHEADER;
21
22typedef struct {
23 uint32_t biSize; // 信息头大小(通常为40)
24 int32_t biWidth; // 图像宽度(像素)
25 int32_t biHeight; // 图像高度(像素)
26 uint16_t biPlanes; // 颜色平面数(必须为1)
27 uint16_t biBitCount; // 每像素位数(如24表示RGB)
28 uint32_t biCompression; // 压缩类型(0表示无压缩)
29 uint32_t biSizeImage; // 像素数据大小(含填充)
30 int32_t biXPelsPerMeter;// 水平分辨率(像素/米)
31 int32_t biYPelsPerMeter;// 垂直分辨率
32 uint32_t biClrUsed; // 实际使用的颜色数
33 uint32_t biClrImportant; // 重要颜色数
34} BITMAPINFOHEADER;
35#pragma pack(pop)
36
b.liuffb01e02025-03-05 14:28:10 +080037#define ANIM_PIC_MAX 100 // 开机动画的最大图片数量 (1.bmp - 100.bmp)
b.liu90f385f2025-02-20 19:57:52 +080038
39static mbtk_logo_header_t logo_header = {
40 .addr = LOGO_ADDR_START,
41 .pic_width = 240,
42 .pic_height = 320,
43 .bg_rgb = 0x00000000 // black
44};
45
46static mbtk_animation_header_t animation_header = {
47 .addr = ANIMATION_ADDR_START,
b.liuffb01e02025-03-05 14:28:10 +080048 .pic_num = 0, // Max is ANIM_PIC_MAX
b.liu90f385f2025-02-20 19:57:52 +080049 .pic_width = 240,
50 .pic_height = 320,
b.liu0c2d03b2025-02-26 16:53:44 +080051 .waitting_time = 0, // ms
b.liuffb01e02025-03-05 14:28:10 +080052 .frame_show_num = 0, // show forever
b.liu90f385f2025-02-20 19:57:52 +080053 .bg_rgb = 0x00000000 // black
54};
55
56static int is_directory_exists(const char *path) {
57 struct stat stats;
58 if (stat(path, &stats) == 0 && S_ISDIR(stats.st_mode)) {
59 return 1; // 目录存在
60 }
61 printf("%s not exists.\n", path);
62 return 0; // 目录不存在或路径是文件
63}
64
65static void help()
66{
67 //printf("logo_partition_generate [pic_dir] -a [logo_w] -b [logo_h] -c [logo_bg] -d [anim_num] -e [anim_w] -f [anim_h] -g [anim_rate] -i [anim_bg]\n");
b.liu0c2d03b2025-02-26 16:53:44 +080068 printf("logo_partition_generate [pic_dir] -a [logo_bg] -b [waitting_time(ms)] -c [anim_bg] -d [frame_show_num]\n");
b.liu90f385f2025-02-20 19:57:52 +080069}
70
71static int bmp_read(const char* file_name, uint32 *width, uint32 *height, char *buff, int buff_size)
72{
73 FILE* file = fopen(file_name, "rb");
74 if (!file) return 0; // 文件不存在
75
76 // 读取文件头和信息头
77 BITMAPFILEHEADER file_header;
78 BITMAPINFOHEADER info_header;
79 fread(&file_header, sizeof(file_header), 1, file);
80 fread(&info_header, sizeof(info_header), 1, file);
81
82 // 验证是否为BMP文件
83 if (file_header.bfType != 0x4D42) {
84 fclose(file);
85 return -1;
86 }
87
88 // 仅支持24位无压缩格式
89 if (info_header.biBitCount != 24 || info_header.biCompression != 0) {
90 fclose(file);
91 return -1;
92 }
93
94 *width = info_header.biWidth;
95 *height = abs(info_header.biHeight); // 高度可能为负(表示从上到下存储)
96
97 // 计算每行实际字节数(含4字节对齐填充)
98 uint32_t row_size = ((info_header.biWidth * 3 + 3) / 4) * 4; // [[9, 18]]
99 uint32_t data_size = row_size * abs(info_header.biHeight); // [[9, 17]]
100 if(buff_size < data_size) {
101 printf("buff_size too small...");
102 return -1;
103 }
104
105 // 分配内存并读取像素数据
106 fseek(file, file_header.bfOffBits, SEEK_SET); // 定位到数据区 [[2, 8, 15]]
b.liu0c2d03b2025-02-26 16:53:44 +0800107#if 0
b.liu90f385f2025-02-20 19:57:52 +0800108 fread(buff, 1, data_size, file);
b.liu0c2d03b2025-02-26 16:53:44 +0800109#else
110 // bmp中y轴是反的,所以从最下面一行开始依次读取一行数据。
111 int line_size = info_header.biWidth * 3;
112 for(int y = info_header.biHeight - 1; y >= 0; y--) {
113 fread(buff + y * line_size, 1, line_size, file);
114 }
115#endif
b.liu90f385f2025-02-20 19:57:52 +0800116 fclose(file);
117
118 return data_size;
119}
120
121static int write_header(int fd, mbtk_logo_header_t *logo_h, mbtk_animation_header_t *anim_h)
122{
123 if(-1 == lseek(fd, 0, SEEK_SET)) {
124 printf("lseek() fail:%d\n", errno);
125 return -1;
126 }
127
128 if(sizeof(mbtk_logo_header_t) != write(fd, logo_h, sizeof(mbtk_logo_header_t))) {
129 printf("Write logo header fail:%d\n", errno);
130 return -1;
131 }
132
133 if(sizeof(mbtk_animation_header_t) != write(fd, anim_h, sizeof(mbtk_animation_header_t))) {
134 printf("Write anim header fail:%d\n", errno);
135 return -1;
136 }
137
138 return 0;
139}
140
141static int write_item_logo(int fd, const char *dir, mbtk_logo_header_t *logo_h)
142{
143 if(-1 == lseek(fd, logo_h->addr, SEEK_SET)) {
144 printf("lseek() fail:%d\n", errno);
145 return -1;
146 }
147
148 char pic_name[256] = {0};
149 char buff[4 * 1024 * 1024] = {0}; // 4MB
150 int len = 0;
151 snprintf(pic_name, sizeof(pic_name), "%s/%s", dir, "logo.bmp");
152 if((len = bmp_read(pic_name, &(logo_h->pic_width), &(logo_h->pic_height), buff, sizeof(buff))) <= 0) {
153 printf("bmp_read() fail.\n");
154 return -1;
155 }
156
157 if(len != write(fd, buff, len)) {
158 printf("Write logo buffer fail:%d\n", errno);
159 return -1;
160 }
161
162 return 0;
163}
164
165static int write_item_anim(int fd, const char *dir, mbtk_animation_header_t *anim_h)
166{
167 if(-1 == lseek(fd, anim_h->addr, SEEK_SET)) {
168 printf("lseek() fail:%d\n", errno);
169 return -1;
170 }
171
172 char pic_name[256] = {0};
173 char buff[4 * 1024 * 1024] = {0}; // 4MB
174 int len, i = 1; // 1.bmp - ANIM_PIC_MAX.bmp
175
176 for(; i <= ANIM_PIC_MAX; i++) {
177 memset(pic_name, 0, sizeof(pic_name));
178 snprintf(pic_name, sizeof(pic_name), "%s/%d.bmp", dir, i);
179
180/*
181 if(!is_directory_exists(pic_name)) {
182 anim_h->pic_num = i - 1;
183 printf("Anim pic num is : %d\n", i - 1);
184 return 0;
185 }
186*/
187
188 len = bmp_read(pic_name, &(anim_h->pic_width), &(anim_h->pic_height), buff, sizeof(buff));
189 if(len == 0) { // 文件不存在
190 anim_h->pic_num = i - 1;
191 printf("Anim pic num is : %d\n", i - 1);
192 return 0;
193 } else if(len < 0) {
194 printf("bmp_read() fail.\n");
195 return -1;
196 }
197
198 if(len != write(fd, buff, len)) {
199 printf("Write logo buffer fail:%d\n", errno);
200 return -1;
201 }
202 }
203
204 anim_h->pic_num = ANIM_PIC_MAX;
205 return 0;
206}
207
208
209/*
210*
211* logo_partition_generate [pic_dir] -a [logo_w] -b [logo_h] -c [logo_bg] -d [anim_num] -e [anim_w] -f [anim_h] -g [anim_rate] -i [anim_bg]
b.liu0c2d03b2025-02-26 16:53:44 +0800212* logo_partition_generate [pic_dir] -a [logo_bg] -b [waitting_time(ms)] -c [anim_bg] -d [frame_show_num]
b.liu90f385f2025-02-20 19:57:52 +0800213*/
214int main(int argc, char *argv[])
215{
216 int ch;
217 char *out_bin = "logo.img";
218 uint32 temp_int;
219 if(argc < 2) {
220 help();
221 return -1;
222 }
223
224 char *dir = argv[1];
225 if(!is_directory_exists(dir)) {
226 printf("Dir %s not exists.\n", dir);
227 return -1;
228 }
229
b.liu0c2d03b2025-02-26 16:53:44 +0800230 while((ch = getopt(argc, argv, "a:b:c:d:"))!= -1){
b.liu90f385f2025-02-20 19:57:52 +0800231 switch(ch)
232 {
233#if 0
234 case 'a':
235 temp_int = (uint32)atoi(optarg);
236 if(temp_int > 0) {
237 logo_header.pic_width = temp_int;
238 } else {
239 printf("logo width error.");
240 }
241 break;
242 case 'b':
243 temp_int = (uint32)atoi(optarg);
244 if(temp_int > 0) {
245 logo_header.pic_height = temp_int;
246 } else {
247 printf("logo height error.");
248 }
249 break;
250 case 'c':
251 temp_int = (uint32)strtoul(optarg, NULL, 0); // 自动识别
252 logo_header.bg_rgb = temp_int & 0x00FFFFFF;
253 break;
254 case 'd':
255 temp_int = (uint32)atoi(optarg);
256 if(temp_int > 0) {
257 animation_header.pic_num = temp_int;
258 } else {
259 printf("animation number error.");
260 }
261 break;
262 case 'e':
263 temp_int = (uint32)atoi(optarg);
264 if(temp_int > 0) {
265 animation_header.pic_width = temp_int;
266 } else {
267 printf("animation width error.");
268 }
269 break;
270 case 'f':
271 temp_int = (uint32)atoi(optarg);
272 if(temp_int > 0) {
273 animation_header.pic_height = temp_int;
274 } else {
275 printf("animation height error.");
276 }
277 break;
278 case 'g':
279 temp_int = (uint32)atoi(optarg);
280 if(temp_int > 0) {
281 animation_header.frame_rate = temp_int;
282 } else {
283 printf("animation frame_rate error.");
284 }
285 break;
286 case 'i':
287 temp_int = (uint32)strtoul(optarg, NULL, 0); // 自动识别
288 animation_header.bg_rgb = temp_int & 0x00FFFFFF;
289 break;
290#else
291 case 'a':
292 temp_int = (uint32)strtoul(optarg, NULL, 0); // 自动识别
b.liu0c2d03b2025-02-26 16:53:44 +0800293 logo_header.bg_rgb = temp_int << 8;
b.liu90f385f2025-02-20 19:57:52 +0800294 break;
295 case 'b':
296 temp_int = (uint32)atoi(optarg);
297 if(temp_int > 0) {
b.liu0c2d03b2025-02-26 16:53:44 +0800298 animation_header.waitting_time = temp_int;
b.liu90f385f2025-02-20 19:57:52 +0800299 } else {
b.liu0c2d03b2025-02-26 16:53:44 +0800300 printf("animation waitting_time error.");
b.liu90f385f2025-02-20 19:57:52 +0800301 }
302 break;
303 case 'c':
304 temp_int = (uint32)strtoul(optarg, NULL, 0); // 自动识别
b.liu0c2d03b2025-02-26 16:53:44 +0800305 animation_header.bg_rgb = temp_int << 8;
306 break;
307 case 'd':
308 temp_int = (uint32)atoi(optarg);
b.liuffb01e02025-03-05 14:28:10 +0800309 if(temp_int >= 0) {
b.liu0c2d03b2025-02-26 16:53:44 +0800310 animation_header.frame_show_num = temp_int;
311 } else {
312 printf("animation frame_show_num error.");
313 }
b.liu90f385f2025-02-20 19:57:52 +0800314 break;
315#endif
316 default:
317 help();
318 return -1;
319 }
320 }
321
322 printf("Before Logo : addr - 0x%x, w - %d, h - %d, bg - 0x%06x\n", logo_header.addr ,logo_header.pic_width, logo_header.pic_height, logo_header.bg_rgb);
b.liu0c2d03b2025-02-26 16:53:44 +0800323 printf("Before Anim : addr - 0x%x, w - %d, h - %d, bg - 0x%06x, num - %d, waitting_time(ms) - %d, frame_show_num - %d\n", animation_header.addr ,animation_header.pic_width, animation_header.pic_height, animation_header.bg_rgb,
324 animation_header.pic_num, animation_header.waitting_time, animation_header.frame_show_num);
b.liu90f385f2025-02-20 19:57:52 +0800325
326 int fd = open(out_bin, O_WRONLY | O_TRUNC | O_CREAT, 0644);
327 if(fd < 0) {
328 printf("Open(%s) fail:%d\n", out_bin, errno);
329 return -1;
330 }
331
332 if(write_item_logo(fd, dir, &logo_header)) {
333 printf("write_item_logo() fail.");
334 goto fail;
335 }
336
337 if(write_item_anim(fd, dir, &animation_header)) {
338 printf("write_item_anim() fail.");
339 goto fail;
340 }
341
342 // Write header in the last.
343 if(write_header(fd, &logo_header, &animation_header)) {
344 printf("write_header() fail.");
345 goto fail;
346 }
347
348 printf("After Logo : addr - 0x%x, w - %d, h - %d, bg - 0x%06x\n", logo_header.addr ,logo_header.pic_width, logo_header.pic_height, logo_header.bg_rgb);
b.liu0c2d03b2025-02-26 16:53:44 +0800349 printf("After Anim : addr - 0x%x, w - %d, h - %d, bg - 0x%06x, num - %d, waitting_time(ms) - %d, frame_show_num - %d\n", animation_header.addr ,animation_header.pic_width, animation_header.pic_height, animation_header.bg_rgb,
350 animation_header.pic_num, animation_header.waitting_time, animation_header.frame_show_num);
b.liu90f385f2025-02-20 19:57:52 +0800351
352 printf("Success generate logo_partition bin:%s\n", out_bin);
353 close(fd);
354 return 0;
355fail:
356 close(fd);
357 return -1;
358}
359