163 行
4.2 KiB
C
163 行
4.2 KiB
C
#include "gif.h"
|
|
|
|
XImage *ximage_from_frame(Display *d, GifFileType *file) {
|
|
int depth = 32;
|
|
int width = file->Image.Width;
|
|
int height = file->Image.Height;
|
|
|
|
char *imgdata = malloc(width * height * 4);
|
|
if (imgdata == NULL) {
|
|
perror("画像データ向けメモリを割り当てに失敗\n");
|
|
return NULL;
|
|
}
|
|
|
|
GifPixelType *raster = (GifPixelType *)malloc(width * height * sizeof(GifPixelType));
|
|
if (!raster) {
|
|
fprintf(stderr, "メモリ割当に失敗\n");
|
|
return NULL;
|
|
}
|
|
|
|
for (int i = 0; i < height; ++i) {
|
|
if (DGifGetLine(file, raster + i * width, width) == GIF_ERROR) {
|
|
fprintf(stderr, "ラスタースキャンに失敗\n");
|
|
free(raster);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
ColorMapObject *cmap = file->Image.ColorMap ? file->Image.ColorMap : file->SColorMap;
|
|
|
|
for (int y = 0; y < height; y++) {
|
|
for (int x = 0; x < width; x++) {
|
|
GifPixelType px = raster[y * width + x];
|
|
GifColorType col = cmap->Colors[px];
|
|
|
|
// 32ビットARGB形式に交換
|
|
uint32_t argb = 0xFF << 24 | // 透明
|
|
col.Red << 16 | // 赤
|
|
col.Green << 8 | // 緑
|
|
col.Blue; // 青
|
|
|
|
// imgdataに保存
|
|
((uint32_t *)imgdata)[y * width + x] = argb;
|
|
}
|
|
}
|
|
|
|
free(raster);
|
|
|
|
// XImageを創作
|
|
XImage *img = XCreateImage(d, DefaultVisual(d, 0), depth, ZPixmap, 0, imgdata, width, height, 32, 0);
|
|
if (img == NULL) {
|
|
fprintf(stderr, "XImageを創作に失敗\n");
|
|
free(imgdata);
|
|
return NULL;
|
|
}
|
|
|
|
return img;
|
|
}
|
|
|
|
GifAnimation* read_gif(Display *d, const char *filename) {
|
|
GifFileType *file;
|
|
if ((file = DGifOpenFileName(filename, NULL)) == NULL) {
|
|
perror("GIFファイルを開けられません。");
|
|
return NULL;
|
|
}
|
|
|
|
GifAnimation *anime = malloc(sizeof(GifAnimation));
|
|
if (anime == NULL) {
|
|
DGifCloseFile(file, NULL);
|
|
perror("GIFファイルを開けられません。");
|
|
return NULL;
|
|
}
|
|
|
|
int framecnt = 0;
|
|
int ExtCode;
|
|
GifByteType *Extension;
|
|
GifRecordType RecordType;
|
|
|
|
do {
|
|
if (DGifGetRecordType(file, &RecordType) == GIF_ERROR) {
|
|
fprintf(stderr, "GIFエラー\n");
|
|
break;
|
|
}
|
|
|
|
if (RecordType == IMAGE_DESC_RECORD_TYPE) {
|
|
framecnt++;
|
|
}
|
|
} while (RecordType != TERMINATE_RECORD_TYPE);
|
|
|
|
anime->frames = malloc(sizeof(XImage*) * framecnt);
|
|
anime->delays = malloc(sizeof(int) * framecnt);
|
|
|
|
if (anime->frames == NULL || anime->delays == NULL) {
|
|
fprintf(stderr, "フレームや延長向けメモリを作成に失敗しました。\n");
|
|
free(anime);
|
|
DGifCloseFile(file, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
DGifCloseFile(file, NULL);
|
|
file = DGifOpenFileName(filename, NULL);
|
|
|
|
int i = 0;
|
|
do {
|
|
if (DGifGetRecordType(file, &RecordType) == GIF_ERROR) {
|
|
fprintf(stderr, "GIFエラー\n");
|
|
break;
|
|
}
|
|
|
|
switch (RecordType) {
|
|
case IMAGE_DESC_RECORD_TYPE:
|
|
if (DGifGetImageDesc(file) == GIF_ERROR) {
|
|
fprintf(stderr, "GIF説明エラー\n");
|
|
break;
|
|
}
|
|
|
|
XImage *img = ximage_from_frame(d, file);
|
|
if (img == NULL) {
|
|
fprintf(stderr, "フレーム %d のXImageを創作に失敗。\n", i);
|
|
break;
|
|
}
|
|
|
|
anime->frames[i] = img;
|
|
|
|
i++;
|
|
break;
|
|
case EXTENSION_RECORD_TYPE:
|
|
if (DGifGetExtension(file, &ExtCode, &Extension) == GIF_ERROR) {
|
|
fprintf(stderr, "GIF種類エラー\n");
|
|
}
|
|
|
|
if (ExtCode == GRAPHICS_EXT_FUNC_CODE) {
|
|
int delay = Extension[2] | (Extension[3] << 8);
|
|
anime->delays[i] = delay;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} while (RecordType != TERMINATE_RECORD_TYPE);
|
|
|
|
if (framecnt == 0) {
|
|
fprintf(stderr, "GIFフレームを見つけられませんでした。\n");
|
|
free(anime);
|
|
DGifCloseFile(file, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
anime->frames = malloc(sizeof(XImage*) * framecnt);
|
|
anime->delays = malloc(sizeof(int) * framecnt);
|
|
|
|
if (anime->frames == NULL || anime->delays == NULL) {
|
|
fprintf(stderr, "フレームや延長向けメモリを作成に失敗しました。\n");
|
|
free(anime->frames);
|
|
free(anime->delays);
|
|
free(anime);
|
|
DGifCloseFile(file, NULL);
|
|
return NULL;
|
|
}
|
|
|
|
DGifCloseFile(file, NULL);
|
|
return anime;
|
|
}
|