pokestadium/oldnotes/utils/face2png.c

212 lines
4.8 KiB
C

/*
* Copyright © 2014 IIMarckus <imarckus@gmail.com>
*
* 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 <png.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
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;
}