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 }