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 |