#include #include #include #include "libpng/png.h" typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned int hdc_color_t; typedef unsigned short hdc_pixel_t; #define HDC_ARGB(a, r, g, b) \ ((hdc_color_t)(((uint8_t)(r)|\ (((unsigned)(uint8_t)(g))<<8))|\ (((unsigned long)(uint8_t)(b))<<16)|\ (((unsigned long)(uint8_t)(a))<<24))) #define HDC_RGB(r, g, b) HDC_ARGB(255, (r), (g), (b)) #define HDC_RGB_R(c) ((c) & 0xff) #define HDC_RGB_G(c) (((c) >> 8) & 0xff) #define HDC_RGB_B(c) (((c) >> 16) & 0xff) #define HDC_RGB_A(c) (((c) >> 24) & 0xff) /* convert HDC color to BBBBBGGGGGGRRRRR */ uint16_t hdc_color_to_565(hdc_color_t c) { uint16_t pixel; pixel = ((HDC_RGB_B(c)>> 3) << 11) | ((HDC_RGB_G(c) >> 2) << 5) | (HDC_RGB_R(c) >> 3); return pixel; } /* convert HDC color to RRRRRGGGGGGBBBBB */ uint16_t hdc_color_to_565p(hdc_color_t c) { uint16_t pixel; pixel = ((HDC_RGB_R(c) >> 3) << 11) | ((HDC_RGB_G(c) >> 2) << 5) | (HDC_RGB_B(c)>> 3); return pixel; } /* png image information */ png_structp png_ptr; png_infop info_ptr; struct hdc_image_header { uint32_t magic; uint32_t width; uint32_t height; /* transparent color */ uint32_t tmask; /* reserved */ uint32_t reserved; }; struct hdc_image_header header; int main(int argc, char** argv) { int bit_depth; int color_type; double gamma; int width, height; FILE *src_fp, *dst_fp; png_uint_32 x, y; png_bytep row; png_bytep data; hdc_pixel_t *ptr; src_fp = fopen(argv[1], "rb"); dst_fp = fopen(argv[2], "wb"); if (src_fp == NULL || dst_fp == NULL) { printf("can't open file for read or write\n"); return -1; } png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { return -1; } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, NULL, NULL); return -1; } if (setjmp(png_jmpbuf(png_ptr))) { png_read_end(png_ptr, NULL); /* destroy png struct */ png_destroy_info_struct(png_ptr, &info_ptr); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(src_fp);fclose(dst_fp); return (-1); } png_init_io(png_ptr, src_fp); png_read_info(png_ptr, info_ptr); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (bit_depth == 16) png_set_strip_16(png_ptr); if (color_type == PNG_COLOR_TYPE_PALETTE) png_set_expand(png_ptr); if (bit_depth < 8) png_set_expand(png_ptr); if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) png_set_expand(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /* set gamma conversion */ if (png_get_gAMA(png_ptr, info_ptr, &gamma)) png_set_gamma(png_ptr, (double)2.2, gamma); png_read_update_info(png_ptr, info_ptr); /* write HDC file header */ sprintf((char *)&header.magic, "HDC%c", '\0'); header.width = info_ptr->width; header.height = info_ptr->height; header.tmask = 0; header.reserved = 0; fwrite(&header, 1, sizeof(struct hdc_image_header), dst_fp); row = (png_bytep) malloc (png_get_rowbytes(png_ptr, info_ptr)); if (row == NULL) goto _return; ptr = (hdc_pixel_t*) malloc (header.width * header.height * sizeof(hdc_pixel_t)); switch (info_ptr->color_type) { case PNG_COLOR_TYPE_RGBA: for (y = 0; y < info_ptr->height; y++) { png_read_row(png_ptr, row, png_bytep_NULL); for (x = 0; x < info_ptr->width; x++) { data = &(row[x * 4]); ptr[x + y * info_ptr->width] = hdc_color_to_565p(HDC_ARGB((255 - data[3]), data[0], data[1], data[2])); } } break; case PNG_COLOR_TYPE_PALETTE: for (y = 0; y < info_ptr->height; y++) { png_read_row(png_ptr, row, png_bytep_NULL); for (x = 0; x < info_ptr->width; x++) { data = &(row[x]); ptr[x] = hdc_color_to_565p(HDC_ARGB(0, info_ptr->palette[data[0]].red, info_ptr->palette[data[0]].green, info_ptr->palette[data[0]].blue)); } } default: break; }; fwrite(ptr, 1, header.height * header.width * sizeof(hdc_pixel_t), dst_fp); _return: png_read_end(png_ptr, NULL); /* destroy png struct */ png_destroy_info_struct(png_ptr, &info_ptr); png_destroy_read_struct(&png_ptr, NULL, NULL); fclose(src_fp); fclose(dst_fp); free(ptr); return 0; }