emote2ss

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

animation.c (3557B)


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