emote2ss

Animated webp to spritesheets converting tool
git clone git://bsandro.tech/emote2ss
Log | Files | Refs | README | LICENSE

animation.c (3624B)


      1 #define _GNU_SOURCE
      2 
      3 #include "animation.h"
      4 #include "fileops.h"
      5 #include <libgen.h>
      6 #include <stdlib.h>
      7 #include <stdio.h>
      8 #include <assert.h>
      9 #include <string.h>
     10 #include <strings.h>
     11 #include "webp/decode.h"
     12 #include "webp/demux.h"
     13 
     14 #ifdef UI_WINDOWS
     15 #include <windows.h>
     16 #include <limits.h>
     17 #endif
     18 
     19 #ifdef __OpenBSD__
     20 #include <sys/syslimits.h>
     21 #endif
     22 
     23 #ifdef __NetBSD__
     24 #include <sys/syslimits.h>
     25 #endif
     26 
     27 #ifdef __linux__
     28 #include <linux/limits.h>
     29 #endif
     30 
     31 Animation * ImageLoad(const char *path) {
     32 	Animation *img = malloc(sizeof(Animation));
     33 	assert(img!=NULL);
     34 	bzero(img, sizeof(Animation));
     35 	img->path = realpath(path, NULL);
     36 	assert(img->path!=NULL);
     37 	printf("img->path: %s\n", img->path);
     38 	int r = WebpRead(img->path, img);
     39 	assert(r==0);
     40 
     41 	char *name_copy = strndup(img->path, PATH_MAX);
     42 	char *path_copy = strndup(img->path, PATH_MAX);
     43 	img->filename = strndup(basename(name_copy), NAME_MAX);
     44 	img->dirname = strndup(dirname(path_copy), PATH_MAX);
     45 	free(name_copy);
     46 	free(path_copy);
     47 
     48 	//printf("[%s/%s]\ncols: %d\ndimensions: %dx%dpx\nframes: %d\n", img->dirname, img->filename, cols, img->width, img->height, img->frame_count);
     49 
     50 	return img;
     51 }
     52 
     53 void ImageUnload(Animation **img) {
     54 	free((*img)->path);
     55 	free((*img)->dirname);
     56 	free((*img)->filename);
     57 	free(*img);
     58 	*img = NULL;
     59 }
     60 
     61 int WebpRead(const char *filename, Animation *anim) {
     62 	printf("WebpRead(%s)\n", filename);
     63 
     64 	WebPData webp_data;
     65 	WebPDataInit(&webp_data);
     66 
     67 	if (FileRead(filename, &webp_data.bytes, &webp_data.size) == -1) {
     68 		fprintf(stderr, "FileRead() error\n");
     69 		return -1;
     70 	}
     71 
     72 	if (!WebPGetInfo(webp_data.bytes, webp_data.size, NULL, NULL)) {
     73 		fprintf(stderr, "invalid webp\n");
     74 		WebPDataClear(&webp_data);
     75 		return -1;
     76 	}
     77 
     78 	WebPAnimDecoder *dec = WebPAnimDecoderNew(&webp_data, NULL);
     79 	assert(dec != NULL);
     80 
     81 	WebPAnimInfo anim_info;
     82 	if (!WebPAnimDecoderGetInfo(dec, &anim_info)) {
     83 		fprintf(stderr, "error decoding animation info\n");
     84 		// @todo cleanup
     85 		return -1;
     86 	}
     87 
     88 	anim->width = anim_info.canvas_width;
     89 	anim->height = anim_info.canvas_height;
     90 	anim->loop_count = anim_info.loop_count;
     91 	anim->bgcolor = anim_info.bgcolor;
     92 	AnimationCreate(anim, anim_info.frame_count);
     93 
     94 	uint32_t frame_index = 0;
     95 	int prev_ts = 0;
     96 	while (WebPAnimDecoderHasMoreFrames(dec)) {
     97 		Frame *frame;
     98 		uint8_t *curr_rgba, *frame_rgba;
     99 		int ts;
    100 		if (!WebPAnimDecoderGetNext(dec, &frame_rgba, &ts)) {
    101 			fprintf(stderr, "error decoding frame %d\n", frame_index);
    102 			return -1;
    103 		}
    104 		assert(frame_index < anim_info.frame_count);
    105 		frame = &anim->frames[frame_index];
    106 		curr_rgba = frame->rgba;
    107 		frame->duration = ts - prev_ts;
    108 		memcpy(curr_rgba, frame_rgba, anim->width * anim->height * NUM_CHANNELS);
    109 		// ... <- nani kore?
    110 		++frame_index;
    111 		prev_ts = ts;
    112 	}
    113 
    114 	WebPDataClear(&webp_data);
    115 	WebPAnimDecoderDelete(dec);
    116 	return 0;
    117 }
    118 
    119 void AnimationCreate(Animation *img, uint32_t frame_count) {
    120 	assert(frame_count > 0);
    121 	uint8_t *mem = NULL;
    122 	Frame *frames = NULL;
    123 	const uint64_t rgba_size = img->width * img->height * NUM_CHANNELS;
    124 	const uint64_t img_size = frame_count * rgba_size * sizeof(uint8_t);
    125 	const uint64_t frames_size = frame_count * sizeof(Frame);
    126 
    127 	assert(img_size == (size_t)img_size);
    128 	assert(frames_size == (size_t)frames_size);
    129 
    130 	printf("img mem: %" PRIu64 "\nframes mem: %" PRIu64 "\n", img_size, frames_size);
    131 
    132 	mem = malloc(img_size);
    133 	frames = malloc(frames_size);
    134 	assert(mem != NULL);
    135 	assert(frames != NULL);
    136 
    137 	for (uint32_t i=0; i<frame_count; ++i) {
    138 		frames[i].rgba = mem+i*rgba_size;
    139 		frames[i].duration = 0;
    140 		frames[i].is_key = false;
    141 	}
    142 	img->frame_count = frame_count;
    143 	img->frames = frames;
    144 	img->raw_mem = mem;
    145 }