/* Copyright (C) 2009 Red Hat, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see . */ #include #include #include #include #include #include #include #include #include #include #include #define TAB " " #define ERROR(str) printf("%s: error: %s\n", prog_name, str); exit(-1); static char *prog_name = NULL; static size_t read_input(const char *file_name, uint8_t** out_buf) { int fd = open(file_name, O_RDONLY); if (fd == -1) { ERROR("open source file failed"); return 0; } struct stat file_stat; if (fstat(fd, &file_stat) == -1) { ERROR("fstat on source file failed"); return 0; } uint8_t *buf = malloc(file_stat.st_size); if (!buf) { close(fd); ERROR("alloc mem failed"); return 0; } size_t to_read = file_stat.st_size; uint8_t *buf_pos = buf; while (to_read) { int n = read(fd, buf_pos, to_read); if (n <= 0) { ERROR("read from source file failed"); close(fd); free(buf); return 0; } to_read -= n; buf_pos += n; } close(fd); *out_buf = buf; return file_stat.st_size; } typedef struct __attribute__ ((__packed__)) BitmpaHeader { uint32_t header_size; uint32_t width; uint32_t height; uint16_t plans; uint16_t bpp; uint32_t compression; uint32_t image_size; uint32_t horizontal_resolution; uint32_t vertical_resolution; uint32_t num_colors; uint32_t important_colors; } BitmpaHeader; typedef struct __attribute__ ((__packed__)) BMPFileHeader { uint16_t magic; uint32_t file_size; uint32_t reserved; uint32_t data_offset; BitmpaHeader header; } BMPFileHeader; #define BI_RGB 0 typedef struct Pixmap { uint32_t width; uint32_t height; uint32_t stride; uint32_t bpp; uint8_t* data; } Pixmap; static Pixmap *init_bitmap(size_t input_size, uint8_t *buf) { BMPFileHeader *file_header; uint8_t *pixels; Pixmap *pixmap; uint32_t stride; if (input_size < sizeof(BMPFileHeader)) { ERROR("invalid source file"); return NULL; } file_header = (BMPFileHeader *)buf; if (file_header->magic != 0x4d42) { ERROR("bad bitmap magic"); return NULL; } if (file_header->file_size != input_size) { ERROR("invalid source file"); return NULL; } if (file_header->header.header_size != 40 || file_header->header.plans != 1 || file_header->header.compression != BI_RGB || !file_header->header.width || !file_header->header.height) { ERROR("invalid bitmap header"); return NULL; } if (file_header->header.bpp == 32) { stride = file_header->header.width * sizeof(uint32_t); } else if (file_header->header.bpp == 24) { stride = SPICE_ALIGN(file_header->header.width * 3, 4); } else { ERROR("unsupported bpp"); return NULL; } if (file_header->header.height * stride > file_header->header.image_size) { ERROR("image size is to small"); return NULL; } pixels = buf + file_header->data_offset; if (pixels < (uint8_t *)(file_header + 1) || pixels + file_header->header.image_size > buf + input_size) { ERROR("bad data offset"); return NULL; } if (!(pixmap = (Pixmap *)malloc(sizeof(*pixmap)))) { ERROR("alloc mem failed"); return NULL; } pixmap->width = file_header->header.width; pixmap->height = file_header->header.height; pixmap->stride = stride; pixmap->bpp = file_header->header.bpp; pixmap->data = pixels; return pixmap; } static inline void put_char(FILE* f, uint8_t val) { fprintf(f, "0x%.2x,", val); } static void do_dump_with_alpha_conversion(const Pixmap *pixmap, FILE *f) { uint8_t *line = (uint8_t *)(pixmap->data + ((pixmap->height - 1) * pixmap->stride)); int line_size = 0; int i, j; for (i = 0; i < pixmap->height; i++) { uint8_t *now = line; for (j = 0; j < pixmap->width; j++, now += 4) { if ((line_size++ % 4) == 0) { fprintf(f, "\n" TAB); } double alpha = (double)now[3] / 0xff; put_char(f, alpha * now[0]); put_char(f, alpha * now[1]); put_char(f, alpha * now[2]); put_char(f, now[3]); } line -= pixmap->stride; } } static void do_dump_32bpp(const Pixmap *pixmap, FILE *f) { uint8_t *line = (uint8_t *)(pixmap->data + ((pixmap->height - 1) * pixmap->stride)); int line_size = 0; int i, j; for (i = 0; i < pixmap->height; i++) { uint8_t *now = line; for (j = 0; j < pixmap->width; j++, now += 4) { if ((line_size++ % 4) == 0) { fprintf(f, "\n" TAB); } put_char(f, now[0]); put_char(f, now[1]); put_char(f, now[2]); put_char(f, now[3]); } line -= pixmap->stride; } } static void do_dump_24bpp(const Pixmap *pixmap, FILE *f) { uint8_t *line = (uint8_t *)(pixmap->data + ((pixmap->height - 1) * pixmap->stride)); int line_size = 0; int i, j; for (i = 0; i < pixmap->height; i++) { uint8_t *now = line; for (j = 0; j < pixmap->width; j++, now += 3) { if ((line_size++ % 4) == 0) { fprintf(f, "\n" TAB); } put_char(f, now[0]); put_char(f, now[1]); put_char(f, now[2]); put_char(f, 0); } line -= pixmap->stride; } } static int pixmap_to_c_struct(const Pixmap *pixmap, const char *dest_file, const char *image_name, int alpha_convertion) { int fd; FILE *f; if ((fd = open(dest_file, O_WRONLY | O_CREAT | O_TRUNC, 0644)) == -1) { ERROR("open dest file failed"); return -1; } if (!(f = fdopen(fd, "w"))) { ERROR("fdopen failed"); close(fd); return -1; } uint32_t data_size = pixmap->width * sizeof(uint32_t) * pixmap->height; fprintf(f, "static const struct {\n" TAB "uint32_t width;\n" TAB "uint32_t height;\n" TAB "uint8_t pixel_data[%u];\n" "} %s = { %u, %u, {", data_size, image_name, pixmap->width, pixmap->height); if (alpha_convertion) { if (pixmap->bpp != 32) { ERROR("32 bpp is requred for alpha option") } do_dump_with_alpha_conversion(pixmap, f); } else if (pixmap->bpp == 32) { do_dump_32bpp(pixmap, f); } else { do_dump_24bpp(pixmap, f); } fseek(f, -1, SEEK_CUR); fprintf(f, "}\n};\n"); fclose(f); close(fd); return 0; } enum { ALPHA_OPT = 'a', HELP_OPT = 'h', NAME_OPT = 'n', }; static void usage() { printf("usage: %s [--alpha] [--name ] SOURCE [DEST]\n", prog_name); printf(" %s --help\n", prog_name); } const struct option longopts[] = { {"help", no_argument, NULL, HELP_OPT}, {"alpha", no_argument, NULL, ALPHA_OPT}, {"name", required_argument, NULL, NAME_OPT}, {NULL, 0, NULL, 0}, }; int main(int argc, char **argv) { size_t input_size; uint8_t* buf; Pixmap *pixmap; int opt; int alpha_convertion = FALSE; char *struct_name = NULL; char *src = NULL; char *dest = NULL; if (!(prog_name = strrchr(argv[0], '/'))) { prog_name = argv[0]; } else { prog_name++; } while ((opt = getopt_long(argc, argv, "ah", longopts, NULL)) != -1) { switch (opt) { case 0: case '?': usage(); exit(-1); case ALPHA_OPT: alpha_convertion = TRUE; break; case HELP_OPT: usage(); exit(0); case NAME_OPT: struct_name = optarg; break; } } int more = argc - optind; switch (more) { case 1: { char *slash; char *dot; dest = malloc(strlen(argv[optind]) + 3); strcpy(dest, argv[optind]); dot = strrchr(dest, '.'); slash = strrchr(dest, '/'); if (!dot || (slash && slash > dot)) { strcat(dest, ".c"); } else { strcpy(dot, ".c"); } break; } case 2: dest = argv[optind + 1]; //todo: if dir strcat src name break; default: usage(); exit(-1); } src = argv[optind]; if (!struct_name) { char *struct_name_src; char *dot; struct_name_src = strrchr(dest, '/'); if (!struct_name_src) { struct_name_src = dest; } else { ++struct_name_src; } struct_name = malloc(strlen(struct_name_src) + 1); strcpy(struct_name, struct_name_src); if ((dot = strchr(struct_name, '.'))) { *dot = 0; } } if (!(input_size = read_input(src, &buf))) { return -1; } if (!(pixmap = init_bitmap(input_size, buf))) { return -1; } return pixmap_to_c_struct(pixmap, dest, struct_name, alpha_convertion); }