#include #include #include #include #include #include #include static char const pic_sig[8] = {'\xdd', '\xdd', 'p', 'i', 'c', '\n', '\0', 0}; static char const help_text[] = "%s [-fh] [-o OUTPUT.dat] INPUT.png\n"; static void write_vlq(size_t value, FILE *file) { unsigned char buf[9]; size_t bytes; for (bytes = 0; bytes < sizeof (size_t); bytes++) { size_t byte = value >> (bytes * 8); if ((byte & (0x7f >> bytes)) == byte) { break; } buf[8 - bytes] = value >> (bytes * 8); } buf[8 - bytes] = (value >> (bytes * 8)) | (0xff00 >> bytes); fwrite(buf + 8 - bytes, 1, bytes + 1, file); } int main(int argc, char **argv) { struct option const options[] = { {"force", 0, NULL, 'f'}, {"help", 0, NULL, 'h'}, {"output", 1, NULL, 'o'}, {"verbose", 0, NULL, 'v'}, {NULL, 0, NULL, 0 }, }; int opt, force = 0, verbose = 0; char *outname = NULL; while ((opt = getopt_long(argc, argv, "fho:v", options, NULL)) != -1) { switch (opt) { case 'f': force++; break; case 'h': fprintf(stderr, help_text, argv[0]); fputs("-f --force allow outputting not-quite-successful conversions\n", stderr); fputs("-h --help this message\n", stderr); fputs("-o --output=FILE output converted image to FILE\n", stderr); fputs("-v --verbose print diagnostics\n", stderr); return EXIT_SUCCESS; case 'o': outname = optarg; break; case 'v': verbose++; break; default: return EXIT_FAILURE; } } if (optind + 1 != argc) { fprintf(stderr, help_text, argv[0]); return EXIT_FAILURE; } // half-assed libpng use, will be fixed in a project where proper libpng use is necessary png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL); if (png_ptr == NULL) { return EXIT_FAILURE; } png_infop info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_read_struct(&png_ptr, NULL, NULL); return EXIT_FAILURE; } FILE *fp = NULL; if (setjmp(png_jmpbuf(png_ptr))) { png_destroy_read_struct(&png_ptr, &info_ptr, NULL); if (fp != NULL) { fclose(fp); } return EXIT_FAILURE; } fp = fopen(argv[optind], "rb"); if (fp == NULL) { perror(argv[optind]); return EXIT_FAILURE; } png_init_io(png_ptr, fp); // we do NOT want gamma! //png_set_gamma_fixed(png_ptr, PNG_GAMMA_LINEAR, PNG_GAMMA_LINEAR); //png_set_alpha_mode(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_LINEAR); png_read_info(png_ptr, info_ptr); png_uint_32 width, height; int bit_depth, color_type; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (color_type == PNG_COLOR_TYPE_PALETTE) { png_set_palette_to_rgb(png_ptr); } else if (bit_depth < 8) { png_set_packing(png_ptr); } else if (bit_depth > 8) { png_set_scale_16(png_ptr); } if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); } else { png_set_add_alpha(png_ptr, 0xff, PNG_FILLER_AFTER); } png_set_rgb_to_gray(png_ptr, 1, -1, -1); //png_set_expand_gray_1_2_4_to_8(png_ptr); png_read_update_info(png_ptr, info_ptr); png_uint_32 rowbytes = png_get_rowbytes(png_ptr, info_ptr); png_bytepp row_pointers = malloc(sizeof (png_bytep) * height); unsigned char *image = malloc(rowbytes * height); for (unsigned i = 0; i < height; i++) { row_pointers[i] = image + (height - i - 1) * rowbytes; } png_read_image(png_ptr, row_pointers); png_destroy_read_struct(&png_ptr, &info_ptr, NULL); //free(row_pointers); if (outname != NULL) { FILE *out = fopen(outname, "wb"); if (out == NULL) { perror(outname); return EXIT_FAILURE; } fwrite(pic_sig, 1, sizeof (pic_sig), out); write_vlq(width - 1, out); write_vlq(height - 1, out); for (size_t i = 0; i < width * height; i++) { if (image[i * 2 + 1] < 0x80) { fputc(0x00, out); } else if (image[i * 2 + 0] < 0x80) { fputc(0x80, out); } else { fputc(0xff, out); } } fclose(out); } return EXIT_SUCCESS; }