mivfx/main.c

170 行
4.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include "format/png.h"
#include "format/webp.h"
#include "format/gif.h"
typedef enum {
STATIC,
ANIME
} ImgType;
typedef struct {
ImgType type;
int width;
int height;
union {
XImage *simg;
GifWrap *aimg;
} imgdata;
} LoliImg;
int XErrorHandlerd(Display *d, XErrorEvent *event) {
char error_text[120];
XGetErrorText(d, event->error_code, error_text, sizeof(error_text));
fprintf(stderr, "Xエラー: %s\n", error_text);
return 0;
}
LoliImg* openimg(Display *d, const char *filename) {
FILE *fp;
fp = fopen(filename, "rb");
if (!fp) {
perror("ファイルを開けられません。");
return NULL;
}
unsigned char buf[16];
fread(buf, 1, 16, fp);
fclose(fp);
LoliImg *limg = malloc(sizeof(LoliImg));
if (memcmp(buf, "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A", 8) == 0) { // PNG
limg->type = STATIC;
limg->imgdata.simg = read_png(d, filename);
limg->width = limg->imgdata.simg->width;
limg->height = limg->imgdata.simg->height;
return limg;
} else if (memcmp(buf + 8, "WEBP", 4) == 0) { // WEBP
limg->type = STATIC;
limg->imgdata.simg = read_webp(d, filename);
limg->width = limg->imgdata.simg->width;
limg->height = limg->imgdata.simg->height;
return limg;
} else if (memcmp(buf, "GIF", 3) == 0) { // GIF
GifWrap *wrap = malloc(sizeof(GifWrap));
wrap->anime = read_gif(d, filename);
wrap->width = wrap->anime->width;
wrap->height = wrap->anime->height;
wrap->frames = wrap->anime->frames;
wrap->framecnt = wrap->anime->framecnt;
limg->type = ANIME;
limg->imgdata.aimg = wrap;
limg->width = wrap->width;
limg->height = wrap->height;
return limg;
}
free(limg);
fprintf(stderr, "不明なファイル種類。\n");
return NULL;
}
void GentleDestroyLoliImage(LoliImg *limg) {
if (limg->type == STATIC) {
XDestroyImage(limg->imgdata.simg);
} else if (limg->type == ANIME) {
GifWrap *wrap = limg->imgdata.aimg;
// 各フレームを破壊する
for (int i = 0; i < wrap->framecnt; ++i) {
XDestroyImage(wrap->frames[i]);
}
}
free(limg);
}
int main(int argc, char **argv) {
XSetErrorHandler(XErrorHandlerd);
if (argc < 2) {
printf("使用方法: %s <画像ファイル>\n", argv[0]);
return 1;
}
Display *d = XOpenDisplay(NULL);
if (d == NULL) {
fprintf(stderr, "画面を開けられません。\n");
return 1;
}
int scr = DefaultScreen(d);
Window w = XCreateSimpleWindow(d, RootWindow(d, scr), 0, 0, 500, 500, 1, BlackPixel(d, scr), WhitePixel(d, scr));
XSelectInput(d, w, ExposureMask | KeyPressMask);
XMapWindow(d, w);
XFlush(d);
GC gc = XCreateGC(d, w, 0, NULL);
if (gc == NULL) {
fprintf(stderr, "グラフィックス内容を創作に失敗しました。\n");
return 1;
}
LoliImg *ximg = openimg(d, argv[1]);
if (ximg == NULL) {
fprintf(stderr, "画像を開けられません: %s\n", argv[1]);
XFreeGC(d, gc);
XCloseDisplay(d);
return 1;
}
double scale = 1.0;
struct timeval tv;
gettimeofday(&tv, NULL);
unsigned long curframe = 1000000 * tv.tv_sec + tv.tv_usec;
while (1) {
XEvent e;
XNextEvent(d, &e);
if (e.type == Expose) {
int nw = (int)(ximg->width * scale);
int nh = (int)(ximg->height * scale);
if (ximg->type == STATIC) {
XPutImage(d, w, gc, ximg->imgdata.simg, 0, 0, 0, 0, nw, nh);
} else {
GifWrap *wrap = ximg->imgdata.aimg;
XPutImage(d, w, gc, wrap->frames[curframe], 0, 0, 0, 0, nw, nh);
}
}
if (e.type == KeyPress) {
XWindowAttributes attrs;
XGetWindowAttributes(d, w, &attrs);
KeySym keysym = XLookupKeysym(&e.xkey, 0);
if (keysym == XK_q) {
break;
}
}
}
// 掃除
XFreeGC(d, gc);
GentleDestroyLoliImage(ximg);
XDestroyWindow(d, w);
XCloseDisplay(d);
return 0;
}