/* * Copyright © 2014 IIMarckus * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include uint16_t getint16BE(FILE *f) { uint16_t n; n = fgetc(f) << 8; n |= fgetc(f); return n; } uint32_t getint32BE(FILE *f) { uint32_t n; n = fgetc(f) << 24; n |= fgetc(f) << 16; n |= fgetc(f) << 8; n |= fgetc(f); return n; } void printpng(uint16_t **pixels, int height, int width) { png_structp png_ptr; png_infop info_ptr; int x, y; png_byte **row_pointers; int pixel_size; int depth; png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { errx(1, "Could not create PNG write struct"); } info_ptr = png_create_info_struct(png_ptr); if (info_ptr == NULL) { png_destroy_write_struct(&png_ptr, NULL); errx(1, "Could not create PNG info struct"); } if (setjmp (png_jmpbuf (png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); errx(1, "Internal PNG error"); } depth = 8; png_set_IHDR(png_ptr, info_ptr, width, height, depth, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); pixel_size = 3; row_pointers = png_malloc(png_ptr, height * sizeof (png_byte *)); for (y = 0; y < height; ++y) { png_byte *row = png_malloc(png_ptr, sizeof(uint8_t) * width * pixel_size); row_pointers[y] = row; for (x = 0; x < width; ++x) { *row++ = (pixels[x][y] >> 11) << 3; *row++ = ((pixels[x][y] >> 6) & 0x1f) << 3; *row++ = ((pixels[x][y] >> 1) & 0x1f) << 3; } } png_init_io(png_ptr, stdout); png_set_rows(png_ptr, info_ptr, row_pointers); png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); for (y = 0; y < height; y++) { png_free(png_ptr, row_pointers[y]); } png_free(png_ptr, row_pointers); png_destroy_write_struct(&png_ptr, &info_ptr); } /* * read a face from offset in f and store it into pixels. */ void getface(FILE *f, long offset, int height, int width, uint16_t **pixels, int inset) { /* * In the original format, on every other line, every other pair of * pixels is swapped. Here we transpose it into top-bottom left-right. */ uint16_t q[4]; int x, y; fseek(f, offset, SEEK_SET); for (y = 0; y < height; ++y) { for (x = inset; x < width + inset; ++x) { if (y % 2 == 0) { pixels[x][y] = fgetc(f) << 8; pixels[x][y] |= fgetc(f); } else { q[x % 4] = fgetc(f) << 8; q[x % 4] |= fgetc(f); if (x % 4 == 3) { pixels[x - 3][y] = q[2]; pixels[x - 2][y] = q[3]; pixels[x - 1][y] = q[0]; pixels[x][y] = q[1]; } } } } } int main(int argc, char *argv[]) { FILE *f; int x, y; uint16_t **pixels; int height, width; uint32_t nfaces; uint32_t *offsets; uint16_t *heights, *widths; int inset; if (argc != 2) { errx(1, "Usage: face2png file"); } f = fopen(argv[1], "rb"); if (f == NULL) { err(1, "Could not open file '%s'", argv[1]); } nfaces = getint32BE(f); offsets = reallocarray(NULL, nfaces, sizeof *offsets); heights = reallocarray(NULL, nfaces, sizeof *heights); widths = reallocarray(NULL, nfaces, sizeof *widths); if (offsets == NULL || heights == NULL || widths == NULL) { err(1, "Could not allocate memory"); } for (y = 0; y < nfaces; ++y) { offsets[y] = getint32BE(f); } height = 0; width = 0; for (y = 0; y < nfaces; ++y) { fseek(f, offsets[y] - 8, SEEK_SET); /* * XXX * check whether height follows width or width follows height */ heights[y] = getint16BE(f); widths[y] = getint16BE(f); getint32BE(f); /* height equals the largest height */ height = heights[y] > height ? heights[y] : height; /* width equals the sum of the widths */ width += widths[y]; } pixels = reallocarray(NULL, width, sizeof *pixels); if (pixels == NULL) { err(1, "Could not allocate memory"); } for (x = 0; x < width; ++x) { pixels[x] = reallocarray(NULL, height, sizeof *pixels[x]); if (pixels[x] == NULL) { err(1, "Could not allocate memory"); } } inset = 0; for (y = 0; y < nfaces; ++y) { getface(f, offsets[y], heights[y], widths[y], pixels, inset); inset += widths[y]; } printpng(pixels, height, width); fclose(f); return 0; }