Stefan Schuermans commited on 2016-12-18 18:52:03
Showing 11 changed files, with 269 additions and 9 deletions.
... | ... |
@@ -377,13 +377,18 @@ int main(int argCnt, char **args) |
377 | 377 |
# define MNGEXT ", *.mng" |
378 | 378 |
#else |
379 | 379 |
# define MNGEXT |
380 |
+#endif |
|
381 |
+#ifdef BLINKENLIB_CFG_GIF |
|
382 |
+# define GIFEXT ", *.gif" |
|
383 |
+#else |
|
384 |
+# define GIFEXT |
|
380 | 385 |
#endif |
381 | 386 |
printf("syntax: %s <parameter> [...]\n\n" |
382 | 387 |
"parameters:\n" |
383 | 388 |
" -i <file>\n" |
384 |
- " read movie from file (*.blm, *.bmm, *.bml, *.bbm"MNGEXT")\n" |
|
389 |
+ " read movie from file (*.blm, *.bmm, *.bml, *.bbm" MNGEXT GIFEXT ")\n" |
|
385 | 390 |
" -a <file>\n" |
386 |
- " append movie from file (*.blm, *.bmm, *.bml, *.bbm"MNGEXT")\n" |
|
391 |
+ " append movie from file (*.blm, *.bmm, *.bml, *.bbm" MNGEXT GIFEXT ")\n" |
|
387 | 392 |
" -l <number>\n" |
388 | 393 |
" loop video a number of times\n" |
389 | 394 |
" -f\n" |
... | ... |
@@ -429,7 +434,7 @@ int main(int argCnt, char **args) |
429 | 434 |
" -Md2\n" |
430 | 435 |
" mirror movie diagonally (/)\n" |
431 | 436 |
" -o <file>\n" |
432 |
- " write movie to file (*.blm, *.bmm, *.bml, *.bbm)\n\n" |
|
437 |
+ " write movie to file (*.blm, *.bmm, *.bml, *.bbm" MNGEXT ")\n\n" |
|
433 | 438 |
"test_modes: black, white, gradient, dots, lines, trans\n\n" |
434 | 439 |
"old syntax: %s <input-file> [<output-file>]\n\n", |
435 | 440 |
args[0], args[0]); |
... | ... |
@@ -0,0 +1,188 @@ |
1 |
+/* BlinkenLib |
|
2 |
+ Copyright 2004-2016 Stefan Schuermans <stefan@schuermans.info> |
|
3 |
+ Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html |
|
4 |
+ a blinkenarea.org project */ |
|
5 |
+ |
|
6 |
+#include <gif_lib.h> |
|
7 |
+ |
|
8 |
+#include <BlinkenLib/config.h> |
|
9 |
+#include <BlinkenLib/BlinkenConstants.h> |
|
10 |
+#include <BlinkenLib/BlinkenFrame.h> |
|
11 |
+#include <BlinkenLib/BlinkenMovie.h> |
|
12 |
+#include <BlinkenLib/BlinkenGif.h> |
|
13 |
+ |
|
14 |
+// get color from GIF color map |
|
15 |
+static void BlinkenGifGetColor(ColorMapObject *pMap, int idx, int transparent, |
|
16 |
+ unsigned char *r, unsigned char *g, |
|
17 |
+ unsigned char *b, unsigned char *t) |
|
18 |
+{ |
|
19 |
+ if (transparent >= 0 && idx == transparent) { |
|
20 |
+ *t = 1; |
|
21 |
+ } else { |
|
22 |
+ *t = 0; |
|
23 |
+ } |
|
24 |
+ if (pMap != NULL) { |
|
25 |
+ if (idx >= 0 && idx < pMap->ColorCount) { |
|
26 |
+ *r = pMap->Colors[idx].Red; |
|
27 |
+ *g = pMap->Colors[idx].Green; |
|
28 |
+ *b = pMap->Colors[idx].Blue; |
|
29 |
+ } else { |
|
30 |
+ *r = 0; |
|
31 |
+ *g = 0; |
|
32 |
+ *b = 0; |
|
33 |
+ *t = 1; |
|
34 |
+ } |
|
35 |
+ } else { |
|
36 |
+ *r = 0; |
|
37 |
+ *g = 0; |
|
38 |
+ *b = 0; |
|
39 |
+ *t = 1; |
|
40 |
+ } |
|
41 |
+} |
|
42 |
+ |
|
43 |
+// set pixel to GIF color |
|
44 |
+static void BlinkenGifSetPixel(ColorMapObject *pMap, int idx, int transparent, |
|
45 |
+ stBlinkenFrame *pFrame, int y, int x) |
|
46 |
+{ |
|
47 |
+ unsigned char r, g, b, t; |
|
48 |
+ |
|
49 |
+ if (pFrame != NULL) { |
|
50 |
+ BlinkenGifGetColor(pMap, idx, transparent, &r, &g, &b, &t); |
|
51 |
+ if (! t) { |
|
52 |
+ BlinkenFrameSetPixel(pFrame, y, x, 0, r); |
|
53 |
+ BlinkenFrameSetPixel(pFrame, y, x, 1, g); |
|
54 |
+ BlinkenFrameSetPixel(pFrame, y, x, 2, b); |
|
55 |
+ } |
|
56 |
+ } |
|
57 |
+} |
|
58 |
+ |
|
59 |
+// load a GIF file as BlinkenMovie |
|
60 |
+stBlinkenMovie *BlinkenGifLoad(const char *pFilename) |
|
61 |
+{ |
|
62 |
+ GifFileType *gif; |
|
63 |
+ int height, width, frameCnt, frameIdx, i, y, x, |
|
64 |
+ bg, disposal, delay, transp, idx; |
|
65 |
+ ColorMapObject *pGlobalMap, *pMap; |
|
66 |
+ SavedImage *pImg; |
|
67 |
+ GifImageDesc *pDesc; |
|
68 |
+ ExtensionBlock *pEx; |
|
69 |
+ stBlinkenMovie *pMovie; |
|
70 |
+ stBlinkenFrame *pBack, *pFrame; |
|
71 |
+ |
|
72 |
+ if (pFilename == NULL) |
|
73 |
+ return NULL; |
|
74 |
+ |
|
75 |
+ // open GIF file for decoding |
|
76 |
+ gif = DGifOpenFileName(pFilename); |
|
77 |
+ if (gif == NULL) { |
|
78 |
+ return NULL; |
|
79 |
+ } |
|
80 |
+ |
|
81 |
+ // read GIF file |
|
82 |
+ if (DGifSlurp(gif) != GIF_OK) { |
|
83 |
+ DGifCloseFile(gif); |
|
84 |
+ return NULL; |
|
85 |
+ } |
|
86 |
+ height = gif->SHeight; |
|
87 |
+ width = gif->SWidth; |
|
88 |
+ frameCnt = gif->ImageCount; |
|
89 |
+ pGlobalMap = gif->SColorMap; |
|
90 |
+ bg = gif->SBackGroundColor; |
|
91 |
+ |
|
92 |
+ // create movie |
|
93 |
+ pMovie = BlinkenMovieNew(height, width, 3, 255); |
|
94 |
+ if (! pMovie) { |
|
95 |
+ DGifCloseFile(gif); |
|
96 |
+ return NULL; |
|
97 |
+ } |
|
98 |
+ |
|
99 |
+ // create background frame and set it to background color |
|
100 |
+ pBack = BlinkenFrameNew(height, width, 3, 255, 1); |
|
101 |
+ if (! pBack) { |
|
102 |
+ BlinkenMovieFree(pMovie); |
|
103 |
+ DGifCloseFile(gif); |
|
104 |
+ return NULL; |
|
105 |
+ } |
|
106 |
+ for (y = 0; y < height; ++y) { |
|
107 |
+ for (x = 0; x < width; ++x) { |
|
108 |
+ BlinkenGifSetPixel(pGlobalMap, bg, -1, pBack, y, x); |
|
109 |
+ } |
|
110 |
+ } |
|
111 |
+ |
|
112 |
+ // process all frames |
|
113 |
+ for (frameIdx = 0; frameIdx < frameCnt; ++frameIdx) { |
|
114 |
+ pImg = &gif->SavedImages[frameIdx]; |
|
115 |
+ pDesc = &pImg->ImageDesc; |
|
116 |
+ |
|
117 |
+ // get local color map |
|
118 |
+ pMap = pDesc->ColorMap != NULL ? pDesc->ColorMap : pGlobalMap; |
|
119 |
+ |
|
120 |
+ // get disposal mode, delay and transparent color |
|
121 |
+ disposal = 0; |
|
122 |
+ delay = 100; |
|
123 |
+ transp = -1; |
|
124 |
+ for (i = 0; i < pImg->ExtensionBlockCount; ++i) { |
|
125 |
+ pEx = &pImg->ExtensionBlocks[i]; |
|
126 |
+ if (pEx->Function == GRAPHICS_EXT_FUNC_CODE && pEx->ByteCount == 4) { |
|
127 |
+ disposal = pEx->Bytes[0] >> 2 & 0x07; |
|
128 |
+ delay = (unsigned int)(unsigned char)pEx->Bytes[1] | |
|
129 |
+ (unsigned int)(unsigned char)pEx->Bytes[2] << 8; |
|
130 |
+ transp = pEx->Bytes[0] & 0x01 ? (int)(unsigned char)pEx->Bytes[3] : -1; |
|
131 |
+ } |
|
132 |
+ } |
|
133 |
+ |
|
134 |
+ // draw new frame based on background frame, maybe update background frame |
|
135 |
+ if (delay > 0) { |
|
136 |
+ pFrame = BlinkenFrameClone(pBack); |
|
137 |
+ BlinkenFrameSetDuration(pFrame, delay * 10); // GIF delay is in 10ms |
|
138 |
+ } else { |
|
139 |
+ // frames with no duration -> only effect on background |
|
140 |
+ pFrame = NULL; |
|
141 |
+ } |
|
142 |
+ // FIXME: pDesc->Interlace > 0 |
|
143 |
+ for (y = pDesc->Top, i = 0; y < pDesc->Top + pDesc->Height; ++y) { |
|
144 |
+ for (x = pDesc->Left; x < pDesc->Left + pDesc->Width; ++x, ++i) { |
|
145 |
+ idx = pImg->RasterBits[i]; |
|
146 |
+ switch (disposal) { |
|
147 |
+ // undefined |
|
148 |
+ case 0: |
|
149 |
+ case 4: |
|
150 |
+ case 5: |
|
151 |
+ case 6: |
|
152 |
+ case 7: |
|
153 |
+ // do not dispose -> draw to frame and update background |
|
154 |
+ case 1: |
|
155 |
+ BlinkenGifSetPixel(pMap, idx, transp, pFrame, y, x); |
|
156 |
+ BlinkenGifSetPixel(pMap, idx, transp, pBack, y, x); |
|
157 |
+ break; |
|
158 |
+ // restore background -> draw to frame and reset background |
|
159 |
+ case 2: |
|
160 |
+ BlinkenGifSetPixel(pMap, idx, transp, pFrame, y, x); |
|
161 |
+ BlinkenGifSetPixel(pMap, bg, transp, pBack, y, x); |
|
162 |
+ break; |
|
163 |
+ // restore previous -> draw to frame only |
|
164 |
+ case 3: |
|
165 |
+ BlinkenGifSetPixel(pMap, idx, transp, pFrame, y, x); |
|
166 |
+ break; |
|
167 |
+ } |
|
168 |
+ } |
|
169 |
+ } |
|
170 |
+ |
|
171 |
+ // append frame to movie |
|
172 |
+ if (pFrame) { |
|
173 |
+ if (BlinkenMovieAppendFrame(pMovie, pFrame) != 0) { |
|
174 |
+ BlinkenFrameFree(pFrame); |
|
175 |
+ } |
|
176 |
+ } |
|
177 |
+ |
|
178 |
+ } // for frameIdx |
|
179 |
+ |
|
180 |
+ // delete background frame |
|
181 |
+ BlinkenFrameFree(pBack); |
|
182 |
+ |
|
183 |
+ // close GIF file |
|
184 |
+ DGifCloseFile(gif); |
|
185 |
+ |
|
186 |
+ return pMovie; |
|
187 |
+} |
|
188 |
+ |
... | ... |
@@ -0,0 +1,27 @@ |
1 |
+/* BlinkenLib |
|
2 |
+ Copyright 2004-2016 Stefan Schuermans <stefan@schuermans.info> |
|
3 |
+ Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html |
|
4 |
+ a blinkenarea.org project */ |
|
5 |
+ |
|
6 |
+#ifndef INC_BlinkenLib_BlinkenGif |
|
7 |
+#define INC_BlinkenLib_BlinkenGif |
|
8 |
+ |
|
9 |
+#include <BlinkenLib/config.h> |
|
10 |
+#include <BlinkenLib/BlinkenFrame.h> |
|
11 |
+#include <BlinkenLib/BlinkenMovie.h> |
|
12 |
+ |
|
13 |
+#ifndef BLINKENLIB_CFG_GIF |
|
14 |
+#error This file is to be used for GIF support only. |
|
15 |
+#endif // #ifndef BLINKENLIB_CFG_GIF |
|
16 |
+ |
|
17 |
+#ifdef __cplusplus |
|
18 |
+extern "C" { |
|
19 |
+#endif |
|
20 |
+ |
|
21 |
+stBlinkenMovie *BlinkenGifLoad(const char *pFilename); |
|
22 |
+ |
|
23 |
+#ifdef __cplusplus |
|
24 |
+} // extern "C" |
|
25 |
+#endif |
|
26 |
+ |
|
27 |
+#endif // #ifndef INC_BlinkenLib_BlinkenGif |
... | ... |
@@ -24,6 +24,9 @@ |
24 | 24 |
#ifdef BLINKENLIB_CFG_MNG |
25 | 25 |
#include <BlinkenLib/BlinkenMng.h> |
26 | 26 |
#endif // #ifdef BLINKENLIB_CFG_MNG |
27 |
+#ifdef BLINKENLIB_CFG_GIF |
|
28 |
+#include <BlinkenLib/BlinkenGif.h> |
|
29 |
+#endif // #ifdef BLINKENLIB_CFG_GIF |
|
27 | 30 |
|
28 | 31 |
struct sBlinkenMovie { |
29 | 32 |
int height; |
... | ... |
@@ -1494,6 +1497,15 @@ stBlinkenMovie *BlinkenMovieLoadMng(const char *pFilename) |
1494 | 1497 |
|
1495 | 1498 |
#endif // #ifdef BLINKENLIB_CFG_MNG |
1496 | 1499 |
|
1500 |
+#ifdef BLINKENLIB_CFG_GIF |
|
1501 |
+ |
|
1502 |
+stBlinkenMovie *BlinkenMovieLoadGif(const char *pFilename) |
|
1503 |
+{ |
|
1504 |
+ return BlinkenGifLoad(pFilename); |
|
1505 |
+} |
|
1506 |
+ |
|
1507 |
+#endif // #ifdef BLINKENLIB_CFG_GIF |
|
1508 |
+ |
|
1497 | 1509 |
stBlinkenMovie *BlinkenMovieLoad(const char *pFilename) |
1498 | 1510 |
{ |
1499 | 1511 |
int len; |
... | ... |
@@ -1514,6 +1526,10 @@ stBlinkenMovie *BlinkenMovieLoad(const char *pFilename) |
1514 | 1526 |
if (len > 4 && strcmp(pFilename + len - 4, ".mng") == 0) |
1515 | 1527 |
return BlinkenMovieLoadMng(pFilename); |
1516 | 1528 |
#endif // #ifdef BLINKENLIB_CFG_MNG |
1529 |
+#ifdef BLINKENLIB_CFG_GIF |
|
1530 |
+ if (len > 4 && strcmp(pFilename + len - 4, ".gif") == 0) |
|
1531 |
+ return BlinkenMovieLoadGif(pFilename); |
|
1532 |
+#endif // #ifdef BLINKENLIB_CFG_GIF |
|
1517 | 1533 |
return NULL; |
1518 | 1534 |
} |
1519 | 1535 |
|
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
# BlinkenLib |
2 |
-# Copyright 2004-2014 Stefan Schuermans <stefan@schuermans.info> |
|
2 |
+# Copyright 2004-2016 Stefan Schuermans <stefan@schuermans.info> |
|
3 | 3 |
# Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html |
4 | 4 |
# a blinkenarea.org project |
5 | 5 |
|
... | ... |
@@ -29,7 +29,14 @@ BLINKEN_MNG_O:=BlinkenMng.o |
29 | 29 |
LMNG:=-lmng -lz |
30 | 30 |
endif |
31 | 31 |
|
32 |
-LIB_OBJS=BlinkenColorizer.o BlinkenFrame.o BlinkenMovie.o $(BLINKEN_MNG_O) \ |
|
32 |
+ifeq ($(BLINKENLIB_CFG_GIF),1) |
|
33 |
+BLINKEN_GIF_H:=BlinkenGif.h |
|
34 |
+BLINKEN_GIF_O:=BlinkenGif.o |
|
35 |
+LGIF:=-lgif |
|
36 |
+endif |
|
37 |
+ |
|
38 |
+LIB_OBJS:=BlinkenColorizer.o BlinkenFrame.o BlinkenMovie.o \ |
|
39 |
+ $(BLINKEN_MNG_O) $(BLINKEN_GIF_O) \ |
|
33 | 40 |
BlinkenProto.o Tools.o |
34 | 41 |
|
35 | 42 |
.phony: all clean |
... | ... |
@@ -48,7 +55,7 @@ BlinkenProto.o: BlinkenProto.c BlinkenProto.h BlinkenProtoIntern.h |
48 | 55 |
BlinkenFrame.o: BlinkenFrame.c BlinkenConstants.h BlinkenColorizer.h BlinkenFrame.h BlinkenProto.h BlinkenProtoIntern.h Tools.h |
49 | 56 |
$(CC) $(CFLAGS) -c -o $@ $< |
50 | 57 |
|
51 |
-BlinkenMovie.o: BlinkenMovie.c BlinkenConstants.h BlinkenColorizer.h BlinkenFrame.h BlinkenProto.h BlinkenMovie.h $(BLINKEN_MNG_H) Tools.h config.h |
|
58 |
+BlinkenMovie.o: BlinkenMovie.c BlinkenConstants.h BlinkenColorizer.h BlinkenFrame.h BlinkenProto.h BlinkenMovie.h $(BLINKEN_MNG_H) $(BLINKEN_GIF_H) Tools.h config.h |
|
52 | 59 |
$(CC) $(CFLAGS) -c -o $@ $< |
53 | 60 |
|
54 | 61 |
BlinkenMng.o: BlinkenMng.c BlinkenConstants.h BlinkenColorizer.h BlinkenFrame.h BlinkenProto.h BlinkenMovie.h Tools.h config.h |
... | ... |
@@ -62,7 +69,7 @@ libBlinkenLib.a: $(LIB_OBJS) |
62 | 69 |
$(RANLIB) $@ |
63 | 70 |
|
64 | 71 |
libBlinkenLib.$(SHLIBEXT).$(VERSION): $(LIB_OBJS) |
65 |
- $(CC) -shared $(SONAMEOPT) $(LIB_LFLAGS) -o $@ $+ $(LMNG) |
|
72 |
+ $(CC) -shared $(SONAMEOPT) $(LIB_LFLAGS) -o $@ $+ $(LMNG) $(LGIF) |
|
66 | 73 |
|
67 | 74 |
libBlinkenLib.$(SHLIBEXT).$(VERSION_MAJOR): libBlinkenLib.$(SHLIBEXT).$(VERSION) |
68 | 75 |
rm -f $@ |
... | ... |
@@ -1,5 +1,5 @@ |
1 | 1 |
# BlinkenLib |
2 |
-# Copyright 2004-2014 Stefan Schuermans <stefan@schuermans.info> |
|
2 |
+# Copyright 2004-2016 Stefan Schuermans <stefan@schuermans.info> |
|
3 | 3 |
# Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html |
4 | 4 |
# a blinkenarea.org project |
5 | 5 |
|
... | ... |
@@ -20,7 +20,12 @@ mng.cfg: |
20 | 20 |
(($(CC) $(INCDIR) $(LIBDIR) -o mng mng.c -lmng && ./mng && echo "1") || echo "0") >>mng.cfg |
21 | 21 |
rm -f mng |
22 | 22 |
|
23 |
-config.cfg: osx.cfg mng.cfg |
|
23 |
+gif.cfg: |
|
24 |
+ echo "GIF=" | tr -d '\n' >gif.cfg |
|
25 |
+ (($(CC) $(INCDIR) $(LIBDIR) -o gif gif.c -lgif && ./gif && echo "1") || echo "0") >>gif.cfg |
|
26 |
+ rm -f gif |
|
27 |
+ |
|
28 |
+config.cfg: osx.cfg mng.cfg gif.cfg |
|
24 | 29 |
cat $+ >config.cfg |
25 | 30 |
|
26 | 31 |
config.mk: config.cfg |