emote2ss

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

animation.c (3748B)


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