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 }