Last active
January 15, 2020 09:55
-
-
Save max-verem/65fde062b909a53299671cba068abe1d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Miranda Animation OXI file to PNG sequence | |
gcc -g3 -ggdb -O0 demo.c -o demo -lpng | |
*/ | |
#include <stdio.h> | |
#include <sys/types.h> | |
#include <sys/stat.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <stdlib.h> | |
#include <inttypes.h> | |
#include <stdint.h> | |
#include <limits.h> | |
#include <string.h> | |
#include <png.h> | |
static const char* file_header = "Miranda Animation Builder"; | |
int16_t r_16le(fd) | |
{ | |
int16_t b; | |
read(fd, &b, sizeof(b)); | |
return b; | |
}; | |
int32_t r_32le(fd) | |
{ | |
int32_t b; | |
read(fd, &b, sizeof(b)); | |
return b; | |
}; | |
typedef struct | |
{ | |
int w, h, x, y; | |
} field_desc_t; | |
enum | |
{ | |
OFFSET_FRAME_WIDTH = 0, | |
OFFSET_FRAME_HEIGHT, | |
OFFSET_FIELDS_CNT, | |
OFFSET_TABLE1, | |
OFFSET_FIELDS_LAST | |
}; | |
int main(int argc, char** argv) | |
{ | |
uint8_t *frame_buf, **frame_rows; | |
field_desc_t *fields; | |
char path[PATH_MAX], seq[PATH_MAX], *ver; | |
int s, r, fd, i, j, frame_width, frame_height, fields_cnt, frame_stride, frame_sz, OFFSET[OFFSET_FIELDS_LAST]; | |
int f_RGBA = 0; | |
if(argc != 2) | |
{ | |
fprintf(stderr, "Error! Please specify filename\n"); | |
return 1; | |
}; | |
fd = open(argv[1], O_RDONLY); | |
if(fd < 0) | |
{ | |
fprintf(stderr, "Error! Failed to open filename [%s]\n", argv[1]); | |
return 1; | |
}; | |
lseek(fd, 0x00000000, SEEK_SET); | |
read(fd, seq, PATH_MAX); | |
if(strcmp(seq, file_header)) | |
{ | |
fprintf(stderr, "No header [%s] found\n", file_header); | |
close(fd); | |
return 1; | |
}; | |
ver = seq + 0x1A; | |
printf("File version [%s] found\n", ver); | |
if(!strcmp("V5.05", ver)) | |
{ | |
OFFSET[OFFSET_FRAME_WIDTH] = 0x0000002f; | |
OFFSET[OFFSET_FRAME_HEIGHT] = 0x00000033; | |
OFFSET[OFFSET_FIELDS_CNT] = 0x00000027; | |
OFFSET[OFFSET_TABLE1] = 0x0000006C; | |
} | |
else if(strcmp("V5.10", ver) != 0 || strcmp("V5.11", ver) != 0) | |
{ | |
OFFSET[OFFSET_FRAME_WIDTH] = 0x00000029; | |
OFFSET[OFFSET_FRAME_HEIGHT] = 0x0000002d; | |
OFFSET[OFFSET_FIELDS_CNT] = 0x00000031; | |
OFFSET[OFFSET_TABLE1] = 0x00000067; | |
f_RGBA = 1; | |
} | |
else | |
{ | |
fprintf(stderr, "version [%s] not supported\n", ver); | |
close(fd); | |
return 1; | |
}; | |
lseek(fd, OFFSET[OFFSET_FRAME_WIDTH], SEEK_SET); | |
frame_width = r_32le(fd); | |
lseek(fd, OFFSET[OFFSET_FRAME_HEIGHT], SEEK_SET); | |
frame_height = r_32le(fd); | |
lseek(fd, OFFSET[OFFSET_FIELDS_CNT], SEEK_SET); | |
fields_cnt = r_16le(fd); | |
printf("width=%d, height=%d, fields=%d\n", frame_width, frame_height, fields_cnt); | |
fields = (field_desc_t *)malloc(sizeof(field_desc_t) * fields_cnt); | |
/* read dims */ | |
lseek(fd, OFFSET[OFFSET_TABLE1], SEEK_SET); | |
for(i = 0; i < fields_cnt; i++) | |
{ | |
fields[i].w = r_16le(fd); | |
fields[i].h = r_16le(fd); | |
}; | |
/* read dims */ | |
lseek(fd, OFFSET[OFFSET_TABLE1] + 4 * fields_cnt, SEEK_SET); | |
for(i = 0; i < fields_cnt; i++) | |
{ | |
fields[i].x = r_16le(fd); | |
fields[i].y = r_16le(fd); | |
}; | |
frame_stride = 4 * frame_width; | |
frame_sz = frame_stride * frame_height; | |
frame_buf = (uint8_t*)malloc(frame_sz); | |
snprintf(path, sizeof(path), "%s.seq", argv[1]); | |
mkdir(path, 0777); | |
frame_rows = (uint8_t**)malloc(frame_height * sizeof(uint8_t*)); | |
for(i = 0; i < frame_height; i++) | |
frame_rows[i] = frame_buf + i * frame_stride; | |
/* read fields */ | |
lseek(fd, OFFSET[OFFSET_TABLE1] + 2 * 4 * fields_cnt, SEEK_SET); | |
for(i = 0; i < fields_cnt; i++) | |
{ | |
printf("\t[%4d] [%d, %d] {%d, %d}\n", i, fields[i].w, fields[i].h, fields[i].x, fields[i].y); | |
if(!(i & 1)) | |
memset(frame_buf, 0, frame_sz); | |
for(j = 0; j < fields[i].h; j++) | |
{ | |
uint8_t *dst = frame_buf | |
+ ((i & 1) ? frame_stride : 0) | |
+ (j + fields[i].y) * 2 * frame_stride | |
+ 4 * fields[i].x; | |
r = read(fd, dst, 4 * fields[i].w); | |
for(s = 0; s < r; s += 4) | |
{ | |
uint8_t | |
p0 = dst[s + 0], | |
p1 = dst[s + 1], | |
p2 = dst[s + 2], | |
p3 = dst[s + 3]; | |
/* | |
*(dst + s + 0) = 0x10; // R | |
*(dst + s + 1) = 0x20; // G | |
*(dst + s + 2) = 0x30; // B | |
*(dst + s + 3) = 0x40; // A | |
*/ | |
if(f_RGBA) | |
{ | |
// ARGB -> RGBA | |
dst[s + 0] = p1; //R | |
dst[s + 1] = p2; //G | |
dst[s + 2] = p3; //B | |
dst[s + 3] = p0; //A | |
} | |
else | |
{ | |
// BGRA -> RGBA | |
dst[s + 0] = p2; | |
dst[s + 1] = p1; | |
dst[s + 2] = p0; | |
dst[s + 3] = p3; | |
}; | |
}; | |
printf("\t\t[%4d] %d\n", j, r); | |
}; | |
if(i & 1) | |
{ | |
#if 0 | |
int f; | |
snprintf(path, sizeof(path), "%s.seq/%05d.data", argv[1], i / 2); | |
f = creat(path, 0666); | |
if(f >= 0) | |
{ | |
write(f, frame_buf, frame_sz); | |
close(f); | |
}; | |
#else | |
FILE* fp; | |
png_structp png_ptr = NULL; | |
png_infop info_ptr = NULL; | |
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); | |
info_ptr = png_create_info_struct(png_ptr); | |
snprintf(path, sizeof(path), "%s.seq/%05d.png", argv[1], i / 2); | |
fp = fopen(path, "wb"); | |
png_init_io(png_ptr, fp); | |
png_set_IHDR | |
( | |
png_ptr, info_ptr, frame_width, frame_height, | |
8, | |
PNG_COLOR_TYPE_RGB_ALPHA, | |
PNG_INTERLACE_NONE, // PNG_INTERLACE_ADAM7 | |
PNG_COMPRESSION_TYPE_BASE, //PNG_COMPRESSION_TYPE_DEFAULT, | |
PNG_FILTER_TYPE_DEFAULT | |
); | |
png_write_info(png_ptr, info_ptr); | |
png_write_image(png_ptr, frame_rows); | |
png_write_end(png_ptr, NULL); | |
#if 0 | |
png_set_rows(png_ptr, info_ptr, frame_rows); | |
png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); | |
#endif | |
png_destroy_write_struct(&png_ptr, &info_ptr); | |
fclose(fp); | |
#endif | |
}; | |
}; | |
free(frame_rows); | |
free(fields); | |
close(fd); | |
return 0; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello Max, I have some questions for you about this project. Can I contact you directly?