170 行
4.0 KiB
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;
|
|
}
|