Skip to content

Instantly share code, notes, and snippets.

@max-verem
Last active January 15, 2020 09:55
Show Gist options
  • Save max-verem/65fde062b909a53299671cba068abe1d to your computer and use it in GitHub Desktop.
Save max-verem/65fde062b909a53299671cba068abe1d to your computer and use it in GitHub Desktop.
/*
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;
};
@dapollon83
Copy link

Hello Max, I have some questions for you about this project. Can I contact you directly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment