编译uos-amd64版本的giflib库
This commit is contained in:
parent
ba40c13cdf
commit
7f15550da1
|
@ -20,6 +20,7 @@
|
|||
<Add directory="../../../third_party/zlib/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/libpng/uos/amd64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/giflib/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/libzip/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/pdflib/uos/amd64/include" />
|
||||
|
@ -30,6 +31,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/uos/amd64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/uos/amd64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/uos/amd64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/uos/amd64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/uos/amd64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/uos/amd64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/uos/amd64/lib -lz" />
|
||||
|
@ -50,6 +52,7 @@
|
|||
<Add directory="../../../third_party/zlib/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/libpng/uos/amd64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/giflib/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/libzip/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/uos/amd64/include" />
|
||||
<Add directory="../../../third_party/pdflib/uos/amd64/include" />
|
||||
|
@ -61,6 +64,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/uos/amd64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/uos/amd64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/uos/amd64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/uos/amd64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/uos/amd64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/uos/amd64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/uos/amd64/lib -lz" />
|
||||
|
@ -81,6 +85,7 @@
|
|||
<Add directory="../../../third_party/zlib/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/libpng/uos/aarch64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/giflib/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/libzip/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/pdflib/uos/aarch64/include" />
|
||||
|
@ -91,6 +96,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/uos/aarch64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/uos/aarch64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/uos/aarch64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/uos/aarch64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/uos/aarch64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/uos/aarch64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/uos/aarch64/lib -lz" />
|
||||
|
@ -111,6 +117,7 @@
|
|||
<Add directory="../../../third_party/zlib/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/libpng/uos/aarch64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/giflib/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/libzip/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/uos/aarch64/include" />
|
||||
<Add directory="../../../third_party/pdflib/uos/aarch64/include" />
|
||||
|
@ -122,6 +129,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/uos/aarch64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/uos/aarch64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/uos/aarch64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/uos/aarch64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/uos/aarch64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/uos/aarch64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/uos/aarch64/lib -lz" />
|
||||
|
@ -142,6 +150,7 @@
|
|||
<Add directory="../../../third_party/zlib/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/libpng/uos/mips64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/giflib/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/libzip/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/pdflib/uos/mips64/include" />
|
||||
|
@ -152,6 +161,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/uos/mips64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/uos/mips64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/uos/mips64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/uos/mips64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/uos/mips64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/uos/mips64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/uos/mips64/lib -lz" />
|
||||
|
@ -172,6 +182,7 @@
|
|||
<Add directory="../../../third_party/zlib/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/libpng/uos/mips64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/giflib/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/libzip/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/uos/mips64/include" />
|
||||
<Add directory="../../../third_party/pdflib/uos/mips64/include" />
|
||||
|
@ -183,6 +194,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/uos/mips64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/uos/mips64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/uos/mips64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/uos/mips64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/uos/mips64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/uos/mips64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/uos/mips64/lib -lz" />
|
||||
|
@ -203,6 +215,7 @@
|
|||
<Add directory="../../../third_party/zlib/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/libpng/kylin/amd64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/giflib/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/libzip/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/pdflib/kylin/amd64/include" />
|
||||
|
@ -213,6 +226,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/kylin/amd64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/kylin/amd64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/kylin/amd64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/kylin/amd64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/kylin/amd64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/kylin/amd64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/kylin/amd64/lib -lz" />
|
||||
|
@ -233,6 +247,7 @@
|
|||
<Add directory="../../../third_party/zlib/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/libpng/kylin/amd64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/giflib/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/libzip/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/kylin/amd64/include" />
|
||||
<Add directory="../../../third_party/pdflib/kylin/amd64/include" />
|
||||
|
@ -244,6 +259,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/kylin/amd64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/kylin/amd64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/kylin/amd64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/kylin/amd64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/kylin/amd64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/kylin/amd64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/kylin/amd64/lib -lz" />
|
||||
|
@ -264,6 +280,7 @@
|
|||
<Add directory="../../../third_party/zlib/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/libpng/kylin/aarch64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/giflib/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/libzip/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/pdflib/kylin/aarch64/include" />
|
||||
|
@ -274,6 +291,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/kylin/aarch64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/kylin/aarch64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/kylin/aarch64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/kylin/aarch64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/kylin/aarch64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/kylin/aarch64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/kylin/aarch64/lib -lz" />
|
||||
|
@ -294,6 +312,7 @@
|
|||
<Add directory="../../../third_party/zlib/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/libpng/kylin/aarch64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/giflib/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/libzip/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/kylin/aarch64/include" />
|
||||
<Add directory="../../../third_party/pdflib/kylin/aarch64/include" />
|
||||
|
@ -305,6 +324,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/kylin/aarch64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/kylin/aarch64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/kylin/aarch64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/kylin/aarch64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/kylin/aarch64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/kylin/aarch64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/kylin/aarch64/lib -lz" />
|
||||
|
@ -325,6 +345,7 @@
|
|||
<Add directory="../../../third_party/zlib/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/libpng/kylin/mips64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/giflib/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/libzip/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/pdflib/kylin/mips64/include" />
|
||||
|
@ -335,6 +356,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/kylin/mips64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/kylin/mips64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/kylin/mips64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/kylin/mips64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/kylin/mips64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/kylin/mips64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/kylin/mips64/lib -lz" />
|
||||
|
@ -355,6 +377,7 @@
|
|||
<Add directory="../../../third_party/zlib/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/libpng/kylin/mips64/include/libpng16" />
|
||||
<Add directory="../../../third_party/libtiff/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/giflib/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/libzip/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/tinyxml2/kylin/mips64/include" />
|
||||
<Add directory="../../../third_party/pdflib/kylin/mips64/include" />
|
||||
|
@ -366,6 +389,7 @@
|
|||
<Add option="-L../../../third_party/libnsbmp/kylin/mips64/lib -lnsbmp" />
|
||||
<Add option="-L../../../third_party/libpng/kylin/mips64/lib -lpng16" />
|
||||
<Add option="-L../../../third_party/libtiff/kylin/mips64/lib -ltiff" />
|
||||
<Add option="-L../../../third_party/giflib/kylin/mips64/lib -lgiflib" />
|
||||
<Add option="-L../../../third_party/libzip/kylin/mips64/lib -lzip" />
|
||||
<Add option="-L../../../third_party/tinyxml2/kylin/mips64/lib -ltinyxml2" />
|
||||
<Add option="-L../../../third_party/zlib/kylin/mips64/lib -lz" />
|
||||
|
@ -386,6 +410,8 @@
|
|||
</Linker>
|
||||
<Unit filename="../../../modules/imgfmt/HGBmp.cpp" />
|
||||
<Unit filename="../../../modules/imgfmt/HGBmp.h" />
|
||||
<Unit filename="../../../modules/imgfmt/HGGif.cpp" />
|
||||
<Unit filename="../../../modules/imgfmt/HGGif.h" />
|
||||
<Unit filename="../../../modules/imgfmt/HGImgFmt.cpp" />
|
||||
<Unit filename="../../../modules/imgfmt/HGImgFmt.h" />
|
||||
<Unit filename="../../../modules/imgfmt/HGImgFmtErr.h" />
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,639 @@
|
|||
/***************************************************************************
|
||||
|
||||
getarg.c - routines to grab the parameters from the command line:
|
||||
|
||||
Names of all the routines except the main one start with GA (Get
|
||||
Arguments) to prevent conflicts.
|
||||
|
||||
The following routines are available in this module:
|
||||
|
||||
1. int GAGetArgs(argc, argv, CtrlStr, Variables...)
|
||||
where argc, argv are received on entry.
|
||||
CtrlStr is the contrl string (see below)
|
||||
Variables are all the variables to be set according to CtrlStr.
|
||||
Note that all the variables MUST be transfered by address.
|
||||
Return 0 on correct parsing, otherwise error number (see GetArg.h).
|
||||
|
||||
2. GAPrintHowTo(CtrlStr)
|
||||
Print the control string to stderr, in the correct format.
|
||||
This feature is very useful in case of an error during GetArgs parsing.
|
||||
Chars equal to SPACE_CHAR are not printed (regular spaces are NOT
|
||||
allowed, and so using SPACE_CHAR you can create space in PrintHowTo).
|
||||
|
||||
3. GAPrintErrMsg(Error)
|
||||
Describe the error to stderr, according to Error (usually returned by
|
||||
GAGetArgs).
|
||||
|
||||
CtrlStr format:
|
||||
|
||||
The control string passed to GetArgs controls the way argv (argc) are
|
||||
parsed. Each entry in this string must not have any spaces in it. The
|
||||
First Entry is the name of the program, which is usually ignored except
|
||||
when GAPrintHowTo is called. All the other entries (except the last one
|
||||
which we will come back to later) must have the following format:
|
||||
|
||||
1. One letter which sets the option letter.
|
||||
2. '!' or '%' to determines if this option is really optional ('%') or
|
||||
required ('!')...
|
||||
3. '-' must always be given.
|
||||
4. Alphanumeric string, usually ignored, but used by GAPrintHowTo to
|
||||
print the meaning of this option.
|
||||
5. Sequences starts with '!' or '%'. Again if '!' then this sequence
|
||||
must exist (only if its option flag is given of course), and if '%'
|
||||
it is optional. Each sequence will continue with one or two
|
||||
characters which defines the kind of the input:
|
||||
a: d, x, o, u - integer is expected (decimal, hex, octal base or unsigned).
|
||||
b: D, X, O, U - long integer is expected (same as above).
|
||||
c: f - float number is expected.
|
||||
d: F - double number is expected.
|
||||
e: s - string is expected.
|
||||
f: *? - any number of '?' kind (d, x, o, u, D, X, O, U, f, F, s)
|
||||
will match this one. If '?' is numeric, it scans until
|
||||
non-numeric input is given. If '?' is 's' then it scans
|
||||
up to the next option or end of argv.
|
||||
|
||||
If the last parameter given in the CtrlStr, is not an option (i.e. the
|
||||
second char is not in ['!', '%'] and the third one is not '-'), all what
|
||||
remained from argv is linked to it.
|
||||
|
||||
The variables passed to GAGetArgs (starting from 4th parameter) MUST
|
||||
match the order of the CtrlStr:
|
||||
|
||||
For each option, one integer address must be passed. This integer must
|
||||
be initialized with 0. If that option is given in the command line, it will
|
||||
be set.
|
||||
|
||||
In addition, the sequences that might follow an option require the
|
||||
following parameters to pass:
|
||||
|
||||
1. d, x, o, u - pointer to integer (int *).
|
||||
2. D, X, O, U - pointer to long (long *).
|
||||
3. f - pointer to float (float *).
|
||||
4. F - pointer to double (double *).
|
||||
5. s - pointer to char (char *). NO allocation is needed!
|
||||
6. *? - TWO variables are passed for each wild request. the first
|
||||
one is (address of) integer, and it will return number of
|
||||
parameters actually matched this sequence, and the second
|
||||
one is a pointer to pointer to ? (? **), and will return an
|
||||
address to a block of pointers to ? kind, terminated with
|
||||
NULL pointer. NO pre-allocation is required. The caller is
|
||||
responsible for freeing this memory, including the pointed to
|
||||
memory.
|
||||
|
||||
Note that these two variables are pretty like the argv/argc pair...
|
||||
|
||||
Examples:
|
||||
|
||||
"Example1 i%-OneInteger!d s%-Strings!*s j%- k!-Float!f Files"
|
||||
|
||||
Will match: Example1 -i 77 -s String1 String2 String3 -k 88.2 File1 File2
|
||||
or: Example1 -s String1 -k 88.3 -i 999 -j
|
||||
but not: Example1 -i 77 78 (option i expects one integer, k must be).
|
||||
|
||||
Note the option k must exist, and that the order of the options is not
|
||||
important. In the first examples File1 & File2 will match the Files
|
||||
in the command line.
|
||||
|
||||
A call to GAPrintHowTo with this CtrlStr will print to stderr:
|
||||
Example1 [-i OneIngeter] [-s Strings...] [-j] -k Float Files...
|
||||
|
||||
Notes:
|
||||
|
||||
1. This module assumes that all the pointers to all kind of data types
|
||||
have the same length and format, i.e. sizeof(int *) == sizeof(char *).
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
**************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "getarg.h"
|
||||
|
||||
#define MAX_PARAM 100 /* maximum number of parameters allowed. */
|
||||
#define CTRL_STR_MAX_LEN 1024
|
||||
|
||||
#define SPACE_CHAR '|' /* The character not to print using HowTo. */
|
||||
|
||||
#define ARG_OK false
|
||||
|
||||
#define ISSPACE(x) ((x) <= ' ') /* Not conventional - but works fine! */
|
||||
|
||||
/* The two characters '%' and '!' are used in the control string: */
|
||||
#define ISCTRLCHAR(x) (((x) == '%') || ((x) == '!'))
|
||||
|
||||
static char *GAErrorToken; /* On error, ErrorToken is set to point to it. */
|
||||
static int GATestAllSatis(char *CtrlStrCopy, char *CtrlStr, char **argv_end,
|
||||
char ***argv, void *Parameters[MAX_PARAM],
|
||||
int *ParamCount);
|
||||
static bool GAUpdateParameters(void *Parameters[], int *ParamCount,
|
||||
char *Option, char *CtrlStrCopy, char *CtrlStr,
|
||||
char **argv_end, char ***argv);
|
||||
static int GAGetParmeters(void *Parameters[], int *ParamCount,
|
||||
char *CtrlStrCopy, char *Option, char **argv_end,
|
||||
char ***argv);
|
||||
static int GAGetMultiParmeters(void *Parameters[], int *ParamCount,
|
||||
char *CtrlStrCopy, char **argv_end, char ***argv);
|
||||
static void GASetParamCount(char *CtrlStr, int Max, int *ParamCount);
|
||||
static bool GAOptionExists(char **argv_end, char **argv);
|
||||
|
||||
/***************************************************************************
|
||||
Allocate or die
|
||||
***************************************************************************/
|
||||
static void *
|
||||
xmalloc(unsigned size) {
|
||||
|
||||
void *p;
|
||||
|
||||
if ((p = malloc(size)) != NULL)
|
||||
return p;
|
||||
|
||||
fprintf(stderr, "Not enough memory, exit.\n");
|
||||
exit(2);
|
||||
|
||||
return NULL; /* Makes warning silent. */
|
||||
}
|
||||
/***************************************************************************
|
||||
Routine to access the command line argument and interpret them:
|
||||
Return ARG_OK (0) is case of successful parsing, error code else...
|
||||
***************************************************************************/
|
||||
bool
|
||||
GAGetArgs(int argc,
|
||||
char **argv,
|
||||
char *CtrlStr, ...) {
|
||||
|
||||
int i, ParamCount = 0;
|
||||
void *Parameters[MAX_PARAM]; /* Save here parameter addresses. */
|
||||
char CtrlStrCopy[CTRL_STR_MAX_LEN];
|
||||
char **argv_end = argv + argc;
|
||||
va_list ap;
|
||||
|
||||
strncpy(CtrlStrCopy, CtrlStr, sizeof(CtrlStrCopy)-1);
|
||||
GASetParamCount(CtrlStr, strlen(CtrlStr), &ParamCount);
|
||||
va_start(ap, CtrlStr);
|
||||
for (i = 1; i <= ParamCount; i++)
|
||||
Parameters[i - 1] = va_arg(ap, void *);
|
||||
va_end(ap);
|
||||
|
||||
argv++; /* Skip the program name (first in argv/c list). */
|
||||
while (argv < argv_end) {
|
||||
bool Error = false;
|
||||
if (!GAOptionExists(argv_end, argv))
|
||||
break; /* The loop. */
|
||||
char *Option = *argv++;
|
||||
if ((Error = GAUpdateParameters(Parameters, &ParamCount, Option,
|
||||
CtrlStrCopy, CtrlStr, argv_end,
|
||||
&argv)) != false)
|
||||
return Error;
|
||||
}
|
||||
/* Check for results and update trail of command line: */
|
||||
return GATestAllSatis(CtrlStrCopy, CtrlStr, argv_end, &argv, Parameters,
|
||||
&ParamCount) != ARG_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to search for unsatisfied flags - simply scan the list for !-
|
||||
sequence. Before this scan, this routine updates the rest of the command
|
||||
line into the last two parameters if it is requested by the CtrlStr
|
||||
(last item in CtrlStr is NOT an option).
|
||||
Return ARG_OK if all satisfied, CMD_ERR_AllSatis error else.
|
||||
***************************************************************************/
|
||||
static int
|
||||
GATestAllSatis(char *CtrlStrCopy,
|
||||
char *CtrlStr,
|
||||
char **argv_end,
|
||||
char ***argv,
|
||||
void *Parameters[MAX_PARAM],
|
||||
int *ParamCount) {
|
||||
|
||||
int i;
|
||||
static char *LocalToken = NULL;
|
||||
|
||||
/* If LocalToken is not initialized - do it now. Note that this string
|
||||
* should be writable as well so we can not assign it directly.
|
||||
*/
|
||||
if (LocalToken == NULL) {
|
||||
LocalToken = (char *)malloc(3);
|
||||
strcpy(LocalToken, "-?");
|
||||
}
|
||||
|
||||
/* Check if last item is an option. If not then copy rest of command
|
||||
* line into it as 1. NumOfprm, 2. pointer to block of pointers.
|
||||
*/
|
||||
for (i = strlen(CtrlStr) - 1; i > 0 && !ISSPACE(CtrlStr[i]); i--) ;
|
||||
if (!ISCTRLCHAR(CtrlStr[i + 2])) {
|
||||
GASetParamCount(CtrlStr, i, ParamCount); /* Point in correct param. */
|
||||
*(int *)Parameters[(*ParamCount)++] = argv_end - *argv;
|
||||
*(char ***)Parameters[(*ParamCount)++] = *argv;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (++i < (int)strlen(CtrlStrCopy))
|
||||
if ((CtrlStrCopy[i] == '-') && (CtrlStrCopy[i - 1] == '!')) {
|
||||
GAErrorToken = LocalToken;
|
||||
LocalToken[1] = CtrlStrCopy[i - 2]; /* Set the correct flag. */
|
||||
return CMD_ERR_AllSatis;
|
||||
}
|
||||
|
||||
return ARG_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to update the parameters according to the given Option:
|
||||
**************************************************************************/
|
||||
static bool
|
||||
GAUpdateParameters(void *Parameters[],
|
||||
int *ParamCount,
|
||||
char *Option,
|
||||
char *CtrlStrCopy,
|
||||
char *CtrlStr,
|
||||
char **argv_end,
|
||||
char ***argv) {
|
||||
|
||||
int i;
|
||||
bool BooleanTrue = Option[2] != '-';
|
||||
|
||||
if (Option[0] != '-') {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_NotAnOpt;
|
||||
}
|
||||
i = 0; /* Scan the CtrlStrCopy for that option: */
|
||||
while (i + 2 < (int)strlen(CtrlStrCopy)) {
|
||||
if ((CtrlStrCopy[i] == Option[1]) && (ISCTRLCHAR(CtrlStrCopy[i + 1]))
|
||||
&& (CtrlStrCopy[i + 2] == '-')) {
|
||||
/* We found that option! */
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i + 2 >= (int)strlen(CtrlStrCopy)) {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_NoSuchOpt;
|
||||
}
|
||||
|
||||
/* If we are here, then we found that option in CtrlStr - Strip it off: */
|
||||
CtrlStrCopy[i] = CtrlStrCopy[i + 1] = CtrlStrCopy[i + 2] = (char)' ';
|
||||
GASetParamCount(CtrlStr, i, ParamCount); /* Set it to point in
|
||||
correct prm. */
|
||||
i += 3;
|
||||
/* Set boolean flag for that option. */
|
||||
*(bool *)Parameters[(*ParamCount)++] = BooleanTrue;
|
||||
if (ISSPACE(CtrlStrCopy[i]))
|
||||
return ARG_OK; /* Only a boolean flag is needed. */
|
||||
|
||||
/* Skip the text between the boolean option and data follows: */
|
||||
while (!ISCTRLCHAR(CtrlStrCopy[i]))
|
||||
i++;
|
||||
/* Get the parameters and return the appropriete return code: */
|
||||
return GAGetParmeters(Parameters, ParamCount, &CtrlStrCopy[i],
|
||||
Option, argv_end, argv);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to get parameters according to the CtrlStr given from argv/argc
|
||||
***************************************************************************/
|
||||
static int
|
||||
GAGetParmeters(void *Parameters[],
|
||||
int *ParamCount,
|
||||
char *CtrlStrCopy,
|
||||
char *Option,
|
||||
char **argv_end,
|
||||
char ***argv) {
|
||||
|
||||
int i = 0, ScanRes;
|
||||
|
||||
while (!(ISSPACE(CtrlStrCopy[i]))) {
|
||||
switch (CtrlStrCopy[i + 1]) {
|
||||
case 'd': /* Get signed integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%d",
|
||||
(int *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'u': /* Get unsigned integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%u",
|
||||
(unsigned *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'x': /* Get hex integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%x",
|
||||
(unsigned int *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'o': /* Get octal integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%o",
|
||||
(unsigned int *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'D': /* Get signed long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%ld",
|
||||
(long *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'U': /* Get unsigned long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lu",
|
||||
(unsigned long *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'X': /* Get hex long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lx",
|
||||
(unsigned long *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'O': /* Get octal long integers. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lo",
|
||||
(unsigned long *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'f': /* Get float number. */
|
||||
ScanRes = sscanf(*((*argv)++), "%f",
|
||||
(float *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 'F': /* Get double float number. */
|
||||
ScanRes = sscanf(*((*argv)++), "%lf",
|
||||
(double *)Parameters[(*ParamCount)++]);
|
||||
break;
|
||||
case 's': /* It as a string. */
|
||||
ScanRes = 1; /* Allways O.K. */
|
||||
*(char **)Parameters[(*ParamCount)++] = *((*argv)++);
|
||||
break;
|
||||
case '*': /* Get few parameters into one: */
|
||||
ScanRes = GAGetMultiParmeters(Parameters, ParamCount,
|
||||
&CtrlStrCopy[i], argv_end, argv);
|
||||
if ((ScanRes == 0) && (CtrlStrCopy[i] == '!')) {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_WildEmpty;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ScanRes = 0; /* Make optimizer warning silent. */
|
||||
}
|
||||
/* If reading fails and this number is a must (!) then error: */
|
||||
if ((ScanRes == 0) && (CtrlStrCopy[i] == '!')) {
|
||||
GAErrorToken = Option;
|
||||
return CMD_ERR_NumRead;
|
||||
}
|
||||
if (CtrlStrCopy[i + 1] != '*') {
|
||||
i += 2; /* Skip to next parameter (if any). */
|
||||
} else
|
||||
i += 3; /* Skip the '*' also! */
|
||||
}
|
||||
|
||||
return ARG_OK;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to get a few parameters into one pointer such that the returned
|
||||
pointer actually points on a block of pointers to the parameters...
|
||||
For example *F means a pointer to pointers on floats.
|
||||
Returns number of parameters actually read.
|
||||
This routine assumes that all pointers (on any kind of scalar) has the
|
||||
same size (and the union below is totally ovelapped bteween dif. arrays)
|
||||
***************************************************************************/
|
||||
static int
|
||||
GAGetMultiParmeters(void *Parameters[],
|
||||
int *ParamCount,
|
||||
char *CtrlStrCopy,
|
||||
char **argv_end,
|
||||
char ***argv) {
|
||||
|
||||
int i = 0, ScanRes, NumOfPrm = 0;
|
||||
void **Pmain, **Ptemp;
|
||||
union TmpArray { /* Save here the temporary data before copying it to */
|
||||
void *VoidArray[MAX_PARAM]; /* the returned pointer block. */
|
||||
int *IntArray[MAX_PARAM];
|
||||
long *LngArray[MAX_PARAM];
|
||||
float *FltArray[MAX_PARAM];
|
||||
double *DblArray[MAX_PARAM];
|
||||
char *ChrArray[MAX_PARAM];
|
||||
} TmpArray;
|
||||
|
||||
do {
|
||||
switch (CtrlStrCopy[2]) { /* CtrlStr == '!*?' or '%*?' where ? is. */
|
||||
case 'd': /* Format to read the parameters: */
|
||||
TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%d",
|
||||
(int *)TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'u':
|
||||
TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%u",
|
||||
(unsigned int *)TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'o':
|
||||
TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%o",
|
||||
(unsigned int *)TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'x':
|
||||
TmpArray.IntArray[NumOfPrm] = xmalloc(sizeof(int));
|
||||
ScanRes = sscanf(*((*argv)++), "%x",
|
||||
(unsigned int *)TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'D':
|
||||
TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%ld",
|
||||
(long *)TmpArray.IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'U':
|
||||
TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%lu",
|
||||
(unsigned long *)TmpArray.
|
||||
IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'O':
|
||||
TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%lo",
|
||||
(unsigned long *)TmpArray.
|
||||
IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'X':
|
||||
TmpArray.LngArray[NumOfPrm] = xmalloc(sizeof(long));
|
||||
ScanRes = sscanf(*((*argv)++), "%lx",
|
||||
(unsigned long *)TmpArray.
|
||||
IntArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'f':
|
||||
TmpArray.FltArray[NumOfPrm] = xmalloc(sizeof(float));
|
||||
ScanRes = sscanf(*((*argv)++), "%f",
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
(float *)TmpArray.LngArray[NumOfPrm++]);
|
||||
break;
|
||||
case 'F':
|
||||
TmpArray.DblArray[NumOfPrm] = xmalloc(sizeof(double));
|
||||
ScanRes = sscanf(*((*argv)++), "%lf",
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
(double *)TmpArray.LngArray[NumOfPrm++]);
|
||||
break;
|
||||
case 's':
|
||||
while ((*argv < argv_end) && ((**argv)[0] != '-')) {
|
||||
TmpArray.ChrArray[NumOfPrm++] = *((*argv)++);
|
||||
}
|
||||
ScanRes = 0; /* Force quit from do - loop. */
|
||||
NumOfPrm++; /* Updated again immediately after loop! */
|
||||
(*argv)++; /* "" */
|
||||
break;
|
||||
default:
|
||||
ScanRes = 0; /* Make optimizer warning silent. */
|
||||
}
|
||||
}
|
||||
while (ScanRes == 1); /* Exactly one parameter was read. */
|
||||
(*argv)--;
|
||||
NumOfPrm--;
|
||||
|
||||
/* Now allocate the block with the exact size, and set it: */
|
||||
Ptemp = Pmain = xmalloc((unsigned)(NumOfPrm + 1) * sizeof(void *));
|
||||
/* And here we use the assumption that all pointers are the same: */
|
||||
for (i = 0; i < NumOfPrm; i++)
|
||||
*Ptemp++ = TmpArray.VoidArray[i];
|
||||
*Ptemp = NULL; /* Close the block with NULL pointer. */
|
||||
|
||||
/* That it save the number of parameters read as first parameter to
|
||||
* return and the pointer to the block as second, and return: */
|
||||
*(int *)Parameters[(*ParamCount)++] = NumOfPrm;
|
||||
*(void ***)Parameters[(*ParamCount)++] = Pmain;
|
||||
/* free(Pmain); -- can not free here as caller needs to access memory */
|
||||
return NumOfPrm;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to scan the CtrlStr, up to Max and count the number of parameters
|
||||
to that point:
|
||||
1. Each option is counted as one parameter - boolean variable (int)
|
||||
2. Within an option, each %? or !? is counted once - pointer to something
|
||||
3. Within an option, %*? or !*? is counted twice - one for item count
|
||||
and one for pointer to block pointers.
|
||||
Note ALL variables are passed by address and so of fixed size (address).
|
||||
***************************************************************************/
|
||||
static void
|
||||
GASetParamCount(char *CtrlStr,
|
||||
int Max,
|
||||
int *ParamCount) {
|
||||
int i;
|
||||
|
||||
*ParamCount = 0;
|
||||
for (i = 0; i < Max; i++)
|
||||
if (ISCTRLCHAR(CtrlStr[i])) {
|
||||
if (CtrlStr[i + 1] == '*')
|
||||
*ParamCount += 2;
|
||||
else
|
||||
(*ParamCount)++;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to check if more option (i.e. first char == '-') exists in the
|
||||
given list argc, argv:
|
||||
***************************************************************************/
|
||||
static bool
|
||||
GAOptionExists(char **argv_end,
|
||||
char **argv) {
|
||||
|
||||
while (argv < argv_end)
|
||||
if ((*argv++)[0] == '-')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to print some error messages, for this module:
|
||||
***************************************************************************/
|
||||
void
|
||||
GAPrintErrMsg(int Error) {
|
||||
|
||||
fprintf(stderr, "Error in command line parsing - ");
|
||||
switch (Error) {
|
||||
case 0:;
|
||||
fprintf(stderr, "Undefined error");
|
||||
break;
|
||||
case CMD_ERR_NotAnOpt:
|
||||
fprintf(stderr, "None option Found");
|
||||
break;
|
||||
case CMD_ERR_NoSuchOpt:
|
||||
fprintf(stderr, "Undefined option Found");
|
||||
break;
|
||||
case CMD_ERR_WildEmpty:
|
||||
fprintf(stderr, "Empty input for '!*?' seq.");
|
||||
break;
|
||||
case CMD_ERR_NumRead:
|
||||
fprintf(stderr, "Failed on reading number");
|
||||
break;
|
||||
case CMD_ERR_AllSatis:
|
||||
fprintf(stderr, "Fail to satisfy");
|
||||
break;
|
||||
}
|
||||
fprintf(stderr, " - '%s'.\n", GAErrorToken);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Routine to print correct format of command line allowed:
|
||||
***************************************************************************/
|
||||
void
|
||||
GAPrintHowTo(char *CtrlStr) {
|
||||
|
||||
int i = 0;
|
||||
bool SpaceFlag;
|
||||
|
||||
fprintf(stderr, "Usage: ");
|
||||
/* Print program name - first word in ctrl. str. (optional): */
|
||||
while (!(ISSPACE(CtrlStr[i])) && (!ISCTRLCHAR(CtrlStr[i + 1])))
|
||||
fprintf(stderr, "%c", CtrlStr[i++]);
|
||||
|
||||
while (i < (int)strlen(CtrlStr)) {
|
||||
// cppcheck-suppress arrayIndexThenCheck
|
||||
while ((ISSPACE(CtrlStr[i])) && (i < (int)strlen(CtrlStr)))
|
||||
i++;
|
||||
switch (CtrlStr[i + 1]) {
|
||||
case '%':
|
||||
fprintf(stderr, " [-%c", CtrlStr[i++]);
|
||||
i += 2; /* Skip the '%-' or '!- after the char! */
|
||||
SpaceFlag = true;
|
||||
while (!ISCTRLCHAR(CtrlStr[i]) && (i < (int)strlen(CtrlStr)) &&
|
||||
(!ISSPACE(CtrlStr[i])))
|
||||
if (SpaceFlag) {
|
||||
if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, " %c", CtrlStr[i - 1]);
|
||||
SpaceFlag = false;
|
||||
} else if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, "%c", CtrlStr[i - 1]);
|
||||
while (!ISSPACE(CtrlStr[i]) && (i < (int)strlen(CtrlStr))) {
|
||||
if (CtrlStr[i] == '*')
|
||||
fprintf(stderr, "...");
|
||||
i++; /* Skip the rest of it. */
|
||||
}
|
||||
fprintf(stderr, "]");
|
||||
break;
|
||||
case '!':
|
||||
fprintf(stderr, " -%c", CtrlStr[i++]);
|
||||
i += 2; /* Skip the '%-' or '!- after the char! */
|
||||
SpaceFlag = true;
|
||||
while (!ISCTRLCHAR(CtrlStr[i]) && (i < (int)strlen(CtrlStr)) &&
|
||||
(!ISSPACE(CtrlStr[i])))
|
||||
if (SpaceFlag) {
|
||||
if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, " %c", CtrlStr[i - 1]);
|
||||
SpaceFlag = false;
|
||||
} else if (CtrlStr[i++] == SPACE_CHAR)
|
||||
fprintf(stderr, " ");
|
||||
else
|
||||
fprintf(stderr, "%c", CtrlStr[i - 1]);
|
||||
while (!ISSPACE(CtrlStr[i]) && (i < (int)strlen(CtrlStr))) {
|
||||
if (CtrlStr[i] == '*')
|
||||
fprintf(stderr, "...");
|
||||
i++; /* Skip the rest of it. */
|
||||
}
|
||||
break;
|
||||
default: /* Not checked, but must be last one! */
|
||||
fprintf(stderr, " ");
|
||||
while (!ISSPACE(CtrlStr[i]) && (i < (int)strlen(CtrlStr)) &&
|
||||
!ISCTRLCHAR(CtrlStr[i]))
|
||||
fprintf(stderr, "%c", CtrlStr[i++]);
|
||||
fprintf(stderr, "\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,52 @@
|
|||
/***************************************************************************
|
||||
|
||||
getarg.h - Support routines for the giflib utilities
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef _GETARG_H
|
||||
#define _GETARG_H
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#define VERSION_COOKIE " Version %d.%d, "
|
||||
|
||||
/***************************************************************************
|
||||
Error numbers as returned by GAGetArg routine:
|
||||
***************************************************************************/
|
||||
#define CMD_ERR_NotAnOpt 1 /* None Option found. */
|
||||
#define CMD_ERR_NoSuchOpt 2 /* Undefined Option Found. */
|
||||
#define CMD_ERR_WildEmpty 3 /* Empty input for !*? seq. */
|
||||
#define CMD_ERR_NumRead 4 /* Failed on reading number. */
|
||||
#define CMD_ERR_AllSatis 5 /* Fail to satisfy (must-'!') option. */
|
||||
|
||||
bool GAGetArgs(int argc, char **argv, char *CtrlStr, ...);
|
||||
void GAPrintErrMsg(int Error);
|
||||
void GAPrintHowTo(char *CtrlStr);
|
||||
|
||||
/******************************************************************************
|
||||
From qprintf.c
|
||||
******************************************************************************/
|
||||
extern bool GifNoisyPrint;
|
||||
extern void GifQprintf(char *Format, ...);
|
||||
extern void PrintGifError(int ErrorCode);
|
||||
|
||||
/******************************************************************************
|
||||
Color table quantization
|
||||
******************************************************************************/
|
||||
int GifQuantizeBuffer(unsigned int Width, unsigned int Height,
|
||||
int *ColorMapSize, GifByteType * RedInput,
|
||||
GifByteType * GreenInput, GifByteType * BlueInput,
|
||||
GifByteType * OutputBuffer,
|
||||
GifColorType * OutputColorMap);
|
||||
|
||||
/* These used to live in the library header */
|
||||
#define GIF_MESSAGE(Msg) fprintf(stderr, "\n%s: %s\n", PROGRAM_NAME, Msg)
|
||||
#define GIF_EXIT(Msg) { GIF_MESSAGE(Msg); exit(-3); }
|
||||
|
||||
#endif /* _GETARG_H */
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,538 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gif2rgb - convert GIF to 24-bit RGB pixel triples or vice-versa
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Toshio Kuratomi had written this in a comment about the rgb2gif code:
|
||||
|
||||
Besides fixing bugs, what's really needed is for someone to work out how to
|
||||
calculate a colormap for writing GIFs from rgb sources. Right now, an rgb
|
||||
source that has only two colors (b/w) is being converted into an 8 bit GIF....
|
||||
Which is horrendously wasteful without compression.
|
||||
|
||||
I (ESR) took this off the main to-do list in 2012 because I don't think
|
||||
the GIFLIB project actually needs to be in the converters-and-tools business.
|
||||
Plenty of hackers do that; our job is to supply stable library capability
|
||||
with our utilities mainly interesting as test tools.
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gif2rgb"
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- c%-#Colors!d s%-Width|Height!d!d 1%- o%-OutFileName!s h%- GifFile!*s";
|
||||
|
||||
static void LoadRGB(char *FileName,
|
||||
int OneFileFlag,
|
||||
GifByteType **RedBuffer,
|
||||
GifByteType **GreenBuffer,
|
||||
GifByteType **BlueBuffer,
|
||||
int Width, int Height);
|
||||
static void SaveGif(GifByteType *OutputBuffer,
|
||||
int Width, int Height,
|
||||
int ExpColorMapSize, ColorMapObject *OutputColorMap);
|
||||
|
||||
/******************************************************************************
|
||||
Load RGB file into internal frame buffer.
|
||||
******************************************************************************/
|
||||
static void LoadRGB(char *FileName,
|
||||
int OneFileFlag,
|
||||
GifByteType **RedBuffer,
|
||||
GifByteType **GreenBuffer,
|
||||
GifByteType **BlueBuffer,
|
||||
int Width, int Height)
|
||||
{
|
||||
int i;
|
||||
unsigned long Size;
|
||||
GifByteType *RedP, *GreenP, *BlueP;
|
||||
FILE *rgbfp[3];
|
||||
|
||||
Size = ((long) Width) * Height * sizeof(GifByteType);
|
||||
|
||||
if ((*RedBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL ||
|
||||
(*GreenBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL ||
|
||||
(*BlueBuffer = (GifByteType *) malloc((unsigned int) Size)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
RedP = *RedBuffer;
|
||||
GreenP = *GreenBuffer;
|
||||
BlueP = *BlueBuffer;
|
||||
|
||||
if (FileName != NULL) {
|
||||
if (OneFileFlag) {
|
||||
if ((rgbfp[0] = fopen(FileName, "rb")) == NULL)
|
||||
GIF_EXIT("Can't open input file name.");
|
||||
}
|
||||
else {
|
||||
static char *Postfixes[] = { ".R", ".G", ".B" };
|
||||
char OneFileName[80];
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
strncpy(OneFileName, FileName, sizeof(OneFileName)-1);
|
||||
strncat(OneFileName, Postfixes[i],
|
||||
sizeof(OneFileName) - 1 - strlen(OneFileName));
|
||||
|
||||
if ((rgbfp[i] = fopen(OneFileName, "rb")) == NULL)
|
||||
GIF_EXIT("Can't open input file name.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
OneFileFlag = true;
|
||||
|
||||
#ifdef _WIN32
|
||||
_setmode(0, O_BINARY);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
rgbfp[0] = stdin;
|
||||
}
|
||||
|
||||
GifQprintf("\n%s: RGB image: ", PROGRAM_NAME);
|
||||
|
||||
if (OneFileFlag) {
|
||||
GifByteType *Buffer, *BufferP;
|
||||
|
||||
if ((Buffer = (GifByteType *) malloc(Width * 3)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
for (i = 0; i < Height; i++) {
|
||||
int j;
|
||||
GifQprintf("\b\b\b\b%-4d", i);
|
||||
if (fread(Buffer, Width * 3, 1, rgbfp[0]) != 1)
|
||||
GIF_EXIT("Input file(s) terminated prematurly.");
|
||||
for (j = 0, BufferP = Buffer; j < Width; j++) {
|
||||
*RedP++ = *BufferP++;
|
||||
*GreenP++ = *BufferP++;
|
||||
*BlueP++ = *BufferP++;
|
||||
}
|
||||
}
|
||||
|
||||
free((char *) Buffer);
|
||||
fclose(rgbfp[0]);
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < Height; i++) {
|
||||
GifQprintf("\b\b\b\b%-4d", i);
|
||||
if (fread(RedP, Width, 1, rgbfp[0]) != 1 ||
|
||||
fread(GreenP, Width, 1, rgbfp[1]) != 1 ||
|
||||
fread(BlueP, Width, 1, rgbfp[2]) != 1)
|
||||
GIF_EXIT("Input file(s) terminated prematurly.");
|
||||
RedP += Width;
|
||||
GreenP += Width;
|
||||
BlueP += Width;
|
||||
}
|
||||
|
||||
fclose(rgbfp[0]);
|
||||
fclose(rgbfp[1]);
|
||||
fclose(rgbfp[2]);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Save the GIF resulting image.
|
||||
******************************************************************************/
|
||||
static void SaveGif(GifByteType *OutputBuffer,
|
||||
int Width, int Height,
|
||||
int ExpColorMapSize, ColorMapObject *OutputColorMap)
|
||||
{
|
||||
int i, Error;
|
||||
GifFileType *GifFile;
|
||||
GifByteType *Ptr = OutputBuffer;
|
||||
|
||||
/* Open stdout for the output file: */
|
||||
if ((GifFile = EGifOpenFileHandle(1, &Error)) == NULL) {
|
||||
PrintGifError(Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (EGifPutScreenDesc(GifFile,
|
||||
Width, Height, ExpColorMapSize, 0,
|
||||
OutputColorMap) == GIF_ERROR ||
|
||||
EGifPutImageDesc(GifFile,
|
||||
0, 0, Width, Height, false, NULL) == GIF_ERROR) {
|
||||
PrintGifError(Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
|
||||
GifFile->Image.Width, GifFile->Image.Height);
|
||||
|
||||
for (i = 0; i < Height; i++) {
|
||||
if (EGifPutLine(GifFile, Ptr, Width) == GIF_ERROR)
|
||||
exit(EXIT_FAILURE);
|
||||
GifQprintf("\b\b\b\b%-4d", Height - i - 1);
|
||||
|
||||
Ptr += Width;
|
||||
}
|
||||
|
||||
if (EGifCloseFile(GifFile, &Error) == GIF_ERROR) {
|
||||
PrintGifError(Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Close output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void RGB2GIF(bool OneFileFlag, int NumFiles, char *FileName,
|
||||
int ExpNumOfColors, int Width, int Height)
|
||||
{
|
||||
int ColorMapSize;
|
||||
|
||||
GifByteType *RedBuffer = NULL, *GreenBuffer = NULL, *BlueBuffer = NULL,
|
||||
*OutputBuffer = NULL;
|
||||
ColorMapObject *OutputColorMap = NULL;
|
||||
|
||||
ColorMapSize = 1 << ExpNumOfColors;
|
||||
|
||||
if (NumFiles == 1) {
|
||||
LoadRGB(FileName, OneFileFlag,
|
||||
&RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
|
||||
}
|
||||
else {
|
||||
LoadRGB(NULL, OneFileFlag,
|
||||
&RedBuffer, &GreenBuffer, &BlueBuffer, Width, Height);
|
||||
}
|
||||
|
||||
if ((OutputColorMap = GifMakeMapObject(ColorMapSize, NULL)) == NULL ||
|
||||
(OutputBuffer = (GifByteType *) malloc(Width * Height *
|
||||
sizeof(GifByteType))) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
if (GifQuantizeBuffer(Width, Height, &ColorMapSize,
|
||||
RedBuffer, GreenBuffer, BlueBuffer,
|
||||
OutputBuffer, OutputColorMap->Colors) == GIF_ERROR)
|
||||
exit(EXIT_FAILURE);
|
||||
free((char *) RedBuffer);
|
||||
free((char *) GreenBuffer);
|
||||
free((char *) BlueBuffer);
|
||||
|
||||
SaveGif(OutputBuffer, Width, Height, ExpNumOfColors, OutputColorMap);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
The real screen dumping routine.
|
||||
******************************************************************************/
|
||||
static void DumpScreen2RGB(char *FileName, int OneFileFlag,
|
||||
ColorMapObject *ColorMap,
|
||||
GifRowType *ScreenBuffer,
|
||||
int ScreenWidth, int ScreenHeight)
|
||||
{
|
||||
int i, j;
|
||||
GifRowType GifRow;
|
||||
GifColorType *ColorMapEntry;
|
||||
FILE *rgbfp[3];
|
||||
|
||||
if (FileName != NULL) {
|
||||
if (OneFileFlag) {
|
||||
if ((rgbfp[0] = fopen(FileName, "wb")) == NULL)
|
||||
GIF_EXIT("Can't open input file name.");
|
||||
} else {
|
||||
static char *Postfixes[] = { ".R", ".G", ".B" };
|
||||
char OneFileName[80];
|
||||
|
||||
for (i = 0; i < 3; i++) {
|
||||
strncpy(OneFileName, FileName, sizeof(OneFileName)-1);
|
||||
strncat(OneFileName, Postfixes[i],
|
||||
sizeof(OneFileName) - 1 - strlen(OneFileName));
|
||||
|
||||
if ((rgbfp[i] = fopen(OneFileName, "wb")) == NULL) {
|
||||
GIF_EXIT("Can't open input file name.");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OneFileFlag = true;
|
||||
|
||||
#ifdef _WIN32
|
||||
_setmode(1, O_BINARY);
|
||||
#endif /* _WIN32 */
|
||||
|
||||
rgbfp[0] = stdout;
|
||||
}
|
||||
|
||||
if (ColorMap == NULL) {
|
||||
fprintf(stderr, "Color map pointer is NULL.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (OneFileFlag) {
|
||||
unsigned char *Buffer, *BufferP;
|
||||
|
||||
if ((Buffer = (unsigned char *) malloc(ScreenWidth * 3)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
for (i = 0; i < ScreenHeight; i++) {
|
||||
GifRow = ScreenBuffer[i];
|
||||
GifQprintf("\b\b\b\b%-4d", ScreenHeight - i);
|
||||
for (j = 0, BufferP = Buffer; j < ScreenWidth; j++) {
|
||||
ColorMapEntry = &ColorMap->Colors[GifRow[j]];
|
||||
*BufferP++ = ColorMapEntry->Red;
|
||||
*BufferP++ = ColorMapEntry->Green;
|
||||
*BufferP++ = ColorMapEntry->Blue;
|
||||
}
|
||||
if (fwrite(Buffer, ScreenWidth * 3, 1, rgbfp[0]) != 1)
|
||||
GIF_EXIT("Write to file(s) failed.");
|
||||
}
|
||||
|
||||
free((char *) Buffer);
|
||||
fclose(rgbfp[0]);
|
||||
} else {
|
||||
unsigned char *Buffers[3];
|
||||
|
||||
if ((Buffers[0] = (unsigned char *) malloc(ScreenWidth)) == NULL ||
|
||||
(Buffers[1] = (unsigned char *) malloc(ScreenWidth)) == NULL ||
|
||||
(Buffers[2] = (unsigned char *) malloc(ScreenWidth)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
for (i = 0; i < ScreenHeight; i++) {
|
||||
GifRow = ScreenBuffer[i];
|
||||
GifQprintf("\b\b\b\b%-4d", ScreenHeight - i);
|
||||
for (j = 0; j < ScreenWidth; j++) {
|
||||
ColorMapEntry = &ColorMap->Colors[GifRow[j]];
|
||||
Buffers[0][j] = ColorMapEntry->Red;
|
||||
Buffers[1][j] = ColorMapEntry->Green;
|
||||
Buffers[2][j] = ColorMapEntry->Blue;
|
||||
}
|
||||
if (fwrite(Buffers[0], ScreenWidth, 1, rgbfp[0]) != 1 ||
|
||||
fwrite(Buffers[1], ScreenWidth, 1, rgbfp[1]) != 1 ||
|
||||
fwrite(Buffers[2], ScreenWidth, 1, rgbfp[2]) != 1)
|
||||
GIF_EXIT("Write to file(s) failed.");
|
||||
}
|
||||
|
||||
free((char *) Buffers[0]);
|
||||
free((char *) Buffers[1]);
|
||||
free((char *) Buffers[2]);
|
||||
fclose(rgbfp[0]);
|
||||
fclose(rgbfp[1]);
|
||||
fclose(rgbfp[2]);
|
||||
}
|
||||
}
|
||||
|
||||
static void GIF2RGB(int NumFiles, char *FileName,
|
||||
bool OneFileFlag,
|
||||
char *OutFileName)
|
||||
{
|
||||
int i, j, Size, Row, Col, Width, Height, ExtCode, Count;
|
||||
GifRecordType RecordType;
|
||||
GifByteType *Extension;
|
||||
GifRowType *ScreenBuffer;
|
||||
GifFileType *GifFile;
|
||||
int
|
||||
InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
|
||||
InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
|
||||
int ImageNum = 0;
|
||||
ColorMapObject *ColorMap;
|
||||
int Error;
|
||||
|
||||
if (NumFiles == 1) {
|
||||
int Error;
|
||||
if ((GifFile = DGifOpenFileName(FileName, &Error)) == NULL) {
|
||||
PrintGifError(Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int Error;
|
||||
/* Use stdin instead: */
|
||||
if ((GifFile = DGifOpenFileHandle(0, &Error)) == NULL) {
|
||||
PrintGifError(Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (GifFile->SHeight == 0 || GifFile->SWidth == 0) {
|
||||
fprintf(stderr, "Image of width or height 0\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the screen as vector of column of rows. Note this
|
||||
* screen is device independent - it's the screen defined by the
|
||||
* GIF file parameters.
|
||||
*/
|
||||
if ((ScreenBuffer = (GifRowType *)
|
||||
malloc(GifFile->SHeight * sizeof(GifRowType))) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
Size = GifFile->SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
|
||||
if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
for (i = 0; i < GifFile->SWidth; i++) /* Set its color to BackGround. */
|
||||
ScreenBuffer[0][i] = GifFile->SBackGroundColor;
|
||||
for (i = 1; i < GifFile->SHeight; i++) {
|
||||
/* Allocate the other rows, and set their color to background too: */
|
||||
if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
|
||||
}
|
||||
|
||||
/* Scan the content of the GIF file and load the image(s) in: */
|
||||
do {
|
||||
if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
switch (RecordType) {
|
||||
case IMAGE_DESC_RECORD_TYPE:
|
||||
if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
Row = GifFile->Image.Top; /* Image Position relative to Screen. */
|
||||
Col = GifFile->Image.Left;
|
||||
Width = GifFile->Image.Width;
|
||||
Height = GifFile->Image.Height;
|
||||
GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
|
||||
if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
|
||||
GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
|
||||
fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (GifFile->Image.Interlace) {
|
||||
/* Need to perform 4 passes on the images: */
|
||||
for (Count = i = 0; i < 4; i++)
|
||||
for (j = Row + InterlacedOffset[i]; j < Row + Height;
|
||||
j += InterlacedJumps[i]) {
|
||||
GifQprintf("\b\b\b\b%-4d", Count++);
|
||||
if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
|
||||
Width) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < Height; i++) {
|
||||
GifQprintf("\b\b\b\b%-4d", i);
|
||||
if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
|
||||
Width) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
/* Skip any extension blocks in file: */
|
||||
if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while (Extension != NULL) {
|
||||
if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TERMINATE_RECORD_TYPE:
|
||||
break;
|
||||
default: /* Should be trapped by DGifGetRecordType. */
|
||||
break;
|
||||
}
|
||||
} while (RecordType != TERMINATE_RECORD_TYPE);
|
||||
|
||||
/* Lets dump it - set the global variables required and do it: */
|
||||
ColorMap = (GifFile->Image.ColorMap
|
||||
? GifFile->Image.ColorMap
|
||||
: GifFile->SColorMap);
|
||||
if (ColorMap == NULL) {
|
||||
fprintf(stderr, "Gif Image does not have a colormap\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* check that the background color isn't garbage (SF bug #87) */
|
||||
if (GifFile->SBackGroundColor < 0 || GifFile->SBackGroundColor >= ColorMap->ColorCount) {
|
||||
fprintf(stderr, "Background color out of range for colormap\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
DumpScreen2RGB(OutFileName, OneFileFlag,
|
||||
ColorMap,
|
||||
ScreenBuffer,
|
||||
GifFile->SWidth, GifFile->SHeight);
|
||||
|
||||
(void)free(ScreenBuffer);
|
||||
|
||||
if (DGifCloseFile(GifFile, &Error) == GIF_ERROR) {
|
||||
PrintGifError(Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Interpret the command line and scan the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool Error, OutFileFlag = false, ColorFlag = false, SizeFlag = false;
|
||||
int NumFiles, Width = 0, Height = 0, ExpNumOfColors = 8;
|
||||
char *OutFileName,
|
||||
**FileName = NULL;
|
||||
static bool
|
||||
OneFileFlag = false,
|
||||
HelpFlag = false;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
|
||||
&ColorFlag, &ExpNumOfColors, &SizeFlag, &Width, &Height,
|
||||
&OneFileFlag, &OutFileFlag, &OutFileName,
|
||||
&HelpFlag, &NumFiles, &FileName)) != false ||
|
||||
(NumFiles > 1 && !HelpFlag)) {
|
||||
if (Error)
|
||||
GAPrintErrMsg(Error);
|
||||
else if (NumFiles > 1)
|
||||
GIF_MESSAGE("Error in command line parsing - one input file please.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if (!OutFileFlag) OutFileName = NULL;
|
||||
|
||||
if (SizeFlag && Width > 0 && Height > 0)
|
||||
RGB2GIF(OneFileFlag, NumFiles, *FileName,
|
||||
ExpNumOfColors, Width, Height);
|
||||
else
|
||||
GIF2RGB(NumFiles, *FileName, OneFileFlag, OutFileName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,99 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gif_err.c - handle error reporting for the GIF library.
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "gif_lib_private.h"
|
||||
|
||||
/*****************************************************************************
|
||||
Return a string description of the last GIF error
|
||||
*****************************************************************************/
|
||||
const char *
|
||||
GifErrorString(int ErrorCode)
|
||||
{
|
||||
const char *Err;
|
||||
|
||||
switch (ErrorCode) {
|
||||
case E_GIF_ERR_OPEN_FAILED:
|
||||
Err = "Failed to open given file";
|
||||
break;
|
||||
case E_GIF_ERR_WRITE_FAILED:
|
||||
Err = "Failed to write to given file";
|
||||
break;
|
||||
case E_GIF_ERR_HAS_SCRN_DSCR:
|
||||
Err = "Screen descriptor has already been set";
|
||||
break;
|
||||
case E_GIF_ERR_HAS_IMAG_DSCR:
|
||||
Err = "Image descriptor is still active";
|
||||
break;
|
||||
case E_GIF_ERR_NO_COLOR_MAP:
|
||||
Err = "Neither global nor local color map";
|
||||
break;
|
||||
case E_GIF_ERR_DATA_TOO_BIG:
|
||||
Err = "Number of pixels bigger than width * height";
|
||||
break;
|
||||
case E_GIF_ERR_NOT_ENOUGH_MEM:
|
||||
Err = "Failed to allocate required memory";
|
||||
break;
|
||||
case E_GIF_ERR_DISK_IS_FULL:
|
||||
Err = "Write failed (disk full?)";
|
||||
break;
|
||||
case E_GIF_ERR_CLOSE_FAILED:
|
||||
Err = "Failed to close given file";
|
||||
break;
|
||||
case E_GIF_ERR_NOT_WRITEABLE:
|
||||
Err = "Given file was not opened for write";
|
||||
break;
|
||||
case D_GIF_ERR_OPEN_FAILED:
|
||||
Err = "Failed to open given file";
|
||||
break;
|
||||
case D_GIF_ERR_READ_FAILED:
|
||||
Err = "Failed to read from given file";
|
||||
break;
|
||||
case D_GIF_ERR_NOT_GIF_FILE:
|
||||
Err = "Data is not in GIF format";
|
||||
break;
|
||||
case D_GIF_ERR_NO_SCRN_DSCR:
|
||||
Err = "No screen descriptor detected";
|
||||
break;
|
||||
case D_GIF_ERR_NO_IMAG_DSCR:
|
||||
Err = "No Image Descriptor detected";
|
||||
break;
|
||||
case D_GIF_ERR_NO_COLOR_MAP:
|
||||
Err = "Neither global nor local color map";
|
||||
break;
|
||||
case D_GIF_ERR_WRONG_RECORD:
|
||||
Err = "Wrong record type detected";
|
||||
break;
|
||||
case D_GIF_ERR_DATA_TOO_BIG:
|
||||
Err = "Number of pixels bigger than width * height";
|
||||
break;
|
||||
case D_GIF_ERR_NOT_ENOUGH_MEM:
|
||||
Err = "Failed to allocate required memory";
|
||||
break;
|
||||
case D_GIF_ERR_CLOSE_FAILED:
|
||||
Err = "Failed to close given file";
|
||||
break;
|
||||
case D_GIF_ERR_NOT_READABLE:
|
||||
Err = "Given file was not opened for read";
|
||||
break;
|
||||
case D_GIF_ERR_IMAGE_DEFECT:
|
||||
Err = "Image is defective, decoding aborted";
|
||||
break;
|
||||
case D_GIF_ERR_EOF_TOO_SOON:
|
||||
Err = "Image EOF detected before image complete";
|
||||
break;
|
||||
default:
|
||||
Err = NULL;
|
||||
break;
|
||||
}
|
||||
return Err;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,261 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gif_font.c - utility font handling and simple drawing for the GIF library
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
|
||||
/*****************************************************************************
|
||||
Ascii 8 by 8 regular font - only first 128 characters are supported.
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* Each array entry holds the bits for 8 horizontal scan lines, topmost
|
||||
* first. The most significant bit of each constant is the leftmost bit of
|
||||
* the scan line.
|
||||
*/
|
||||
/*@+charint@*/
|
||||
const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* Ascii 0 */
|
||||
{0x3c, 0x42, 0xa5, 0x81, 0xbd, 0x42, 0x3c, 0x00}, /* Ascii 1 */
|
||||
{0x3c, 0x7e, 0xdb, 0xff, 0xc3, 0x7e, 0x3c, 0x00}, /* Ascii 2 */
|
||||
{0x00, 0xee, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 3 */
|
||||
{0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 4 */
|
||||
{0x00, 0x3c, 0x18, 0xff, 0xff, 0x08, 0x18, 0x00}, /* Ascii 5 */
|
||||
{0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x10, 0x38, 0x00}, /* Ascii 6 */
|
||||
{0x00, 0x00, 0x18, 0x3c, 0x18, 0x00, 0x00, 0x00}, /* Ascii 7 */
|
||||
{0xff, 0xff, 0xe7, 0xc3, 0xe7, 0xff, 0xff, 0xff}, /* Ascii 8 */
|
||||
{0x00, 0x3c, 0x42, 0x81, 0x81, 0x42, 0x3c, 0x00}, /* Ascii 9 */
|
||||
{0xff, 0xc3, 0xbd, 0x7e, 0x7e, 0xbd, 0xc3, 0xff}, /* Ascii 10 */
|
||||
{0x1f, 0x07, 0x0d, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* Ascii 11 */
|
||||
{0x00, 0x7e, 0xc3, 0xc3, 0x7e, 0x18, 0x7e, 0x18}, /* Ascii 12 */
|
||||
{0x04, 0x06, 0x07, 0x04, 0x04, 0xfc, 0xf8, 0x00}, /* Ascii 13 */
|
||||
{0x0c, 0x0a, 0x0d, 0x0b, 0xf9, 0xf9, 0x1f, 0x1f}, /* Ascii 14 */
|
||||
{0x00, 0x92, 0x7c, 0x44, 0xc6, 0x7c, 0x92, 0x00}, /* Ascii 15 */
|
||||
{0x00, 0x00, 0x60, 0x78, 0x7e, 0x78, 0x60, 0x00}, /* Ascii 16 */
|
||||
{0x00, 0x00, 0x06, 0x1e, 0x7e, 0x1e, 0x06, 0x00}, /* Ascii 17 */
|
||||
{0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18}, /* Ascii 18 */
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00}, /* Ascii 19 */
|
||||
{0xff, 0xb6, 0x76, 0x36, 0x36, 0x36, 0x36, 0x00}, /* Ascii 20 */
|
||||
{0x7e, 0xc1, 0xdc, 0x22, 0x22, 0x1f, 0x83, 0x7e}, /* Ascii 21 */
|
||||
{0x00, 0x00, 0x00, 0x7e, 0x7e, 0x00, 0x00, 0x00}, /* Ascii 22 */
|
||||
{0x18, 0x7e, 0x18, 0x18, 0x7e, 0x18, 0x00, 0xff}, /* Ascii 23 */
|
||||
{0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00}, /* Ascii 24 */
|
||||
{0x18, 0x18, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x00}, /* Ascii 25 */
|
||||
{0x00, 0x04, 0x06, 0xff, 0x06, 0x04, 0x00, 0x00}, /* Ascii 26 */
|
||||
{0x00, 0x20, 0x60, 0xff, 0x60, 0x20, 0x00, 0x00}, /* Ascii 27 */
|
||||
{0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xff, 0x00}, /* Ascii 28 */
|
||||
{0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00}, /* Ascii 29 */
|
||||
{0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 0x00, 0x00}, /* Ascii 30 */
|
||||
{0x00, 0x00, 0x00, 0xfe, 0x7c, 0x38, 0x10, 0x00}, /* Ascii 31 */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* */
|
||||
{0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x30, 0x00}, /* ! */
|
||||
{0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* " */
|
||||
{0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00}, /* # */
|
||||
{0x10, 0x7c, 0xd2, 0x7c, 0x86, 0x7c, 0x10, 0x00}, /* $ */
|
||||
{0xf0, 0x96, 0xfc, 0x18, 0x3e, 0x72, 0xde, 0x00}, /* % */
|
||||
{0x30, 0x48, 0x30, 0x78, 0xce, 0xcc, 0x78, 0x00}, /* & */
|
||||
{0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ' */
|
||||
{0x10, 0x60, 0xc0, 0xc0, 0xc0, 0x60, 0x10, 0x00}, /* ( */
|
||||
{0x10, 0x0c, 0x06, 0x06, 0x06, 0x0c, 0x10, 0x00}, /* ) */
|
||||
{0x00, 0x54, 0x38, 0xfe, 0x38, 0x54, 0x00, 0x00}, /* * */
|
||||
{0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x00}, /* + */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x70}, /* , */
|
||||
{0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00}, /* - */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00}, /* . */
|
||||
{0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00}, /* / */
|
||||
{0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* 0 */
|
||||
{0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* 1 */
|
||||
{0x7c, 0xc6, 0x06, 0x0c, 0x30, 0x60, 0xfe, 0x00}, /* 2 */
|
||||
{0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00}, /* 3 */
|
||||
{0x0e, 0x1e, 0x36, 0x66, 0xfe, 0x06, 0x06, 0x00}, /* 4 */
|
||||
{0xfe, 0xc0, 0xc0, 0xfc, 0x06, 0x06, 0xfc, 0x00}, /* 5 */
|
||||
{0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00}, /* 6 */
|
||||
{0xfe, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x60, 0x00}, /* 7 */
|
||||
{0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00}, /* 8 */
|
||||
{0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00}, /* 9 */
|
||||
{0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00}, /* : */
|
||||
{0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x20, 0x00}, /* }, */
|
||||
{0x00, 0x1c, 0x30, 0x60, 0x30, 0x1c, 0x00, 0x00}, /* < */
|
||||
{0x00, 0x00, 0x7e, 0x00, 0x7e, 0x00, 0x00, 0x00}, /* = */
|
||||
{0x00, 0x70, 0x18, 0x0c, 0x18, 0x70, 0x00, 0x00}, /* > */
|
||||
{0x7c, 0xc6, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00}, /* ? */
|
||||
{0x7c, 0x82, 0x9a, 0xaa, 0xaa, 0x9e, 0x7c, 0x00}, /* @ */
|
||||
{0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x00}, /* A */
|
||||
{0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xfc, 0x00}, /* B */
|
||||
{0x7c, 0xc6, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x00}, /* C */
|
||||
{0xf8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 0xf8, 0x00}, /* D */
|
||||
{0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xfe, 0x00}, /* E */
|
||||
{0xfe, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* F */
|
||||
{0x7c, 0xc6, 0xc0, 0xce, 0xc6, 0xc6, 0x7e, 0x00}, /* G */
|
||||
{0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00}, /* H */
|
||||
{0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00}, /* I */
|
||||
{0x1e, 0x06, 0x06, 0x06, 0xc6, 0xc6, 0x7c, 0x00}, /* J */
|
||||
{0xc6, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0xc6, 0x00}, /* K */
|
||||
{0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0x00}, /* L */
|
||||
{0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0xc6, 0x00}, /* M */
|
||||
{0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00}, /* N */
|
||||
{0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* O */
|
||||
{0xfc, 0xc6, 0xc6, 0xfc, 0xc0, 0xc0, 0xc0, 0x00}, /* P */
|
||||
{0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x06}, /* Q */
|
||||
{0xfc, 0xc6, 0xc6, 0xfc, 0xc6, 0xc6, 0xc6, 0x00}, /* R */
|
||||
{0x78, 0xcc, 0x60, 0x30, 0x18, 0xcc, 0x78, 0x00}, /* S */
|
||||
{0xfc, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00}, /* T */
|
||||
{0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* U */
|
||||
{0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* V */
|
||||
{0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00}, /* W */
|
||||
{0xc6, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0xc6, 0x00}, /* X */
|
||||
{0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x00}, /* Y */
|
||||
{0xfe, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xfe, 0x00}, /* Z */
|
||||
{0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 0x3c, 0x00}, /* [ */
|
||||
{0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x00}, /* \ */
|
||||
{0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 0x00}, /* ] */
|
||||
{0x00, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00}, /* ^ */
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}, /* _ */
|
||||
{0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, /* ` */
|
||||
{0x00, 0x00, 0x7c, 0x06, 0x7e, 0xc6, 0x7e, 0x00}, /* a */
|
||||
{0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0x00}, /* b */
|
||||
{0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0x7e, 0x00}, /* c */
|
||||
{0x06, 0x06, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x00}, /* d */
|
||||
{0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7e, 0x00}, /* e */
|
||||
{0x1e, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x30, 0x00}, /* f */
|
||||
{0x00, 0x00, 0x7e, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* g */
|
||||
{0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* */
|
||||
{0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* i */
|
||||
{0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0xf0}, /* j */
|
||||
{0xc0, 0xc0, 0xcc, 0xd8, 0xf0, 0xd8, 0xcc, 0x00}, /* k */
|
||||
{0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00}, /* l */
|
||||
{0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xc6, 0xc6, 0x00}, /* m */
|
||||
{0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x00}, /* n */
|
||||
{0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00}, /* o */
|
||||
{0x00, 0x00, 0xfc, 0xc6, 0xc6, 0xe6, 0xdc, 0xc0}, /* p */
|
||||
{0x00, 0x00, 0x7e, 0xc6, 0xc6, 0xce, 0x76, 0x06}, /* q */
|
||||
{0x00, 0x00, 0x6e, 0x70, 0x60, 0x60, 0x60, 0x00}, /* r */
|
||||
{0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0xfc, 0x00}, /* s */
|
||||
{0x30, 0x30, 0x7c, 0x30, 0x30, 0x30, 0x1c, 0x00}, /* t */
|
||||
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x00}, /* u */
|
||||
{0x00, 0x00, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00}, /* v */
|
||||
{0x00, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0x6c, 0x00}, /* w */
|
||||
{0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00}, /* x */
|
||||
{0x00, 0x00, 0xc6, 0xc6, 0xce, 0x76, 0x06, 0x7c}, /* y */
|
||||
{0x00, 0x00, 0xfc, 0x18, 0x30, 0x60, 0xfc, 0x00}, /* z */
|
||||
{0x0e, 0x18, 0x18, 0x70, 0x18, 0x18, 0x0e, 0x00}, /* { */
|
||||
{0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, /* | */
|
||||
{0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00}, /* } */
|
||||
{0x00, 0x00, 0x70, 0x9a, 0x0e, 0x00, 0x00, 0x00}, /* ~ */
|
||||
{0x00, 0x00, 0x18, 0x3c, 0x66, 0xff, 0x00, 0x00} /* Ascii 127 */
|
||||
};
|
||||
/*@=charint@*/
|
||||
|
||||
void
|
||||
GifDrawText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend,
|
||||
const int color)
|
||||
{
|
||||
int i, j;
|
||||
const char *cp;
|
||||
|
||||
for (i = 0; i < GIF_FONT_HEIGHT; i++) {
|
||||
int base = Image->ImageDesc.Width * (y + i) + x;
|
||||
|
||||
for (cp = legend; *cp; cp++)
|
||||
for (j = 0; j < GIF_FONT_WIDTH; j++) {
|
||||
if (GifAsciiTable8x8[(short)(*cp)][i] & (1 << (GIF_FONT_WIDTH - j)))
|
||||
Image->RasterBits[base] = color;
|
||||
base++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GifDrawBox(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d,
|
||||
const int color)
|
||||
{
|
||||
int j, base = Image->ImageDesc.Width * y + x;
|
||||
|
||||
for (j = 0; j < w; j++)
|
||||
Image->RasterBits[base + j] =
|
||||
Image->RasterBits[base + (d * Image->ImageDesc.Width) + j] = color;
|
||||
|
||||
for (j = 0; j < d; j++)
|
||||
Image->RasterBits[base + j * Image->ImageDesc.Width] =
|
||||
Image->RasterBits[base + j * Image->ImageDesc.Width + w] = color;
|
||||
}
|
||||
|
||||
void
|
||||
GifDrawRectangle(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d,
|
||||
const int color)
|
||||
{
|
||||
unsigned char *bp = Image->RasterBits + Image->ImageDesc.Width * y + x;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < d; i++)
|
||||
memset(bp + (i * Image->ImageDesc.Width), color, (size_t)w);
|
||||
}
|
||||
|
||||
void
|
||||
GifDrawBoxedText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend,
|
||||
const int border,
|
||||
const int bg, const int fg)
|
||||
{
|
||||
int j = 0, LineCount = 0, TextWidth = 0;
|
||||
const char *cp;
|
||||
char *dup;
|
||||
|
||||
/* compute size of text to box */
|
||||
for (cp = legend; *cp; cp++)
|
||||
if (*cp == '\r') {
|
||||
if (j > TextWidth)
|
||||
TextWidth = j;
|
||||
j = 0;
|
||||
LineCount++;
|
||||
} else if (*cp != '\t')
|
||||
++j;
|
||||
LineCount++; /* count last line */
|
||||
if (j > TextWidth) /* last line might be longer than any previous */
|
||||
TextWidth = j;
|
||||
|
||||
/* draw the text */
|
||||
dup = malloc(strlen(legend)+1);
|
||||
/* FIXME: should return bad status, but that would require API change */
|
||||
if (dup != NULL) {
|
||||
int i = 0;
|
||||
/* fill the box */
|
||||
GifDrawRectangle(Image, x + 1, y + 1,
|
||||
border + TextWidth * GIF_FONT_WIDTH + border - 1,
|
||||
border + LineCount * GIF_FONT_HEIGHT + border - 1, bg);
|
||||
(void)strcpy(dup, (char *)legend);
|
||||
char *lasts;
|
||||
cp = strtok_r(dup, "\r\n", &lasts);
|
||||
do {
|
||||
int leadspace = 0;
|
||||
|
||||
if (cp[0] == '\t')
|
||||
leadspace = (TextWidth - strlen(++cp)) / 2;
|
||||
|
||||
GifDrawText8x8(Image, x + border + (leadspace * GIF_FONT_WIDTH),
|
||||
y + border + (GIF_FONT_HEIGHT * i++), cp, fg);
|
||||
cp = strtok_r(NULL, "\r\n", &lasts);
|
||||
} while (cp);
|
||||
(void)free((void *)dup);
|
||||
|
||||
/* outline the box */
|
||||
GifDrawBox(Image, x, y, border + TextWidth * GIF_FONT_WIDTH + border,
|
||||
border + LineCount * GIF_FONT_HEIGHT + border, fg);
|
||||
}
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,133 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gif_hash.c -- module to support the following operations:
|
||||
|
||||
1. InitHashTable - initialize hash table.
|
||||
2. ClearHashTable - clear the hash table to an empty state.
|
||||
2. InsertHashTable - insert one item into data structure.
|
||||
3. ExistsHashTable - test if item exists in data structure.
|
||||
|
||||
This module is used to hash the GIF codes during encoding.
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "gif_hash.h"
|
||||
#include "gif_lib_private.h"
|
||||
|
||||
/* #define DEBUG_HIT_RATE Debug number of misses per hash Insert/Exists. */
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
static long NumberOfTests = 0,
|
||||
NumberOfMisses = 0;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
static int KeyItem(uint32_t Item);
|
||||
|
||||
/******************************************************************************
|
||||
Initialize HashTable - allocate the memory needed and clear it. *
|
||||
******************************************************************************/
|
||||
GifHashTableType *_InitHashTable(void)
|
||||
{
|
||||
GifHashTableType *HashTable;
|
||||
|
||||
if ((HashTable = (GifHashTableType *) malloc(sizeof(GifHashTableType)))
|
||||
== NULL)
|
||||
return NULL;
|
||||
|
||||
_ClearHashTable(HashTable);
|
||||
|
||||
return HashTable;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to clear the HashTable to an empty state. *
|
||||
This part is a little machine depended. Use the commented part otherwise. *
|
||||
******************************************************************************/
|
||||
void _ClearHashTable(GifHashTableType *HashTable)
|
||||
{
|
||||
memset(HashTable -> HTable, 0xFF, HT_SIZE * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to insert a new Item into the HashTable. The data is assumed to be *
|
||||
new one. *
|
||||
******************************************************************************/
|
||||
void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code)
|
||||
{
|
||||
int HKey = KeyItem(Key);
|
||||
uint32_t *HTable = HashTable -> HTable;
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfTests++;
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
while (HT_GET_KEY(HTable[HKey]) != 0xFFFFFL) {
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
HTable[HKey] = HT_PUT_KEY(Key) | HT_PUT_CODE(Code);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to test if given Key exists in HashTable and if so returns its code *
|
||||
Returns the Code if key was found, -1 if not. *
|
||||
******************************************************************************/
|
||||
int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key)
|
||||
{
|
||||
int HKey = KeyItem(Key);
|
||||
uint32_t *HTable = HashTable -> HTable, HTKey;
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfTests++;
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
while ((HTKey = HT_GET_KEY(HTable[HKey])) != 0xFFFFFL) {
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
NumberOfMisses++;
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
if (Key == HTKey) return HT_GET_CODE(HTable[HKey]);
|
||||
HKey = (HKey + 1) & HT_KEY_MASK;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to generate an HKey for the hashtable out of the given unique key. *
|
||||
The given Key is assumed to be 20 bits as follows: lower 8 bits are the *
|
||||
new postfix character, while the upper 12 bits are the prefix code. *
|
||||
Because the average hit ratio is only 2 (2 hash references per entry), *
|
||||
evaluating more complex keys (such as twin prime keys) does not worth it! *
|
||||
******************************************************************************/
|
||||
static int KeyItem(uint32_t Item)
|
||||
{
|
||||
return ((Item >> 12) ^ Item) & HT_KEY_MASK;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_HIT_RATE
|
||||
/******************************************************************************
|
||||
Debugging routine to print the hit ratio - number of times the hash table *
|
||||
was tested per operation. This routine was used to test the KeyItem routine *
|
||||
******************************************************************************/
|
||||
void HashTablePrintHitRatio(void)
|
||||
{
|
||||
printf("Hash Table Hit Ratio is %ld/%ld = %ld%%.\n",
|
||||
NumberOfMisses, NumberOfTests,
|
||||
NumberOfMisses * 100 / NumberOfTests);
|
||||
}
|
||||
#endif /* DEBUG_HIT_RATE */
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,41 @@
|
|||
/******************************************************************************
|
||||
|
||||
gif_hash.h - magfic constants and declarations for GIF LZW
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _GIF_HASH_H_
|
||||
#define _GIF_HASH_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define HT_SIZE 8192 /* 12bits = 4096 or twice as big! */
|
||||
#define HT_KEY_MASK 0x1FFF /* 13bits keys */
|
||||
#define HT_KEY_NUM_BITS 13 /* 13bits keys */
|
||||
#define HT_MAX_KEY 8191 /* 13bits - 1, maximal code possible */
|
||||
#define HT_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
|
||||
/* The 32 bits of the long are divided into two parts for the key & code: */
|
||||
/* 1. The code is 12 bits as our compression algorithm is limited to 12bits */
|
||||
/* 2. The key is 12 bits Prefix code + 8 bit new char or 20 bits. */
|
||||
/* The key is the upper 20 bits. The code is the lower 12. */
|
||||
#define HT_GET_KEY(l) (l >> 12)
|
||||
#define HT_GET_CODE(l) (l & 0x0FFF)
|
||||
#define HT_PUT_KEY(l) (l << 12)
|
||||
#define HT_PUT_CODE(l) (l & 0x0FFF)
|
||||
|
||||
typedef struct GifHashTableType {
|
||||
uint32_t HTable[HT_SIZE];
|
||||
} GifHashTableType;
|
||||
|
||||
GifHashTableType *_InitHashTable(void);
|
||||
void _ClearHashTable(GifHashTableType *HashTable);
|
||||
void _InsertHashTable(GifHashTableType *HashTable, uint32_t Key, int Code);
|
||||
int _ExistsHashTable(GifHashTableType *HashTable, uint32_t Key);
|
||||
|
||||
#endif /* _GIF_HASH_H_ */
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,303 @@
|
|||
/******************************************************************************
|
||||
|
||||
gif_lib.h - service library for decoding and encoding GIF images
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _GIF_LIB_H_
|
||||
#define _GIF_LIB_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define GIFLIB_MAJOR 5
|
||||
#define GIFLIB_MINOR 2
|
||||
#define GIFLIB_RELEASE 1
|
||||
|
||||
#define GIF_ERROR 0
|
||||
#define GIF_OK 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
|
||||
#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
|
||||
#define GIF_VERSION_POS 3 /* Version first character in stamp. */
|
||||
#define GIF87_STAMP "GIF87a" /* First chars in file - GIF stamp. */
|
||||
#define GIF89_STAMP "GIF89a" /* First chars in file - GIF stamp. */
|
||||
|
||||
typedef unsigned char GifPixelType;
|
||||
typedef unsigned char *GifRowType;
|
||||
typedef unsigned char GifByteType;
|
||||
typedef unsigned int GifPrefixType;
|
||||
typedef int GifWord;
|
||||
|
||||
typedef struct GifColorType {
|
||||
GifByteType Red, Green, Blue;
|
||||
} GifColorType;
|
||||
|
||||
typedef struct ColorMapObject {
|
||||
int ColorCount;
|
||||
int BitsPerPixel;
|
||||
bool SortFlag;
|
||||
GifColorType *Colors; /* on malloc(3) heap */
|
||||
} ColorMapObject;
|
||||
|
||||
typedef struct GifImageDesc {
|
||||
GifWord Left, Top, Width, Height; /* Current image dimensions. */
|
||||
bool Interlace; /* Sequential/Interlaced lines. */
|
||||
ColorMapObject *ColorMap; /* The local color map */
|
||||
} GifImageDesc;
|
||||
|
||||
typedef struct ExtensionBlock {
|
||||
int ByteCount;
|
||||
GifByteType *Bytes; /* on malloc(3) heap */
|
||||
int Function; /* The block function code */
|
||||
#define CONTINUE_EXT_FUNC_CODE 0x00 /* continuation subblock */
|
||||
#define COMMENT_EXT_FUNC_CODE 0xfe /* comment */
|
||||
#define GRAPHICS_EXT_FUNC_CODE 0xf9 /* graphics control (GIF89) */
|
||||
#define PLAINTEXT_EXT_FUNC_CODE 0x01 /* plaintext */
|
||||
#define APPLICATION_EXT_FUNC_CODE 0xff /* application block (GIF89) */
|
||||
} ExtensionBlock;
|
||||
|
||||
typedef struct SavedImage {
|
||||
GifImageDesc ImageDesc;
|
||||
GifByteType *RasterBits; /* on malloc(3) heap */
|
||||
int ExtensionBlockCount; /* Count of extensions before image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions before image */
|
||||
} SavedImage;
|
||||
|
||||
typedef struct GifFileType {
|
||||
GifWord SWidth, SHeight; /* Size of virtual canvas */
|
||||
GifWord SColorResolution; /* How many colors can we generate? */
|
||||
GifWord SBackGroundColor; /* Background color for virtual canvas */
|
||||
GifByteType AspectByte; /* Used to compute pixel aspect ratio */
|
||||
ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
|
||||
int ImageCount; /* Number of current image (both APIs) */
|
||||
GifImageDesc Image; /* Current image (low-level API) */
|
||||
SavedImage *SavedImages; /* Image sequence (high-level API) */
|
||||
int ExtensionBlockCount; /* Count extensions past last image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
|
||||
int Error; /* Last error condition reported */
|
||||
void *UserData; /* hook to attach user data (TVT) */
|
||||
void *Private; /* Don't mess with this! */
|
||||
} GifFileType;
|
||||
|
||||
#define GIF_ASPECT_RATIO(n) ((n)+15.0/64.0)
|
||||
|
||||
typedef enum {
|
||||
UNDEFINED_RECORD_TYPE,
|
||||
SCREEN_DESC_RECORD_TYPE,
|
||||
IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
|
||||
EXTENSION_RECORD_TYPE, /* Begin with '!' */
|
||||
TERMINATE_RECORD_TYPE /* Begin with ';' */
|
||||
} GifRecordType;
|
||||
|
||||
/* func type to read gif data from arbitrary sources (TVT) */
|
||||
typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
|
||||
|
||||
/* func type to write gif data to arbitrary targets.
|
||||
* Returns count of bytes written. (MRB)
|
||||
*/
|
||||
typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
|
||||
|
||||
/******************************************************************************
|
||||
GIF89 structures
|
||||
******************************************************************************/
|
||||
|
||||
typedef struct GraphicsControlBlock {
|
||||
int DisposalMode;
|
||||
#define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
|
||||
#define DISPOSE_DO_NOT 1 /* Leave image in place */
|
||||
#define DISPOSE_BACKGROUND 2 /* Set area too background color */
|
||||
#define DISPOSE_PREVIOUS 3 /* Restore to previous content */
|
||||
bool UserInputFlag; /* User confirmation required before disposal */
|
||||
int DelayTime; /* pre-display delay in 0.01sec units */
|
||||
int TransparentColor; /* Palette index for transparency, -1 if none */
|
||||
#define NO_TRANSPARENT_COLOR -1
|
||||
} GraphicsControlBlock;
|
||||
|
||||
/******************************************************************************
|
||||
GIF encoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *EGifOpenFileName(const char *GifFileName,
|
||||
const bool GifTestExistence, int *Error);
|
||||
GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
|
||||
GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
|
||||
int EGifSpew(GifFileType * GifFile);
|
||||
const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
|
||||
int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
|
||||
|
||||
#define E_GIF_SUCCEEDED 0
|
||||
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
|
||||
#define E_GIF_ERR_WRITE_FAILED 2
|
||||
#define E_GIF_ERR_HAS_SCRN_DSCR 3
|
||||
#define E_GIF_ERR_HAS_IMAG_DSCR 4
|
||||
#define E_GIF_ERR_NO_COLOR_MAP 5
|
||||
#define E_GIF_ERR_DATA_TOO_BIG 6
|
||||
#define E_GIF_ERR_NOT_ENOUGH_MEM 7
|
||||
#define E_GIF_ERR_DISK_IS_FULL 8
|
||||
#define E_GIF_ERR_CLOSE_FAILED 9
|
||||
#define E_GIF_ERR_NOT_WRITEABLE 10
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int EGifPutScreenDesc(GifFileType *GifFile,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const int GifColorRes,
|
||||
const int GifBackGround,
|
||||
const ColorMapObject *GifColorMap);
|
||||
int EGifPutImageDesc(GifFileType *GifFile,
|
||||
const int GifLeft, const int GifTop,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const bool GifInterlace,
|
||||
const ColorMapObject *GifColorMap);
|
||||
void EGifSetGifVersion(GifFileType *GifFile, const bool gif89);
|
||||
int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine,
|
||||
int GifLineLen);
|
||||
int EGifPutPixel(GifFileType *GifFile, const GifPixelType GifPixel);
|
||||
int EGifPutComment(GifFileType *GifFile, const char *GifComment);
|
||||
int EGifPutExtensionLeader(GifFileType *GifFile, const int GifExtCode);
|
||||
int EGifPutExtensionBlock(GifFileType *GifFile,
|
||||
const int GifExtLen, const void *GifExtension);
|
||||
int EGifPutExtensionTrailer(GifFileType *GifFile);
|
||||
int EGifPutExtension(GifFileType *GifFile, const int GifExtCode,
|
||||
const int GifExtLen,
|
||||
const void *GifExtension);
|
||||
int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
|
||||
const GifByteType *GifCodeBlock);
|
||||
int EGifPutCodeNext(GifFileType *GifFile,
|
||||
const GifByteType *GifCodeBlock);
|
||||
|
||||
/******************************************************************************
|
||||
GIF decoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *DGifOpenFileName(const char *GifFileName, int *Error);
|
||||
GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
|
||||
int DGifSlurp(GifFileType * GifFile);
|
||||
GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error); /* new one (TVT) */
|
||||
int DGifCloseFile(GifFileType * GifFile, int *ErrorCode);
|
||||
|
||||
#define D_GIF_SUCCEEDED 0
|
||||
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
|
||||
#define D_GIF_ERR_READ_FAILED 102
|
||||
#define D_GIF_ERR_NOT_GIF_FILE 103
|
||||
#define D_GIF_ERR_NO_SCRN_DSCR 104
|
||||
#define D_GIF_ERR_NO_IMAG_DSCR 105
|
||||
#define D_GIF_ERR_NO_COLOR_MAP 106
|
||||
#define D_GIF_ERR_WRONG_RECORD 107
|
||||
#define D_GIF_ERR_DATA_TOO_BIG 108
|
||||
#define D_GIF_ERR_NOT_ENOUGH_MEM 109
|
||||
#define D_GIF_ERR_CLOSE_FAILED 110
|
||||
#define D_GIF_ERR_NOT_READABLE 111
|
||||
#define D_GIF_ERR_IMAGE_DEFECT 112
|
||||
#define D_GIF_ERR_EOF_TOO_SOON 113
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int DGifGetScreenDesc(GifFileType *GifFile);
|
||||
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
|
||||
int DGifGetImageHeader(GifFileType *GifFile);
|
||||
int DGifGetImageDesc(GifFileType *GifFile);
|
||||
int DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
|
||||
int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
|
||||
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
|
||||
GifByteType **GifExtension);
|
||||
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension);
|
||||
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
|
||||
GifByteType **GifCodeBlock);
|
||||
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
|
||||
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
|
||||
const char *DGifGetGifVersion(GifFileType *GifFile);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Error handling and reporting.
|
||||
******************************************************************************/
|
||||
extern const char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
|
||||
|
||||
/*****************************************************************************
|
||||
Everything below this point is new after version 1.2, supporting `slurp
|
||||
mode' for doing I/O in two big belts with all the image-bashing in core.
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Color map handling from gif_alloc.c
|
||||
******************************************************************************/
|
||||
|
||||
extern ColorMapObject *GifMakeMapObject(int ColorCount,
|
||||
const GifColorType *ColorMap);
|
||||
extern void GifFreeMapObject(ColorMapObject *Object);
|
||||
extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||
const ColorMapObject *ColorIn2,
|
||||
GifPixelType ColorTransIn2[]);
|
||||
extern int GifBitSize(int n);
|
||||
|
||||
/******************************************************************************
|
||||
Support for the in-core structures allocation (slurp mode).
|
||||
******************************************************************************/
|
||||
|
||||
extern void GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
|
||||
extern int GifAddExtensionBlock(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks,
|
||||
int Function,
|
||||
unsigned int Len, unsigned char ExtData[]);
|
||||
extern void GifFreeExtensions(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks);
|
||||
extern SavedImage *GifMakeSavedImage(GifFileType *GifFile,
|
||||
const SavedImage *CopyFrom);
|
||||
extern void GifFreeSavedImages(GifFileType *GifFile);
|
||||
|
||||
/******************************************************************************
|
||||
5.x functions for GIF89 graphics control blocks
|
||||
******************************************************************************/
|
||||
|
||||
int DGifExtensionToGCB(const size_t GifExtensionLength,
|
||||
const GifByteType *GifExtension,
|
||||
GraphicsControlBlock *GCB);
|
||||
size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
|
||||
GifByteType *GifExtension);
|
||||
|
||||
int DGifSavedExtensionToGCB(GifFileType *GifFile,
|
||||
int ImageIndex,
|
||||
GraphicsControlBlock *GCB);
|
||||
int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
|
||||
GifFileType *GifFile,
|
||||
int ImageIndex);
|
||||
|
||||
/******************************************************************************
|
||||
The library's internal utility font
|
||||
******************************************************************************/
|
||||
|
||||
#define GIF_FONT_WIDTH 8
|
||||
#define GIF_FONT_HEIGHT 8
|
||||
extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
|
||||
|
||||
extern void GifDrawText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend, const int color);
|
||||
|
||||
extern void GifDrawBox(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawRectangle(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawBoxedText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend,
|
||||
const int border, const int bg, const int fg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* _GIF_LIB_H */
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,70 @@
|
|||
/****************************************************************************
|
||||
|
||||
gif_lib_private.h - internal giflib routines and structures
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _GIF_LIB_PRIVATE_H
|
||||
#define _GIF_LIB_PRIVATE_H
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "gif_hash.h"
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX UINTPTR_MAX
|
||||
#endif
|
||||
|
||||
#define EXTENSION_INTRODUCER 0x21
|
||||
#define DESCRIPTOR_INTRODUCER 0x2c
|
||||
#define TERMINATOR_INTRODUCER 0x3b
|
||||
|
||||
#define LZ_MAX_CODE 4095 /* Biggest code possible in 12 bits. */
|
||||
#define LZ_BITS 12
|
||||
|
||||
#define FLUSH_OUTPUT 4096 /* Impossible code, to signal flush. */
|
||||
#define FIRST_CODE 4097 /* Impossible code, to signal first. */
|
||||
#define NO_SUCH_CODE 4098 /* Impossible code, to signal empty. */
|
||||
|
||||
#define FILE_STATE_WRITE 0x01
|
||||
#define FILE_STATE_SCREEN 0x02
|
||||
#define FILE_STATE_IMAGE 0x04
|
||||
#define FILE_STATE_READ 0x08
|
||||
|
||||
#define IS_READABLE(Private) (Private->FileState & FILE_STATE_READ)
|
||||
#define IS_WRITEABLE(Private) (Private->FileState & FILE_STATE_WRITE)
|
||||
|
||||
typedef struct GifFilePrivateType {
|
||||
GifWord FileState, FileHandle, /* Where all this data goes to! */
|
||||
BitsPerPixel, /* Bits per pixel (Codes uses at least this + 1). */
|
||||
ClearCode, /* The CLEAR LZ code. */
|
||||
EOFCode, /* The EOF LZ code. */
|
||||
RunningCode, /* The next code algorithm can generate. */
|
||||
RunningBits, /* The number of bits required to represent RunningCode. */
|
||||
MaxCode1, /* 1 bigger than max. possible code, in RunningBits bits. */
|
||||
LastCode, /* The code before the current code. */
|
||||
CrntCode, /* Current algorithm code. */
|
||||
StackPtr, /* For character stack (see below). */
|
||||
CrntShiftState; /* Number of bits in CrntShiftDWord. */
|
||||
unsigned long CrntShiftDWord; /* For bytes decomposition into codes. */
|
||||
unsigned long PixelCount; /* Number of pixels in image. */
|
||||
FILE *File; /* File as stream. */
|
||||
InputFunc Read; /* function to read gif input (TVT) */
|
||||
OutputFunc Write; /* function to write gif output (MRB) */
|
||||
GifByteType Buf[256]; /* Compressed input is buffered here. */
|
||||
GifByteType Stack[LZ_MAX_CODE]; /* Decoded pixels are stacked here. */
|
||||
GifByteType Suffix[LZ_MAX_CODE + 1]; /* So we can trace the codes. */
|
||||
GifPrefixType Prefix[LZ_MAX_CODE + 1];
|
||||
GifHashTableType *HashTable;
|
||||
bool gif89;
|
||||
} GifFilePrivateType;
|
||||
|
||||
#ifndef HAVE_REALLOCARRAY
|
||||
extern void *openbsd_reallocarray(void *optr, size_t nmemb, size_t size);
|
||||
#define reallocarray openbsd_reallocarray
|
||||
#endif
|
||||
|
||||
#endif /* _GIF_LIB_PRIVATE_H */
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,420 @@
|
|||
/*****************************************************************************
|
||||
|
||||
GIF construction tools
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "gif_lib_private.h"
|
||||
|
||||
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
/******************************************************************************
|
||||
Miscellaneous utility functions
|
||||
******************************************************************************/
|
||||
|
||||
/* return smallest bitfield size n will fit in */
|
||||
int
|
||||
GifBitSize(int n)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 1; i <= 8; i++)
|
||||
if ((1 << i) >= n)
|
||||
break;
|
||||
return (i);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Color map object functions
|
||||
******************************************************************************/
|
||||
|
||||
/*
|
||||
* Allocate a color map of given size; initialize with contents of
|
||||
* ColorMap if that pointer is non-NULL.
|
||||
*/
|
||||
ColorMapObject *
|
||||
GifMakeMapObject(int ColorCount, const GifColorType *ColorMap)
|
||||
{
|
||||
ColorMapObject *Object;
|
||||
|
||||
/*** FIXME: Our ColorCount has to be a power of two. Is it necessary to
|
||||
* make the user know that or should we automatically round up instead? */
|
||||
if (ColorCount != (1 << GifBitSize(ColorCount))) {
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
Object = (ColorMapObject *)malloc(sizeof(ColorMapObject));
|
||||
if (Object == (ColorMapObject *) NULL) {
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
Object->Colors = (GifColorType *)calloc(ColorCount, sizeof(GifColorType));
|
||||
if (Object->Colors == (GifColorType *) NULL) {
|
||||
free(Object);
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
Object->ColorCount = ColorCount;
|
||||
Object->BitsPerPixel = GifBitSize(ColorCount);
|
||||
Object->SortFlag = false;
|
||||
|
||||
if (ColorMap != NULL) {
|
||||
memcpy((char *)Object->Colors,
|
||||
(char *)ColorMap, ColorCount * sizeof(GifColorType));
|
||||
}
|
||||
|
||||
return (Object);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Free a color map object
|
||||
*******************************************************************************/
|
||||
void
|
||||
GifFreeMapObject(ColorMapObject *Object)
|
||||
{
|
||||
if (Object != NULL) {
|
||||
(void)free(Object->Colors);
|
||||
(void)free(Object);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
DumpColorMap(ColorMapObject *Object,
|
||||
FILE * fp)
|
||||
{
|
||||
if (Object != NULL) {
|
||||
int i, j, Len = Object->ColorCount;
|
||||
|
||||
for (i = 0; i < Len; i += 4) {
|
||||
for (j = 0; j < 4 && j < Len; j++) {
|
||||
(void)fprintf(fp, "%3d: %02x %02x %02x ", i + j,
|
||||
Object->Colors[i + j].Red,
|
||||
Object->Colors[i + j].Green,
|
||||
Object->Colors[i + j].Blue);
|
||||
}
|
||||
(void)fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
/*******************************************************************************
|
||||
Compute the union of two given color maps and return it. If result can't
|
||||
fit into 256 colors, NULL is returned, the allocated union otherwise.
|
||||
ColorIn1 is copied as is to ColorUnion, while colors from ColorIn2 are
|
||||
copied iff they didn't exist before. ColorTransIn2 maps the old
|
||||
ColorIn2 into the ColorUnion color map table./
|
||||
*******************************************************************************/
|
||||
ColorMapObject *
|
||||
GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||
const ColorMapObject *ColorIn2,
|
||||
GifPixelType ColorTransIn2[])
|
||||
{
|
||||
int i, j, CrntSlot, RoundUpTo, NewGifBitSize;
|
||||
ColorMapObject *ColorUnion;
|
||||
|
||||
/*
|
||||
* We don't worry about duplicates within either color map; if
|
||||
* the caller wants to resolve those, he can perform unions
|
||||
* with an empty color map.
|
||||
*/
|
||||
|
||||
/* Allocate table which will hold the result for sure. */
|
||||
ColorUnion = GifMakeMapObject(MAX(ColorIn1->ColorCount,
|
||||
ColorIn2->ColorCount) * 2, NULL);
|
||||
|
||||
if (ColorUnion == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Copy ColorIn1 to ColorUnion.
|
||||
*/
|
||||
for (i = 0; i < ColorIn1->ColorCount; i++)
|
||||
ColorUnion->Colors[i] = ColorIn1->Colors[i];
|
||||
CrntSlot = ColorIn1->ColorCount;
|
||||
|
||||
/*
|
||||
* Potentially obnoxious hack:
|
||||
*
|
||||
* Back CrntSlot down past all contiguous {0, 0, 0} slots at the end
|
||||
* of table 1. This is very useful if your display is limited to
|
||||
* 16 colors.
|
||||
*/
|
||||
while (ColorIn1->Colors[CrntSlot - 1].Red == 0
|
||||
&& ColorIn1->Colors[CrntSlot - 1].Green == 0
|
||||
&& ColorIn1->Colors[CrntSlot - 1].Blue == 0)
|
||||
CrntSlot--;
|
||||
|
||||
/* Copy ColorIn2 to ColorUnion (use old colors if they exist): */
|
||||
for (i = 0; i < ColorIn2->ColorCount && CrntSlot <= 256; i++) {
|
||||
/* Let's see if this color already exists: */
|
||||
for (j = 0; j < ColorIn1->ColorCount; j++)
|
||||
if (memcmp (&ColorIn1->Colors[j], &ColorIn2->Colors[i],
|
||||
sizeof(GifColorType)) == 0)
|
||||
break;
|
||||
|
||||
if (j < ColorIn1->ColorCount)
|
||||
ColorTransIn2[i] = j; /* color exists in Color1 */
|
||||
else {
|
||||
/* Color is new - copy it to a new slot: */
|
||||
ColorUnion->Colors[CrntSlot] = ColorIn2->Colors[i];
|
||||
ColorTransIn2[i] = CrntSlot++;
|
||||
}
|
||||
}
|
||||
|
||||
if (CrntSlot > 256) {
|
||||
GifFreeMapObject(ColorUnion);
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
|
||||
NewGifBitSize = GifBitSize(CrntSlot);
|
||||
RoundUpTo = (1 << NewGifBitSize);
|
||||
|
||||
if (RoundUpTo != ColorUnion->ColorCount) {
|
||||
register GifColorType *Map = ColorUnion->Colors;
|
||||
|
||||
/*
|
||||
* Zero out slots up to next power of 2.
|
||||
* We know these slots exist because of the way ColorUnion's
|
||||
* start dimension was computed.
|
||||
*/
|
||||
for (j = CrntSlot; j < RoundUpTo; j++)
|
||||
Map[j].Red = Map[j].Green = Map[j].Blue = 0;
|
||||
|
||||
/* perhaps we can shrink the map? */
|
||||
if (RoundUpTo < ColorUnion->ColorCount) {
|
||||
GifColorType *new_map = (GifColorType *)reallocarray(Map,
|
||||
RoundUpTo, sizeof(GifColorType));
|
||||
if( new_map == NULL ) {
|
||||
GifFreeMapObject(ColorUnion);
|
||||
return ((ColorMapObject *) NULL);
|
||||
}
|
||||
ColorUnion->Colors = new_map;
|
||||
}
|
||||
}
|
||||
|
||||
ColorUnion->ColorCount = RoundUpTo;
|
||||
ColorUnion->BitsPerPixel = NewGifBitSize;
|
||||
|
||||
return (ColorUnion);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Apply a given color translation to the raster bits of an image
|
||||
*******************************************************************************/
|
||||
void
|
||||
GifApplyTranslation(SavedImage *Image, GifPixelType Translation[])
|
||||
{
|
||||
register int i;
|
||||
register int RasterSize = Image->ImageDesc.Height * Image->ImageDesc.Width;
|
||||
|
||||
for (i = 0; i < RasterSize; i++)
|
||||
Image->RasterBits[i] = Translation[Image->RasterBits[i]];
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Extension record functions
|
||||
******************************************************************************/
|
||||
int
|
||||
GifAddExtensionBlock(int *ExtensionBlockCount,
|
||||
ExtensionBlock **ExtensionBlocks,
|
||||
int Function,
|
||||
unsigned int Len,
|
||||
unsigned char ExtData[])
|
||||
{
|
||||
ExtensionBlock *ep;
|
||||
|
||||
if (*ExtensionBlocks == NULL)
|
||||
*ExtensionBlocks=(ExtensionBlock *)malloc(sizeof(ExtensionBlock));
|
||||
else {
|
||||
ExtensionBlock* ep_new = (ExtensionBlock *)reallocarray
|
||||
(*ExtensionBlocks, (*ExtensionBlockCount + 1),
|
||||
sizeof(ExtensionBlock));
|
||||
if( ep_new == NULL )
|
||||
return (GIF_ERROR);
|
||||
*ExtensionBlocks = ep_new;
|
||||
}
|
||||
|
||||
if (*ExtensionBlocks == NULL)
|
||||
return (GIF_ERROR);
|
||||
|
||||
ep = &(*ExtensionBlocks)[(*ExtensionBlockCount)++];
|
||||
|
||||
ep->Function = Function;
|
||||
ep->ByteCount=Len;
|
||||
ep->Bytes = (GifByteType *)malloc(ep->ByteCount);
|
||||
if (ep->Bytes == NULL)
|
||||
return (GIF_ERROR);
|
||||
|
||||
if (ExtData != NULL) {
|
||||
memcpy(ep->Bytes, ExtData, Len);
|
||||
}
|
||||
|
||||
return (GIF_OK);
|
||||
}
|
||||
|
||||
void
|
||||
GifFreeExtensions(int *ExtensionBlockCount,
|
||||
ExtensionBlock **ExtensionBlocks)
|
||||
{
|
||||
ExtensionBlock *ep;
|
||||
|
||||
if (*ExtensionBlocks == NULL)
|
||||
return;
|
||||
|
||||
for (ep = *ExtensionBlocks;
|
||||
ep < (*ExtensionBlocks + *ExtensionBlockCount);
|
||||
ep++)
|
||||
(void)free((char *)ep->Bytes);
|
||||
(void)free((char *)*ExtensionBlocks);
|
||||
*ExtensionBlocks = NULL;
|
||||
*ExtensionBlockCount = 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Image block allocation functions
|
||||
******************************************************************************/
|
||||
|
||||
/* Private Function:
|
||||
* Frees the last image in the GifFile->SavedImages array
|
||||
*/
|
||||
void
|
||||
FreeLastSavedImage(GifFileType *GifFile)
|
||||
{
|
||||
SavedImage *sp;
|
||||
|
||||
if ((GifFile == NULL) || (GifFile->SavedImages == NULL))
|
||||
return;
|
||||
|
||||
/* Remove one SavedImage from the GifFile */
|
||||
GifFile->ImageCount--;
|
||||
sp = &GifFile->SavedImages[GifFile->ImageCount];
|
||||
|
||||
/* Deallocate its Colormap */
|
||||
if (sp->ImageDesc.ColorMap != NULL) {
|
||||
GifFreeMapObject(sp->ImageDesc.ColorMap);
|
||||
sp->ImageDesc.ColorMap = NULL;
|
||||
}
|
||||
|
||||
/* Deallocate the image data */
|
||||
if (sp->RasterBits != NULL)
|
||||
free((char *)sp->RasterBits);
|
||||
|
||||
/* Deallocate any extensions */
|
||||
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
|
||||
|
||||
/*** FIXME: We could realloc the GifFile->SavedImages structure but is
|
||||
* there a point to it? Saves some memory but we'd have to do it every
|
||||
* time. If this is used in GifFreeSavedImages then it would be inefficient
|
||||
* (The whole array is going to be deallocated.) If we just use it when
|
||||
* we want to free the last Image it's convenient to do it here.
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Append an image block to the SavedImages array
|
||||
*/
|
||||
SavedImage *
|
||||
GifMakeSavedImage(GifFileType *GifFile, const SavedImage *CopyFrom)
|
||||
{
|
||||
if (GifFile->SavedImages == NULL)
|
||||
GifFile->SavedImages = (SavedImage *)malloc(sizeof(SavedImage));
|
||||
else {
|
||||
SavedImage* newSavedImages = (SavedImage *)reallocarray(GifFile->SavedImages,
|
||||
(GifFile->ImageCount + 1), sizeof(SavedImage));
|
||||
if( newSavedImages == NULL)
|
||||
return ((SavedImage *)NULL);
|
||||
GifFile->SavedImages = newSavedImages;
|
||||
}
|
||||
if (GifFile->SavedImages == NULL)
|
||||
return ((SavedImage *)NULL);
|
||||
else {
|
||||
SavedImage *sp = &GifFile->SavedImages[GifFile->ImageCount++];
|
||||
|
||||
if (CopyFrom != NULL) {
|
||||
memcpy((char *)sp, CopyFrom, sizeof(SavedImage));
|
||||
|
||||
/*
|
||||
* Make our own allocated copies of the heap fields in the
|
||||
* copied record. This guards against potential aliasing
|
||||
* problems.
|
||||
*/
|
||||
|
||||
/* first, the local color map */
|
||||
if (CopyFrom->ImageDesc.ColorMap != NULL) {
|
||||
sp->ImageDesc.ColorMap = GifMakeMapObject(
|
||||
CopyFrom->ImageDesc.ColorMap->ColorCount,
|
||||
CopyFrom->ImageDesc.ColorMap->Colors);
|
||||
if (sp->ImageDesc.ColorMap == NULL) {
|
||||
FreeLastSavedImage(GifFile);
|
||||
return (SavedImage *)(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* next, the raster */
|
||||
sp->RasterBits = (unsigned char *)reallocarray(NULL,
|
||||
(CopyFrom->ImageDesc.Height *
|
||||
CopyFrom->ImageDesc.Width),
|
||||
sizeof(GifPixelType));
|
||||
if (sp->RasterBits == NULL) {
|
||||
FreeLastSavedImage(GifFile);
|
||||
return (SavedImage *)(NULL);
|
||||
}
|
||||
memcpy(sp->RasterBits, CopyFrom->RasterBits,
|
||||
sizeof(GifPixelType) * CopyFrom->ImageDesc.Height *
|
||||
CopyFrom->ImageDesc.Width);
|
||||
|
||||
/* finally, the extension blocks */
|
||||
if (CopyFrom->ExtensionBlocks != NULL) {
|
||||
sp->ExtensionBlocks = (ExtensionBlock *)reallocarray(NULL,
|
||||
CopyFrom->ExtensionBlockCount,
|
||||
sizeof(ExtensionBlock));
|
||||
if (sp->ExtensionBlocks == NULL) {
|
||||
FreeLastSavedImage(GifFile);
|
||||
return (SavedImage *)(NULL);
|
||||
}
|
||||
memcpy(sp->ExtensionBlocks, CopyFrom->ExtensionBlocks,
|
||||
sizeof(ExtensionBlock) * CopyFrom->ExtensionBlockCount);
|
||||
}
|
||||
}
|
||||
else {
|
||||
memset((char *)sp, '\0', sizeof(SavedImage));
|
||||
}
|
||||
|
||||
return (sp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GifFreeSavedImages(GifFileType *GifFile)
|
||||
{
|
||||
SavedImage *sp;
|
||||
|
||||
if ((GifFile == NULL) || (GifFile->SavedImages == NULL)) {
|
||||
return;
|
||||
}
|
||||
for (sp = GifFile->SavedImages;
|
||||
sp < GifFile->SavedImages + GifFile->ImageCount; sp++) {
|
||||
if (sp->ImageDesc.ColorMap != NULL) {
|
||||
GifFreeMapObject(sp->ImageDesc.ColorMap);
|
||||
sp->ImageDesc.ColorMap = NULL;
|
||||
}
|
||||
|
||||
if (sp->RasterBits != NULL)
|
||||
free((char *)sp->RasterBits);
|
||||
|
||||
GifFreeExtensions(&sp->ExtensionBlockCount, &sp->ExtensionBlocks);
|
||||
}
|
||||
free((char *)GifFile->SavedImages);
|
||||
GifFile->SavedImages = NULL;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,349 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifbg - generate a test-pattern GIF
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifbg"
|
||||
|
||||
#define DEFAULT_WIDTH 640
|
||||
#define DEFAULT_HEIGHT 350
|
||||
|
||||
#define DEFAULT_COLOR_RED 0
|
||||
#define DEFAULT_COLOR_GREEN 0
|
||||
#define DEFAULT_COLOR_BLUE 255
|
||||
|
||||
#define DEFAULT_MIN_INTENSITY 10 /* In percent. */
|
||||
#define DEFAULT_MAX_INTENSITY 100
|
||||
|
||||
#define DEFAULT_NUM_LEVELS 16 /* Number of colors to gen in image. */
|
||||
|
||||
#define DIR_NONE 0 /* Direction the levels can be changed: */
|
||||
#define DIR_TOP 1
|
||||
#define DIR_TOP_RIGHT 2
|
||||
#define DIR_RIGHT 3
|
||||
#define DIR_BOT_RIGHT 4
|
||||
#define DIR_BOT 5
|
||||
#define DIR_BOT_LEFT 6
|
||||
#define DIR_LEFT 7
|
||||
#define DIR_TOP_LEFT 8
|
||||
|
||||
#define DEFAULT_DIR "T" /* TOP (North) direction. */
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- d%-Dir!s l%-#Lvls!d c%-R|G|B!d!d!d m%-MinI!d M%-MaxI!d s%-W|H!d!d h%-";
|
||||
|
||||
static int
|
||||
MaximumIntensity = DEFAULT_MAX_INTENSITY, /* In percent. */
|
||||
MinimumIntensity = DEFAULT_MIN_INTENSITY,
|
||||
NumLevels = DEFAULT_NUM_LEVELS,
|
||||
ImageWidth = DEFAULT_WIDTH,
|
||||
ImageHeight = DEFAULT_HEIGHT,
|
||||
Direction;
|
||||
static unsigned int
|
||||
RedColor = DEFAULT_COLOR_RED,
|
||||
GreenColor = DEFAULT_COLOR_GREEN,
|
||||
BlueColor = DEFAULT_COLOR_BLUE;
|
||||
|
||||
static void QuitGifError(GifFileType *GifFile);
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and scan the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, l, LevelWidth, LogNumLevels, ErrorCode, Count = 0;
|
||||
bool Error, FlipDir, DoAllMaximum = false,
|
||||
DirectionFlag = false, LevelsFlag = false, ColorFlag = false,
|
||||
MinFlag = false, MaxFlag = false, SizeFlag = false, HelpFlag = false;
|
||||
GifPixelType Color;
|
||||
char *DirectionStr = DEFAULT_DIR;
|
||||
GifRowType Line;
|
||||
ColorMapObject *ColorMap;
|
||||
GifFileType *GifFile;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
|
||||
&DirectionFlag, &DirectionStr, &LevelsFlag, &NumLevels,
|
||||
&ColorFlag, &RedColor, &GreenColor, &BlueColor,
|
||||
&MinFlag, &MinimumIntensity, &MaxFlag, &MaximumIntensity,
|
||||
&SizeFlag, &ImageWidth, &ImageHeight,
|
||||
&HelpFlag)) != false) {
|
||||
GAPrintErrMsg(Error);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Make sure intensities are in the right range: */
|
||||
if (MinimumIntensity < 0 || MinimumIntensity > 100 ||
|
||||
MaximumIntensity < 0 || MaximumIntensity > 100)
|
||||
GIF_EXIT("Intensities (-m or -M options) are not in [0..100] range (percent).");
|
||||
|
||||
/* Convert DirectionStr to our local representation: */
|
||||
Direction = DIR_NONE;
|
||||
FlipDir = false;
|
||||
/* Make sure it's upper case. */
|
||||
for (i = 0; i < (int)strlen(DirectionStr); i++)
|
||||
if (islower(DirectionStr[i]))
|
||||
DirectionStr[i] = toupper(DirectionStr[i]);
|
||||
|
||||
switch(DirectionStr[0]) {
|
||||
case 'T': /* Top or North */
|
||||
case 'N':
|
||||
if (strlen(DirectionStr) < 2)
|
||||
Direction = DIR_TOP;
|
||||
else
|
||||
switch(DirectionStr[1]) {
|
||||
case 'R':
|
||||
case 'E':
|
||||
Direction = DIR_TOP_RIGHT;
|
||||
break;
|
||||
case 'L':
|
||||
case 'W':
|
||||
Direction = DIR_TOP_LEFT;
|
||||
FlipDir = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'R': /* Right or East */
|
||||
case 'E':
|
||||
Direction = DIR_RIGHT;
|
||||
break;
|
||||
case 'B': /* Bottom or South */
|
||||
case 'S':
|
||||
if (strlen(DirectionStr) < 2) {
|
||||
Direction = DIR_BOT;
|
||||
FlipDir = true;
|
||||
}
|
||||
else
|
||||
switch(DirectionStr[1]) {
|
||||
case 'R':
|
||||
case 'E':
|
||||
Direction = DIR_BOT_RIGHT;
|
||||
break;
|
||||
case 'L':
|
||||
case 'W':
|
||||
Direction = DIR_BOT_LEFT;
|
||||
FlipDir = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'L': /* Left or West */
|
||||
case 'W':
|
||||
Direction = DIR_LEFT;
|
||||
FlipDir = true;
|
||||
break;
|
||||
}
|
||||
if (Direction == DIR_NONE)
|
||||
GIF_EXIT("Direction requested (-d option) is weird!");
|
||||
|
||||
/* We are going to handle only TOP, TOP_RIGHT, RIGHT, BOT_RIGHT so flip */
|
||||
/* the complement cases (TOP <-> BOT for example) by flipping the */
|
||||
/* Color i with color (NumLevels - i - 1). */
|
||||
if (FlipDir) {
|
||||
switch (Direction) {
|
||||
case DIR_BOT:
|
||||
Direction = DIR_TOP;
|
||||
break;
|
||||
case DIR_BOT_LEFT:
|
||||
Direction = DIR_TOP_RIGHT;
|
||||
break;
|
||||
case DIR_LEFT:
|
||||
Direction = DIR_RIGHT;
|
||||
break;
|
||||
case DIR_TOP_LEFT:
|
||||
Direction = DIR_BOT_RIGHT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If binary mask is requested (special case): */
|
||||
if (MinimumIntensity == 100 && MaximumIntensity == 100 && NumLevels == 2) {
|
||||
MinimumIntensity = 0;
|
||||
DoAllMaximum = true;
|
||||
Direction = DIR_RIGHT;
|
||||
}
|
||||
|
||||
/* Make sure colors are in the right range: */
|
||||
if (RedColor > 255 || GreenColor > 255 || BlueColor > 255)
|
||||
GIF_EXIT("Colors are not in the ragne [0..255].");
|
||||
|
||||
/* Make sure number of levels is power of 2 (up to 8 bits per pixel). */
|
||||
for (i = 1; i < 8; i++) if (NumLevels == (1 << i)) break;
|
||||
if (i == 8) GIF_EXIT("#Lvls (-l option) is not power of 2.");
|
||||
LogNumLevels = i;
|
||||
|
||||
/* Open stdout for the output file: */
|
||||
if ((GifFile = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Dump out screen description with given size and generated color map: */
|
||||
if ((ColorMap = GifMakeMapObject(NumLevels, NULL)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
for (i = 1; i <= NumLevels; i++) {
|
||||
/* Ratio will be in the range of 0..100 for required intensity: */
|
||||
unsigned int Ratio = (MaximumIntensity * (i * (256 / NumLevels)) +
|
||||
MinimumIntensity * ((NumLevels - i) * (256 / NumLevels))) /
|
||||
256;
|
||||
ColorMap->Colors[i-1].Red = (RedColor * Ratio) / 100;
|
||||
ColorMap->Colors[i-1].Green = (GreenColor * Ratio) / 100;
|
||||
ColorMap->Colors[i-1].Blue = (BlueColor * Ratio) / 100;
|
||||
}
|
||||
if (EGifPutScreenDesc(GifFile,
|
||||
ImageWidth, ImageHeight, LogNumLevels, 0, ColorMap)
|
||||
== GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
|
||||
/* Dump out the image descriptor: */
|
||||
if (EGifPutImageDesc(GifFile,
|
||||
0, 0, ImageWidth, ImageHeight, false, NULL) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
|
||||
GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
|
||||
GifFile->Image.Width, GifFile->Image.Height);
|
||||
|
||||
/* Allocate one scan line twice as big as image is, as we are going to */
|
||||
/* shift along it, while we dump the scan lines: */
|
||||
if ((Line = (GifRowType) malloc(sizeof(GifPixelType) * ImageWidth * 2)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
if (Direction == DIR_TOP) {
|
||||
int LevelHeight;
|
||||
/* We must evaluate the line each time level is changing: */
|
||||
LevelHeight = ImageHeight / NumLevels;
|
||||
for (Color = NumLevels, i = l = 0; i < ImageHeight; i++) {
|
||||
if (i == l) {
|
||||
int j;
|
||||
/* Time to update the line to next color level: */
|
||||
if (Color != 0) Color--;
|
||||
for (j = 0; j < ImageWidth; j++)
|
||||
Line[j] = (FlipDir ? NumLevels - Color - 1 : Color);
|
||||
l += LevelHeight;
|
||||
}
|
||||
if (EGifPutLine(GifFile, Line, ImageWidth) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
GifQprintf("\b\b\b\b%-4d", Count++);
|
||||
}
|
||||
}
|
||||
else if (Direction == DIR_RIGHT) {
|
||||
/* We pre-prepare the scan lines as going from color zero to maximum */
|
||||
/* color and dump the same scan line Height times: */
|
||||
/* Note this case should handle the Boolean Mask special case. */
|
||||
LevelWidth = ImageWidth / NumLevels;
|
||||
if (DoAllMaximum) {
|
||||
/* Special case - do all in maximum color: */
|
||||
for (i = 0; i < ImageWidth; i++) Line[i] = 1;
|
||||
}
|
||||
else {
|
||||
for (Color = i = 0, l = LevelWidth; i < ImageWidth; i++, l--) {
|
||||
if (l == 0) {
|
||||
l = LevelWidth;
|
||||
if (Color < NumLevels - 1) Color++;
|
||||
}
|
||||
Line[i] = (FlipDir ? NumLevels - Color - 1 : Color);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ImageHeight; i++) {
|
||||
/* coverity[uninit_use_in_call] */
|
||||
if (EGifPutLine(GifFile, Line, ImageWidth) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
GifQprintf("\b\b\b\b%-4d", Count++);
|
||||
}
|
||||
}
|
||||
else {
|
||||
int Accumulator, StartX, StepX;
|
||||
/* We are in one of the TOP_RIGHT, BOT_RIGHT cases: we will */
|
||||
/* initialize the Line with its double ImageWidth length from the */
|
||||
/* minimum intensity to the maximum intensity and shift along it */
|
||||
/* while we go along the image height. */
|
||||
LevelWidth = ImageWidth * 2 / NumLevels;
|
||||
for (Color = i = 0, l = LevelWidth; i < ImageWidth * 2; i++, l--) {
|
||||
if (l == 0) {
|
||||
l = LevelWidth;
|
||||
if (Color < NumLevels - 1) Color++;
|
||||
}
|
||||
Line[i] = (FlipDir ? NumLevels - Color - 1 : Color);
|
||||
}
|
||||
/* We need to implement a DDA to know how much to shift Line while */
|
||||
/* we go down along image height. we set the parameters for it now: */
|
||||
Accumulator = 0;
|
||||
switch(Direction) {
|
||||
case DIR_TOP_RIGHT:
|
||||
StartX = ImageWidth;
|
||||
StepX = -1;
|
||||
break;
|
||||
case DIR_BOT_RIGHT:
|
||||
default:
|
||||
StartX = 0;
|
||||
StepX = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Time to dump information out: */
|
||||
for (i = 0; i < ImageHeight; i++) {
|
||||
if (EGifPutLine(GifFile, &Line[StartX], ImageWidth) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
GifQprintf("\b\b\b\b%-4d", Count++);
|
||||
if ((Accumulator += ImageWidth) > ImageHeight) {
|
||||
while (Accumulator > ImageHeight) {
|
||||
Accumulator -= ImageHeight;
|
||||
StartX += StepX;
|
||||
}
|
||||
if (Direction < 0) Direction = 0;
|
||||
if (Direction > ImageWidth) Direction = ImageWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Close output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void QuitGifError(GifFileType *GifFile)
|
||||
{
|
||||
if (GifFile != NULL) {
|
||||
PrintGifError(GifFile->Error);
|
||||
EGifCloseFile(GifFile, NULL);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,940 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifbuild - dump GIF data in a textual format, or undump it to a GIF
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifbuild"
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Eric Raymond, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1992 Eric Raymond.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- d%- t%-Characters!s h%- GifFile(s)!*s";
|
||||
|
||||
static char KeyLetters[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:<=>?@[\\]^_`{|}~";
|
||||
#define PRINTABLES (sizeof(KeyLetters) - 1)
|
||||
|
||||
static void Icon2Gif(char *FileName, FILE *txtin, int fdout);
|
||||
static void Gif2Icon(char *FileName,
|
||||
int fdin, int fdout,
|
||||
char NameTable[]);
|
||||
static int EscapeString(char *cp, char *tp);
|
||||
|
||||
/******************************************************************************
|
||||
Main sequence
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int NumFiles;
|
||||
bool Error, DisasmFlag = false, HelpFlag = false, TextLineFlag = false;
|
||||
char **FileNames = NULL;
|
||||
char *TextLines[1];
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr,
|
||||
&GifNoisyPrint, &DisasmFlag, &TextLineFlag, &TextLines[0],
|
||||
&HelpFlag, &NumFiles, &FileNames)) != false) {
|
||||
GAPrintErrMsg(Error);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (!DisasmFlag && NumFiles > 1) {
|
||||
GIF_MESSAGE("Error in command line parsing - one text input please.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!DisasmFlag && TextLineFlag) {
|
||||
GIF_MESSAGE("Error in command line parsing - -t invalid without -d.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
if (NumFiles == 0)
|
||||
{
|
||||
if (DisasmFlag)
|
||||
Gif2Icon("Stdin", 0, 1, TextLineFlag ? TextLines[0] : KeyLetters);
|
||||
else
|
||||
Icon2Gif("Stdin", stdin, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < NumFiles; i++)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen(FileNames[i], "r")) == (FILE *)NULL)
|
||||
{
|
||||
(void) fprintf(stderr, "Can't open %s\n", FileNames[i]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (DisasmFlag)
|
||||
{
|
||||
printf("#\n# GIF information from %s\n", FileNames[i]);
|
||||
Gif2Icon(FileNames[i], -1, 1, TextLineFlag ? TextLines[0] : KeyLetters);
|
||||
}
|
||||
else
|
||||
{
|
||||
Icon2Gif(FileNames[i], fp, 1);
|
||||
}
|
||||
|
||||
(void) fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Parse image directives
|
||||
******************************************************************************/
|
||||
#define PARSE_ERROR(str) (void) fprintf(stderr,"%s:%d: %s\n",FileName,LineNum,str);
|
||||
|
||||
static void Icon2Gif(char *FileName, FILE *txtin, int fdout)
|
||||
{
|
||||
unsigned int ColorMapSize = 0;
|
||||
GifColorType GlobalColorMap[256], LocalColorMap[256],
|
||||
*ColorMap = GlobalColorMap;
|
||||
char GlobalColorKeys[PRINTABLES], LocalColorKeys[PRINTABLES],
|
||||
*KeyTable = GlobalColorKeys;
|
||||
bool SortFlag = false;
|
||||
unsigned int ExtCode, intval;
|
||||
int red, green, blue, n;
|
||||
char buf[BUFSIZ * 2], InclusionFile[64];
|
||||
GifFileType *GifFileOut;
|
||||
SavedImage *NewImage = NULL;
|
||||
int LeadingExtensionBlockCount = 0;
|
||||
ExtensionBlock *LeadingExtensionBlocks = NULL;
|
||||
int ErrorCode, LineNum = 0;
|
||||
|
||||
if ((GifFileOut = EGifOpenFileHandle(fdout, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* OK, interpret directives */
|
||||
/* coverity[tainted_data_transitive] */
|
||||
while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
|
||||
{
|
||||
char *cp;
|
||||
|
||||
++LineNum;
|
||||
|
||||
/*
|
||||
* Skip lines consisting only of whitespace and comments
|
||||
*/
|
||||
for (cp = buf; isspace((int)(*cp)); cp++)
|
||||
continue;
|
||||
if (*cp == '#' || *cp == '\0')
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If there's a trailing comment, nuke it and all preceding whitespace.
|
||||
* But preserve the EOL.
|
||||
*/
|
||||
if ((cp = strchr(buf, '#')) && (cp == strrchr(cp, '#')))
|
||||
{
|
||||
while (isspace((int)(*--cp)))
|
||||
continue;
|
||||
*++cp = '\n';
|
||||
*++cp = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Explicit header declarations
|
||||
*/
|
||||
|
||||
if (sscanf(buf, "screen width %d\n", &GifFileOut->SWidth) == 1)
|
||||
continue;
|
||||
|
||||
else if (sscanf(buf, "screen height %d\n", &GifFileOut->SHeight) == 1)
|
||||
continue;
|
||||
|
||||
else if (sscanf(buf, "screen colors %d\n", &n) == 1)
|
||||
{
|
||||
int ResBits = GifBitSize(n);
|
||||
|
||||
if (n > 256 || n < 0 || n != (1 << ResBits))
|
||||
{
|
||||
PARSE_ERROR("Invalid color resolution value.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
GifFileOut->SColorResolution = ResBits;
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (sscanf(buf,
|
||||
"screen background %d\n",
|
||||
&GifFileOut->SBackGroundColor) == 1)
|
||||
continue;
|
||||
|
||||
else if (sscanf(buf, "pixel aspect byte %u\n", &intval) == 1) {
|
||||
GifFileOut->AspectByte = (GifByteType)(intval & 0xff);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Color table parsing
|
||||
*/
|
||||
|
||||
else if (strcmp(buf, "screen map\n") == 0)
|
||||
{
|
||||
if (GifFileOut->SColorMap != NULL)
|
||||
{
|
||||
PARSE_ERROR("You've already declared a global color map.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ColorMapSize = 0;
|
||||
ColorMap = GlobalColorMap;
|
||||
SortFlag = false;
|
||||
KeyTable = GlobalColorKeys;
|
||||
memset(GlobalColorKeys, '\0', sizeof(GlobalColorKeys));
|
||||
}
|
||||
|
||||
else if (strcmp(buf, "image map\n") == 0)
|
||||
{
|
||||
if (NewImage == NULL)
|
||||
{
|
||||
PARSE_ERROR("No previous image declaration.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ColorMapSize = 0;
|
||||
ColorMap = LocalColorMap;
|
||||
KeyTable = LocalColorKeys;
|
||||
memset(LocalColorKeys, '\0', sizeof(LocalColorKeys));
|
||||
}
|
||||
|
||||
else if (sscanf(buf, " rgb %d %d %d is %c",
|
||||
&red, &green, &blue, &KeyTable[ColorMapSize]) == 4)
|
||||
{
|
||||
ColorMap[ColorMapSize].Red = red;
|
||||
ColorMap[ColorMapSize].Green = green;
|
||||
ColorMap[ColorMapSize].Blue = blue;
|
||||
ColorMapSize++;
|
||||
}
|
||||
|
||||
else if (sscanf(buf, " rgb %d %d %d", &red, &green, &blue) == 3)
|
||||
{
|
||||
ColorMap[ColorMapSize].Red = red;
|
||||
ColorMap[ColorMapSize].Green = green;
|
||||
ColorMap[ColorMapSize].Blue = blue;
|
||||
ColorMapSize++;
|
||||
}
|
||||
|
||||
else if (strcmp(buf, " sort flag on\n") == 0)
|
||||
SortFlag = true;
|
||||
|
||||
else if (strcmp(buf, " sort flag off\n") == 0)
|
||||
SortFlag = false;
|
||||
|
||||
else if (strcmp(buf, "end\n") == 0)
|
||||
{
|
||||
ColorMapObject *NewMap;
|
||||
|
||||
NewMap = GifMakeMapObject(1 << GifBitSize(ColorMapSize), ColorMap);
|
||||
if (NewMap == (ColorMapObject *)NULL)
|
||||
{
|
||||
PARSE_ERROR("Out of memory while allocating new color map.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
NewMap->SortFlag = SortFlag;
|
||||
|
||||
if (NewImage)
|
||||
NewImage->ImageDesc.ColorMap = NewMap;
|
||||
else
|
||||
GifFileOut->SColorMap = NewMap;
|
||||
}
|
||||
|
||||
/* GIF inclusion */
|
||||
/* ugly magic number is because scanf has no */
|
||||
else if (sscanf(buf, "include %63s", InclusionFile) == 1)
|
||||
{
|
||||
int ErrorCode;
|
||||
bool DoTranslation;
|
||||
GifPixelType Translation[256];
|
||||
|
||||
GifFileType *Inclusion;
|
||||
SavedImage *CopyFrom;
|
||||
|
||||
if ((Inclusion = DGifOpenFileName(InclusionFile, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (DGifSlurp(Inclusion) == GIF_ERROR)
|
||||
{
|
||||
PARSE_ERROR("Inclusion read failed.");
|
||||
if (Inclusion != NULL) {
|
||||
PrintGifError(Inclusion->Error);
|
||||
DGifCloseFile(Inclusion, NULL);
|
||||
}
|
||||
if (GifFileOut != NULL) {
|
||||
EGifCloseFile(GifFileOut, NULL);
|
||||
};
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
//cppcheck-suppress nullPointerRedundantCheck
|
||||
if ((DoTranslation = (GifFileOut->SColorMap!=(ColorMapObject*)NULL)))
|
||||
{
|
||||
ColorMapObject *UnionMap;
|
||||
|
||||
//cppcheck-suppress nullPointerRedundantCheck
|
||||
UnionMap = GifUnionColorMap(GifFileOut->SColorMap, Inclusion->SColorMap, Translation);
|
||||
|
||||
if (UnionMap == NULL)
|
||||
{
|
||||
PARSE_ERROR("Inclusion failed --- global map conflict.");
|
||||
//cppcheck-suppress nullPointerRedundantCheck
|
||||
PrintGifError(GifFileOut->Error);
|
||||
if (Inclusion != NULL) DGifCloseFile(Inclusion, NULL);
|
||||
if (GifFileOut != NULL) EGifCloseFile(GifFileOut, NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
GifFreeMapObject(GifFileOut->SColorMap);
|
||||
GifFileOut->SColorMap = UnionMap;
|
||||
}
|
||||
|
||||
//cppcheck-suppress nullPointerRedundantCheck
|
||||
for (CopyFrom = Inclusion->SavedImages;
|
||||
//cppcheck-suppress nullPointerRedundantCheck
|
||||
CopyFrom < Inclusion->SavedImages + Inclusion->ImageCount;
|
||||
CopyFrom++)
|
||||
{
|
||||
SavedImage *NewImage;
|
||||
if ((NewImage = GifMakeSavedImage(GifFileOut, CopyFrom)) == NULL)
|
||||
{
|
||||
PARSE_ERROR("Inclusion failed --- out of memory.");
|
||||
//cppcheck-suppress nullPointerRedundantCheck
|
||||
PrintGifError(GifFileOut->Error);
|
||||
if (Inclusion != NULL) DGifCloseFile(Inclusion, NULL);
|
||||
if (GifFileOut != NULL) EGifCloseFile(GifFileOut, NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (DoTranslation)
|
||||
GifApplyTranslation(NewImage, Translation);
|
||||
|
||||
GifQprintf(
|
||||
"%s: Image %d at (%d, %d) [%dx%d]: from %s\n",
|
||||
PROGRAM_NAME, GifFileOut->ImageCount,
|
||||
NewImage->ImageDesc.Left, NewImage->ImageDesc.Top,
|
||||
NewImage->ImageDesc.Width, NewImage->ImageDesc.Height,
|
||||
InclusionFile);
|
||||
}
|
||||
|
||||
(void) DGifCloseFile(Inclusion, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extension blocks.
|
||||
*/
|
||||
else if (strcmp(buf, "comment\n") == 0)
|
||||
{
|
||||
int bc = 0;
|
||||
while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
|
||||
if (strcmp(buf, "end\n") == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
int Len;
|
||||
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
Len = EscapeString(buf, buf);
|
||||
if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
|
||||
&LeadingExtensionBlocks,
|
||||
bc++ == CONTINUE_EXT_FUNC_CODE ? COMMENT_EXT_FUNC_CODE : 0,
|
||||
Len,
|
||||
(unsigned char *)buf) == GIF_ERROR) {
|
||||
PARSE_ERROR("out of memory while adding comment block.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp(buf, "plaintext\n") == 0)
|
||||
{
|
||||
int bc = 0;
|
||||
while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
|
||||
if (strcmp(buf, "end\n") == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
int Len;
|
||||
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
Len = EscapeString(buf, buf);
|
||||
if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
|
||||
&LeadingExtensionBlocks,
|
||||
bc++ == CONTINUE_EXT_FUNC_CODE ? PLAINTEXT_EXT_FUNC_CODE : 0,
|
||||
Len,
|
||||
(unsigned char *)buf) == GIF_ERROR) {
|
||||
PARSE_ERROR("out of memory while adding plaintext block.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strcmp(buf, "graphics control\n") == 0)
|
||||
{
|
||||
GraphicsControlBlock gcb;
|
||||
size_t Len;
|
||||
|
||||
memset(&gcb, '\0', sizeof(gcb));
|
||||
gcb.TransparentColor = NO_TRANSPARENT_COLOR;
|
||||
while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
|
||||
if (strcmp(buf, "end\n") == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
char *tp = buf;
|
||||
|
||||
while (isspace(*tp))
|
||||
tp++;
|
||||
if (sscanf(tp, "disposal mode %d\n", &gcb.DisposalMode))
|
||||
continue;
|
||||
if (strcmp(tp, "user input flag on\n") == 0) {
|
||||
gcb.UserInputFlag = true;
|
||||
continue;
|
||||
}
|
||||
if (strcmp(tp, "user input flag off\n") == 0) {
|
||||
gcb.UserInputFlag = false;
|
||||
continue;
|
||||
}
|
||||
if (sscanf(tp, "delay %d\n", &gcb.DelayTime))
|
||||
continue;
|
||||
if (sscanf(tp, "transparent index %d\n",
|
||||
&gcb.TransparentColor))
|
||||
continue;
|
||||
(void) fputs(tp, stderr);
|
||||
PARSE_ERROR("unrecognized directive in GCB block.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
Len = EGifGCBToExtension(&gcb, (GifByteType *)buf);
|
||||
if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
|
||||
&LeadingExtensionBlocks,
|
||||
GRAPHICS_EXT_FUNC_CODE,
|
||||
Len,
|
||||
(unsigned char *)buf) == GIF_ERROR) {
|
||||
PARSE_ERROR("out of memory while adding GCB.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
else if (sscanf(buf, "netscape loop %u", &intval))
|
||||
{
|
||||
unsigned char params[3] = {1, 0, 0};
|
||||
/* Create a Netscape 2.0 loop block */
|
||||
if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
|
||||
&LeadingExtensionBlocks,
|
||||
APPLICATION_EXT_FUNC_CODE,
|
||||
11,
|
||||
(unsigned char *)"NETSCAPE2.0")==GIF_ERROR) {
|
||||
PARSE_ERROR("out of memory while adding loop block.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
params[1] = (intval & 0xff);
|
||||
params[2] = (intval >> 8) & 0xff;
|
||||
if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
|
||||
&LeadingExtensionBlocks,
|
||||
0, sizeof(params), params) == GIF_ERROR) {
|
||||
PARSE_ERROR("out of memory while adding loop continuation.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
}
|
||||
else if (sscanf(buf, "extension %x", &ExtCode))
|
||||
{
|
||||
int bc = 0;
|
||||
while (fgets(buf, sizeof(buf), txtin) != (char *)NULL)
|
||||
if (strcmp(buf, "end\n") == 0)
|
||||
break;
|
||||
else
|
||||
{
|
||||
int Len;
|
||||
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
Len = EscapeString(buf, buf);
|
||||
if (GifAddExtensionBlock(&LeadingExtensionBlockCount,
|
||||
&LeadingExtensionBlocks,
|
||||
bc++ == CONTINUE_EXT_FUNC_CODE ? ExtCode : 0,
|
||||
Len,
|
||||
(unsigned char *)buf) == GIF_ERROR) {
|
||||
PARSE_ERROR("out of memory while adding extension block.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Explicit image declarations
|
||||
*/
|
||||
|
||||
else if (strcmp(buf, "image\n") == 0)
|
||||
{
|
||||
if ((NewImage = GifMakeSavedImage(GifFileOut, NULL)) == (SavedImage *)NULL)
|
||||
{
|
||||
PARSE_ERROR("Out of memory while allocating image block.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* use global table unless user specifies a local one */
|
||||
ColorMap = GlobalColorMap;
|
||||
KeyTable = GlobalColorKeys;
|
||||
|
||||
/* connect leading extension blocks */
|
||||
NewImage->ExtensionBlockCount = LeadingExtensionBlockCount;
|
||||
NewImage->ExtensionBlocks = LeadingExtensionBlocks;
|
||||
LeadingExtensionBlockCount = 0;
|
||||
LeadingExtensionBlocks = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Nothing past this point is valid unless we've seen a previous
|
||||
* image declaration.
|
||||
*/
|
||||
else if (NewImage == (SavedImage *)NULL)
|
||||
{
|
||||
(void) fputs(buf, stderr);
|
||||
PARSE_ERROR("Syntax error in header block.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept image attributes
|
||||
*/
|
||||
else if (sscanf(buf, "image top %d\n", &NewImage->ImageDesc.Top) == 1)
|
||||
continue;
|
||||
|
||||
else if (sscanf(buf, "image left %d\n", &NewImage->ImageDesc.Left)== 1)
|
||||
continue;
|
||||
|
||||
else if (strcmp(buf, "image interlaced\n") == 0)
|
||||
{
|
||||
NewImage->ImageDesc.Interlace = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (sscanf(buf,
|
||||
"image bits %d by %d",
|
||||
&NewImage->ImageDesc.Width,
|
||||
&NewImage->ImageDesc.Height) == 2)
|
||||
{
|
||||
int i, j;
|
||||
static GifPixelType *Raster, *cp;
|
||||
int c;
|
||||
bool hex = (strstr(buf, "hex") != NULL);
|
||||
|
||||
/* coverity[overflow_sink] */
|
||||
if ((Raster = (GifPixelType *) malloc(sizeof(GifPixelType) * NewImage->ImageDesc.Width * NewImage->ImageDesc.Height))
|
||||
== NULL) {
|
||||
PARSE_ERROR("Failed to allocate raster block, aborted.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
GifQprintf("%s: Image %d at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, GifFileOut->ImageCount,
|
||||
NewImage->ImageDesc.Left, NewImage->ImageDesc.Top,
|
||||
NewImage->ImageDesc.Width, NewImage->ImageDesc.Height);
|
||||
|
||||
cp = Raster;
|
||||
for (i = 0; i < NewImage->ImageDesc.Height; i++) {
|
||||
|
||||
char *dp;
|
||||
|
||||
for (j = 0; j < NewImage->ImageDesc.Width; j++)
|
||||
if ((c = fgetc(txtin)) == EOF) {
|
||||
PARSE_ERROR("input file ended prematurely.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else if (c == '\n')
|
||||
{
|
||||
--j;
|
||||
++LineNum;
|
||||
}
|
||||
else if (isspace(c))
|
||||
--j;
|
||||
else if (hex)
|
||||
{
|
||||
const static char *hexdigits = "0123456789ABCDEF";
|
||||
unsigned char hi, lo;
|
||||
dp = strchr(hexdigits, toupper(c));
|
||||
if (dp == NULL) {
|
||||
PARSE_ERROR("Invalid hex high byte.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
hi = (dp - hexdigits);
|
||||
if ((c = fgetc(txtin)) == EOF) {
|
||||
PARSE_ERROR("input file ended prematurely.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
dp = strchr(hexdigits, toupper(c));
|
||||
if (dp == NULL) {
|
||||
PARSE_ERROR("Invalid hex low byte.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
lo = (dp - hexdigits);
|
||||
*cp++ = (hi << 4) | lo;
|
||||
}
|
||||
else if ((dp = strchr(KeyTable, c)))
|
||||
*cp++ = (dp - KeyTable);
|
||||
else {
|
||||
PARSE_ERROR("Invalid ASCII pixel key.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (GifNoisyPrint)
|
||||
fprintf(stderr, "\b\b\b\b%-4d", i);
|
||||
}
|
||||
|
||||
if (GifNoisyPrint)
|
||||
putc('\n', stderr);
|
||||
|
||||
NewImage->RasterBits = (unsigned char *) Raster;
|
||||
}
|
||||
else
|
||||
{
|
||||
(void) fputs(buf, stderr);
|
||||
PARSE_ERROR("Syntax error in image description.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* connect trailing extension blocks */
|
||||
GifFileOut->ExtensionBlockCount = LeadingExtensionBlockCount;
|
||||
GifFileOut->ExtensionBlocks = LeadingExtensionBlocks;
|
||||
//LeadingExtensionBlockCount = 0;
|
||||
LeadingExtensionBlocks = NULL;
|
||||
|
||||
EGifSpew(GifFileOut);
|
||||
}
|
||||
|
||||
static void VisibleDumpBuffer(GifByteType *buf, int len)
|
||||
/* Visibilize a given string */
|
||||
{
|
||||
GifByteType *cp;
|
||||
|
||||
for (cp = buf; cp < buf + len; cp++)
|
||||
{
|
||||
if (isprint((int)(*cp)) || *cp == ' ')
|
||||
putchar(*cp);
|
||||
else if (*cp == '\n')
|
||||
{
|
||||
putchar('\\'); putchar('n');
|
||||
}
|
||||
else if (*cp == '\r')
|
||||
{
|
||||
putchar('\\'); putchar('r');
|
||||
}
|
||||
else if (*cp == '\b')
|
||||
{
|
||||
putchar('\\'); putchar('b');
|
||||
}
|
||||
else if (*cp < ' ')
|
||||
{
|
||||
putchar('\\'); putchar('^'); putchar('@' + *cp);
|
||||
}
|
||||
else
|
||||
printf("\\0x%02x", *cp);
|
||||
}
|
||||
}
|
||||
|
||||
static void DumpExtensions(GifFileType *GifFileOut,
|
||||
int ExtensionBlockCount,
|
||||
ExtensionBlock *ExtensionBlocks)
|
||||
{
|
||||
ExtensionBlock *ep;
|
||||
|
||||
for (ep = ExtensionBlocks;
|
||||
ep < ExtensionBlocks + ExtensionBlockCount;
|
||||
ep++) {
|
||||
bool last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
|
||||
if (ep->Function == COMMENT_EXT_FUNC_CODE) {
|
||||
printf("comment\n");
|
||||
VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
|
||||
putchar('\n');
|
||||
while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) {
|
||||
++ep;
|
||||
last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
|
||||
VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
|
||||
putchar('\n');
|
||||
}
|
||||
printf("end\n\n");
|
||||
}
|
||||
else if (ep->Function == PLAINTEXT_EXT_FUNC_CODE) {
|
||||
printf("plaintext\n");
|
||||
VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
|
||||
putchar('\n');
|
||||
while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) {
|
||||
++ep;
|
||||
last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
|
||||
VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
|
||||
putchar('\n');
|
||||
}
|
||||
printf("end\n\n");
|
||||
}
|
||||
else if (ep->Function == GRAPHICS_EXT_FUNC_CODE)
|
||||
{
|
||||
GraphicsControlBlock gcb;
|
||||
printf("graphics control\n");
|
||||
if (DGifExtensionToGCB(ep->ByteCount, ep->Bytes, &gcb) == GIF_ERROR) {
|
||||
GIF_MESSAGE("invalid graphics control block");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("\tdisposal mode %d\n", gcb.DisposalMode);
|
||||
printf("\tuser input flag %s\n",
|
||||
gcb.UserInputFlag ? "on" : "off");
|
||||
printf("\tdelay %d\n", gcb.DelayTime);
|
||||
printf("\ttransparent index %d\n", gcb.TransparentColor);
|
||||
printf("end\n\n");
|
||||
}
|
||||
else if (!last
|
||||
&& ep->Function == APPLICATION_EXT_FUNC_CODE
|
||||
&& ep->ByteCount >= 11
|
||||
&& (ep+1)->ByteCount >= 3
|
||||
&& memcmp(ep->Bytes, "NETSCAPE2.0", 11) == 0) {
|
||||
unsigned char *params = (++ep)->Bytes;
|
||||
unsigned int loopcount = params[1] | (params[2] << 8);
|
||||
printf("netscape loop %u\n\n", loopcount);
|
||||
}
|
||||
else {
|
||||
printf("extension 0x%02x\n", ep->Function);
|
||||
VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
|
||||
while (!last && ep[1].Function == CONTINUE_EXT_FUNC_CODE) {
|
||||
++ep;
|
||||
last = (ep - ExtensionBlocks == (ExtensionBlockCount - 1));
|
||||
VisibleDumpBuffer(ep->Bytes, ep->ByteCount);
|
||||
putchar('\n');
|
||||
}
|
||||
printf("end\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Gif2Icon(char *FileName,
|
||||
int fdin, int fdout,
|
||||
char NameTable[])
|
||||
{
|
||||
int ErrorCode, im, i, j, ColorCount = 0;
|
||||
GifFileType *GifFile;
|
||||
|
||||
if (fdin == -1) {
|
||||
if ((GifFile = DGifOpenFileName(FileName, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Use stdin instead: */
|
||||
if ((GifFile = DGifOpenFileHandle(fdin, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (DGifSlurp(GifFile) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("screen width %d\nscreen height %d\n",
|
||||
GifFile->SWidth, GifFile->SHeight);
|
||||
|
||||
printf("screen colors %d\nscreen background %d\npixel aspect byte %u\n\n",
|
||||
1 << GifFile->SColorResolution,
|
||||
GifFile->SBackGroundColor,
|
||||
(unsigned)GifFile->AspectByte);
|
||||
|
||||
if (GifFile->SColorMap)
|
||||
{
|
||||
printf("screen map\n");
|
||||
|
||||
printf("\tsort flag %s\n", GifFile->SColorMap->SortFlag ? "on" : "off");
|
||||
|
||||
for (i = 0; i < GifFile->SColorMap->ColorCount; i++)
|
||||
if (GifFile->SColorMap->ColorCount < PRINTABLES)
|
||||
printf("\trgb %03d %03d %03d is %c\n",
|
||||
GifFile->SColorMap ->Colors[i].Red,
|
||||
GifFile->SColorMap ->Colors[i].Green,
|
||||
GifFile->SColorMap ->Colors[i].Blue,
|
||||
NameTable[i]);
|
||||
else
|
||||
printf("\trgb %03d %03d %03d\n",
|
||||
GifFile->SColorMap ->Colors[i].Red,
|
||||
GifFile->SColorMap ->Colors[i].Green,
|
||||
GifFile->SColorMap ->Colors[i].Blue);
|
||||
printf("end\n\n");
|
||||
}
|
||||
|
||||
for (im = 0; im < GifFile->ImageCount; im++) {
|
||||
SavedImage *image = &GifFile->SavedImages[im];
|
||||
|
||||
DumpExtensions(GifFile,
|
||||
image->ExtensionBlockCount, image->ExtensionBlocks);
|
||||
|
||||
printf("image # %d\nimage left %d\nimage top %d\n",
|
||||
im+1, image->ImageDesc.Left, image->ImageDesc.Top);
|
||||
if (image->ImageDesc.Interlace)
|
||||
printf("image interlaced\n");
|
||||
|
||||
if (image->ImageDesc.ColorMap)
|
||||
{
|
||||
printf("image map\n");
|
||||
|
||||
printf("\tsort flag %s\n",
|
||||
image->ImageDesc.ColorMap->SortFlag ? "on" : "off");
|
||||
|
||||
if (image->ImageDesc.ColorMap->ColorCount < PRINTABLES)
|
||||
for (i = 0; i < image->ImageDesc.ColorMap->ColorCount; i++)
|
||||
printf("\trgb %03d %03d %03d is %c\n",
|
||||
image->ImageDesc.ColorMap ->Colors[i].Red,
|
||||
image->ImageDesc.ColorMap ->Colors[i].Green,
|
||||
image->ImageDesc.ColorMap ->Colors[i].Blue,
|
||||
NameTable[i]);
|
||||
else
|
||||
for (i = 0; i < image->ImageDesc.ColorMap->ColorCount; i++)
|
||||
printf("\trgb %03d %03d %03d\n",
|
||||
image->ImageDesc.ColorMap ->Colors[i].Red,
|
||||
image->ImageDesc.ColorMap ->Colors[i].Green,
|
||||
image->ImageDesc.ColorMap ->Colors[i].Blue);
|
||||
printf("end\n\n");
|
||||
}
|
||||
|
||||
/* one of these conditions has to be true */
|
||||
if (image->ImageDesc.ColorMap)
|
||||
ColorCount = image->ImageDesc.ColorMap->ColorCount;
|
||||
else if (GifFile->SColorMap)
|
||||
ColorCount = GifFile->SColorMap->ColorCount;
|
||||
|
||||
if (ColorCount < PRINTABLES)
|
||||
printf("image bits %d by %d\n",
|
||||
image->ImageDesc.Width, image->ImageDesc.Height);
|
||||
else
|
||||
printf("image bits %d by %d hex\n",
|
||||
image->ImageDesc.Width, image->ImageDesc.Height);
|
||||
for (i = 0; i < image->ImageDesc.Height; i++) {
|
||||
for (j = 0; j < image->ImageDesc.Width; j++) {
|
||||
GifByteType ch = image->RasterBits[i*image->ImageDesc.Width + j];
|
||||
if (ColorCount < PRINTABLES && ch < PRINTABLES)
|
||||
putchar(NameTable[ch]);
|
||||
else
|
||||
printf("%02x", ch);
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
|
||||
DumpExtensions(GifFile,
|
||||
GifFile->ExtensionBlockCount, GifFile->ExtensionBlocks);
|
||||
|
||||
/* Tell EMACS this is a picture... */
|
||||
printf("# The following sets edit modes for GNU EMACS\n");
|
||||
printf("# Local "); /* ...break this up, so that EMACS doesn't */
|
||||
printf("Variables:\n"); /* get confused when visiting *this* file! */
|
||||
printf("# mode:picture\n");
|
||||
printf("# truncate-lines:t\n");
|
||||
printf("# End:\n");
|
||||
|
||||
if (fdin == -1)
|
||||
(void) printf("# End of %s dump\n", FileName);
|
||||
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
|
||||
/* check that the background color isn't garbage (SF bug #87) */
|
||||
if (GifFile->SBackGroundColor < 0
|
||||
|| (GifFile->SColorMap && GifFile->SBackGroundColor >= GifFile->SColorMap->ColorCount)) {
|
||||
fprintf(stderr, "gifbuild: background color invalid for screen colormap.\n");
|
||||
}
|
||||
|
||||
if (DGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static int EscapeString(char *cp, char *tp)
|
||||
/* process standard C-style escape sequences in a string */
|
||||
{
|
||||
char *StartAddr = tp;
|
||||
|
||||
while (*cp)
|
||||
{
|
||||
int cval = 0;
|
||||
|
||||
if (*cp == '\\' && strchr("0123456789xX", cp[1]))
|
||||
{
|
||||
int dcount = 0;
|
||||
|
||||
if (*++cp == 'x' || *cp == 'X') {
|
||||
char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
|
||||
for (++cp; (dp = strchr(hex, *cp)) && (dcount++ < 2); cp++)
|
||||
cval = (cval * 16) + (dp - hex) / 2;
|
||||
} else if (*cp == '0')
|
||||
while (strchr("01234567",*cp) != (char*)NULL && (dcount++ < 3))
|
||||
cval = (cval * 8) + (*cp++ - '0');
|
||||
else
|
||||
while ((strchr("0123456789",*cp)!=(char*)NULL)&&(dcount++ < 3))
|
||||
cval = (cval * 10) + (*cp++ - '0');
|
||||
}
|
||||
else if (*cp == '\\') /* C-style character escapes */
|
||||
{
|
||||
switch (*++cp)
|
||||
{
|
||||
case '\\': cval = '\\'; break;
|
||||
case 'n': cval = '\n'; break;
|
||||
case 't': cval = '\t'; break;
|
||||
case 'b': cval = '\b'; break;
|
||||
case 'r': cval = '\r'; break;
|
||||
default: cval = *cp;
|
||||
}
|
||||
cp++;
|
||||
}
|
||||
else if (*cp == '^') /* expand control-character syntax */
|
||||
{
|
||||
cval = (*++cp & 0x1f);
|
||||
cp++;
|
||||
}
|
||||
else
|
||||
cval = *cp++;
|
||||
*tp++ = cval;
|
||||
}
|
||||
|
||||
return(tp - StartAddr);
|
||||
}
|
||||
|
||||
/* end */
|
||||
|
|
@ -0,0 +1,361 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifclrmap - extract colormaps from GIF images
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifclrmp"
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- s%- t%-TranslationFile!s l%-ColorMapFile!s g%-Gamma!F i%-Image#!d h%- GifFile!*s";
|
||||
|
||||
static bool
|
||||
SaveFlag = false,
|
||||
TranslateFlag = false,
|
||||
LoadFlag = false,
|
||||
GammaFlag = false;
|
||||
static
|
||||
double Gamma = 1.0;
|
||||
static
|
||||
FILE *ColorFile = NULL;
|
||||
FILE *TranslateFile = NULL;
|
||||
static
|
||||
GifPixelType Translation[256];
|
||||
|
||||
static ColorMapObject *ModifyColorMap(ColorMapObject *ColorMap);
|
||||
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut);
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and scan the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int NumFiles, ExtCode, CodeSize, ImageNum = 0,
|
||||
ImageN, HasGIFOutput, ErrorCode;
|
||||
bool Error, ImageNFlag = false, HelpFlag = false;
|
||||
GifRecordType RecordType;
|
||||
GifByteType *Extension, *CodeBlock;
|
||||
char **FileName = NULL, *ColorFileName, *TranslateFileName;
|
||||
GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint, &SaveFlag,
|
||||
&TranslateFlag, &TranslateFileName,
|
||||
&LoadFlag, &ColorFileName,
|
||||
&GammaFlag, &Gamma, &ImageNFlag, &ImageN,
|
||||
&HelpFlag, &NumFiles, &FileName)) != false ||
|
||||
(NumFiles > 1 && !HelpFlag)) {
|
||||
if (Error)
|
||||
GAPrintErrMsg(Error);
|
||||
else if (NumFiles > 1)
|
||||
GIF_MESSAGE("Error in command line parsing - one GIF file please.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (SaveFlag + LoadFlag + GammaFlag + TranslateFlag > 1)
|
||||
GIF_EXIT("Can not handle more than one of -s -l, -t, or -g at the same time.");
|
||||
|
||||
/* Default action is to dump colormaps */
|
||||
if (!SaveFlag && !LoadFlag && !GammaFlag && !TranslateFlag)
|
||||
SaveFlag = true;
|
||||
|
||||
if (NumFiles == 1) {
|
||||
if ((GifFileIn = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Use stdin instead: */
|
||||
if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (SaveFlag) {
|
||||
/* We are dumping out the color map as text file to stdout: */
|
||||
ColorFile = stdout;
|
||||
}
|
||||
else {
|
||||
if (TranslateFlag) {
|
||||
/* We are loading new color map from specified file: */
|
||||
if ((TranslateFile = fopen(TranslateFileName, "rt")) == NULL)
|
||||
GIF_EXIT("Failed to open specified color translation file.");
|
||||
}
|
||||
|
||||
if (LoadFlag) {
|
||||
/* We are loading new color map from specified file: */
|
||||
if ((ColorFile = fopen(ColorFileName, "rt")) == NULL)
|
||||
GIF_EXIT("Failed to open specified color map file.");
|
||||
}
|
||||
}
|
||||
|
||||
if ((HasGIFOutput = (LoadFlag || TranslateFlag || GammaFlag)) != 0) {
|
||||
/* Open stdout for GIF output file: */
|
||||
if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ImageNFlag) {
|
||||
/* We are supposed to modify the screen color map, so do it: */
|
||||
if (!GifFileIn->SColorMap)
|
||||
GIF_EXIT("No colormap to modify");
|
||||
GifFileIn->SColorMap = ModifyColorMap(GifFileIn->SColorMap);
|
||||
if (!HasGIFOutput) {
|
||||
/* We can quit here, as we have the color map: */
|
||||
DGifCloseFile(GifFileIn, NULL);
|
||||
fclose(ColorFile);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
/* And dump out its new possible repositioned screen information: */
|
||||
if (HasGIFOutput)
|
||||
if (EGifPutScreenDesc(GifFileOut,
|
||||
GifFileIn->SWidth, GifFileIn->SHeight,
|
||||
GifFileIn->SColorResolution, GifFileIn->SBackGroundColor,
|
||||
GifFileIn->SColorMap) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
/* Scan the content of the GIF file and load the image(s) in: */
|
||||
do {
|
||||
if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
switch (RecordType) {
|
||||
case IMAGE_DESC_RECORD_TYPE:
|
||||
if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if ((++ImageNum == ImageN) && ImageNFlag) {
|
||||
/* We are suppose to modify this image color map, do it: */
|
||||
GifFileIn->SColorMap =ModifyColorMap(GifFileIn->SColorMap);
|
||||
if (!HasGIFOutput) {
|
||||
/* We can quit here, as we have the color map: */
|
||||
DGifCloseFile(GifFileIn, NULL);
|
||||
fclose(ColorFile);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
if (HasGIFOutput)
|
||||
if (EGifPutImageDesc(GifFileOut,
|
||||
GifFileIn->Image.Left, GifFileIn->Image.Top,
|
||||
GifFileIn->Image.Width, GifFileIn->Image.Height,
|
||||
GifFileIn->Image.Interlace,
|
||||
GifFileIn->Image.ColorMap) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
if (!TranslateFlag || (ImageNFlag && (ImageN != ImageNum)))
|
||||
{
|
||||
/* Now read image itself in decoded form as we don't */
|
||||
/* really care what we have there, and this is much */
|
||||
/* faster. */
|
||||
if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (HasGIFOutput)
|
||||
if (EGifPutCode(GifFileOut, CodeSize, CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
while (CodeBlock != NULL) {
|
||||
if (DGifGetCodeNext(GifFileIn, &CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (HasGIFOutput)
|
||||
if (EGifPutCodeNext(GifFileOut, CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
}
|
||||
else /* we need to mung pixels intices */
|
||||
{
|
||||
int i;
|
||||
register GifPixelType *cp;
|
||||
|
||||
GifPixelType *Line
|
||||
= (GifPixelType *) malloc(GifFileIn->Image.Width *
|
||||
sizeof(GifPixelType));
|
||||
for (i = 0; i < GifFileIn->Image.Height; i++) {
|
||||
if (DGifGetLine(GifFileIn, Line,GifFileIn->Image.Width)
|
||||
== GIF_ERROR) {
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
|
||||
/* translation step goes here */
|
||||
for (cp = Line; cp < Line+GifFileIn->Image.Width; cp++)
|
||||
*cp = Translation[*cp];
|
||||
|
||||
if (EGifPutLine(GifFileOut,
|
||||
Line, GifFileIn->Image.Width)
|
||||
== GIF_ERROR) {
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
}
|
||||
free((char *) Line);
|
||||
}
|
||||
break;
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
assert(GifFileOut != NULL); /* might pacify Coverity */
|
||||
/* pass through extension records */
|
||||
if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (Extension == NULL)
|
||||
break;
|
||||
if (EGifPutExtensionLeader(GifFileOut, ExtCode) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (EGifPutExtensionBlock(GifFileOut,
|
||||
Extension[0],
|
||||
Extension + 1) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
while (Extension != NULL) {
|
||||
if (DGifGetExtensionNext(GifFileIn, &Extension)==GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (Extension != NULL)
|
||||
if (EGifPutExtensionBlock(GifFileOut,
|
||||
Extension[0],
|
||||
Extension + 1) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
break;
|
||||
case TERMINATE_RECORD_TYPE:
|
||||
break;
|
||||
default: /* Should be trapped by DGifGetRecordType. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (RecordType != TERMINATE_RECORD_TYPE);
|
||||
|
||||
if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (HasGIFOutput)
|
||||
if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Modify the given colormap according to global variables setting.
|
||||
******************************************************************************/
|
||||
static ColorMapObject *ModifyColorMap(ColorMapObject *ColorMap)
|
||||
{
|
||||
int i, Dummy, Red, Green, Blue;
|
||||
|
||||
if (SaveFlag) {
|
||||
/* Save this color map to ColorFile: */
|
||||
for (i = 0; i < ColorMap->ColorCount; i++)
|
||||
fprintf(ColorFile, "%3d %3d %3d %3d\n", i,
|
||||
ColorMap->Colors[i].Red,
|
||||
ColorMap->Colors[i].Green,
|
||||
ColorMap->Colors[i].Blue);
|
||||
return(ColorMap);
|
||||
}
|
||||
else if (LoadFlag) {
|
||||
/* Read the color map in ColorFile into this color map: */
|
||||
for (i = 0; i < ColorMap->ColorCount; i++) {
|
||||
if (feof(ColorFile))
|
||||
GIF_EXIT("Color file to load color map from, too small.");
|
||||
if (fscanf(ColorFile, "%3d %3d %3d %3d\n", &Dummy, &Red, &Green, &Blue) == 4) {
|
||||
ColorMap->Colors[i].Red = Red;
|
||||
ColorMap->Colors[i].Green = Green;
|
||||
ColorMap->Colors[i].Blue = Blue;
|
||||
}
|
||||
}
|
||||
return(ColorMap);
|
||||
}
|
||||
else if (GammaFlag) {
|
||||
/* Apply gamma correction to this color map: */
|
||||
double Gamma1 = 1.0 / Gamma;
|
||||
for (i = 0; i < ColorMap->ColorCount; i++) {
|
||||
ColorMap->Colors[i].Red =
|
||||
((int) (255 * pow(ColorMap->Colors[i].Red / 255.0, Gamma1)));
|
||||
ColorMap->Colors[i].Green =
|
||||
((int) (255 * pow(ColorMap->Colors[i].Green / 255.0, Gamma1)));
|
||||
ColorMap->Colors[i].Blue =
|
||||
((int) (255 * pow(ColorMap->Colors[i].Blue / 255.0, Gamma1)));
|
||||
}
|
||||
return(ColorMap);
|
||||
}
|
||||
else if (TranslateFlag) {
|
||||
ColorMapObject *NewMap;
|
||||
int Max = 0;
|
||||
|
||||
/* Read the translation table in TranslateFile: */
|
||||
for (i = 0; i < ColorMap->ColorCount; i++) {
|
||||
int tmp;
|
||||
if (feof(TranslateFile))
|
||||
GIF_EXIT("Color file to load color map from, too small.");
|
||||
if (fscanf(TranslateFile, "%3d %3d\n", &Dummy, &tmp) == 2) {
|
||||
Translation[i] = tmp & 0xff;
|
||||
if (Translation[i] > Max)
|
||||
Max = Translation[i];
|
||||
}
|
||||
}
|
||||
|
||||
if ((NewMap = GifMakeMapObject(1 << GifBitSize(Max+1), NULL)) == NULL)
|
||||
GIF_EXIT("Out of memory while allocating color map!");
|
||||
|
||||
/* Apply the translation; we'll do it to the pixels, too */
|
||||
for (i = 0; i < ColorMap->ColorCount; i++) {
|
||||
NewMap->Colors[i] = ColorMap->Colors[Translation[i]];
|
||||
}
|
||||
|
||||
return(NewMap);
|
||||
}
|
||||
else
|
||||
{
|
||||
GIF_EXIT("Nothing to do!");
|
||||
return(ColorMap);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Close both input and output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
|
||||
{
|
||||
if (GifFileIn != NULL) {
|
||||
PrintGifError(GifFileIn->Error);
|
||||
EGifCloseFile(GifFileIn, NULL);
|
||||
}
|
||||
if (GifFileOut != NULL) {
|
||||
PrintGifError(GifFileOut->Error);
|
||||
EGifCloseFile(GifFileOut, NULL);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,170 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifcolor - generate color test-pattern GIFs
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifcolor"
|
||||
|
||||
#define LINE_LEN 40
|
||||
#define IMAGEWIDTH LINE_LEN*GIF_FONT_WIDTH
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr = PROGRAM_NAME " v%- b%-Background!d h%-";
|
||||
|
||||
static int BackGround = 0;
|
||||
static void QuitGifError(GifFileType *GifFile);
|
||||
static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
|
||||
int BufferWidth, int ForeGroundIndex);
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and generate the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, l, GifNoisyPrint, ColorMapSize, ErrorCode;
|
||||
bool Error, BackGroundFlag = false, HelpFlag = false;
|
||||
char Line[LINE_LEN];
|
||||
GifRowType RasterBuffer[GIF_FONT_HEIGHT];
|
||||
ColorMapObject *ColorMap;
|
||||
GifFileType *GifFile;
|
||||
GifColorType ScratchMap[256];
|
||||
int red, green, blue;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr,
|
||||
&GifNoisyPrint,
|
||||
&BackGroundFlag, &BackGround,
|
||||
&HelpFlag)) != false) {
|
||||
GAPrintErrMsg(Error);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Allocate the raster buffer for GIF_FONT_HEIGHT scan lines. */
|
||||
for (i = 0; i < GIF_FONT_HEIGHT; i++)
|
||||
{
|
||||
if ((RasterBuffer[i] = (GifRowType) malloc(sizeof(GifPixelType) *
|
||||
IMAGEWIDTH)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
}
|
||||
|
||||
/* Open stdout for the output file: */
|
||||
if ((GifFile = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Read the color map in ColorFile into this color map: */
|
||||
ColorMapSize = 0;
|
||||
while (fscanf(stdin,
|
||||
"%*3d %3d %3d %3d\n",
|
||||
&red, &green, &blue) == 3) {
|
||||
if (ColorMapSize < 256) {
|
||||
ScratchMap[ColorMapSize].Red = red;
|
||||
ScratchMap[ColorMapSize].Green = green;
|
||||
ScratchMap[ColorMapSize].Blue = blue;
|
||||
ColorMapSize++;
|
||||
} else {
|
||||
GIF_EXIT("Too many color map triples, aborting.");
|
||||
}
|
||||
}
|
||||
|
||||
if ((ColorMap = GifMakeMapObject(1 << GifBitSize(ColorMapSize), ScratchMap)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
if (EGifPutScreenDesc(GifFile,
|
||||
IMAGEWIDTH, ColorMapSize * GIF_FONT_HEIGHT,
|
||||
GifBitSize(ColorMapSize),
|
||||
BackGround, ColorMap) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
|
||||
/* Dump out the image descriptor: */
|
||||
if (EGifPutImageDesc(GifFile,
|
||||
0, 0, IMAGEWIDTH, ColorMapSize * GIF_FONT_HEIGHT, false, NULL) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
|
||||
GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
|
||||
GifFile->Image.Width, GifFile->Image.Height);
|
||||
|
||||
for (i = l = 0; i < ColorMap->ColorCount; i++) {
|
||||
(void)snprintf(Line, sizeof(Line),
|
||||
"Color %-3d: [%-3d, %-3d, %-3d] ", i,
|
||||
ColorMap->Colors[i].Red,
|
||||
ColorMap->Colors[i].Green,
|
||||
ColorMap->Colors[i].Blue);
|
||||
GenRasterTextLine(RasterBuffer, Line, IMAGEWIDTH, i);
|
||||
for (j = 0; j < GIF_FONT_HEIGHT; j++) {
|
||||
if (EGifPutLine(GifFile, RasterBuffer[j], IMAGEWIDTH) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
GifQprintf("\b\b\b\b%-4d", l++);
|
||||
}
|
||||
}
|
||||
|
||||
if (EGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Close output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
|
||||
int BufferWidth, int ForeGroundIndex)
|
||||
{
|
||||
unsigned char Byte, Mask;
|
||||
int i, j, k, CharPosX, Len = strlen(TextLine);
|
||||
|
||||
for (i = 0; i < BufferWidth; i++)
|
||||
for (j = 0; j < GIF_FONT_HEIGHT; j++) RasterBuffer[j][i] = BackGround;
|
||||
|
||||
for (i = CharPosX = 0; i < Len; i++, CharPosX += GIF_FONT_WIDTH) {
|
||||
unsigned char c = TextLine[i];
|
||||
for (j = 0; j < GIF_FONT_HEIGHT; j++) {
|
||||
Byte = GifAsciiTable8x8[(unsigned short)c][j];
|
||||
for (k = 0, Mask = 128; k < GIF_FONT_WIDTH; k++, Mask >>= 1)
|
||||
if (Byte & Mask)
|
||||
RasterBuffer[j][CharPosX + k] = ForeGroundIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Close output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void QuitGifError(GifFileType *GifFile)
|
||||
{
|
||||
if (GifFile != NULL) {
|
||||
PrintGifError(GifFile->Error);
|
||||
EGifCloseFile(GifFile, NULL);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifecho - generate a GIF from ASCII text
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifecho"
|
||||
|
||||
#define MAX_NUM_TEXT_LINES 100 /* Maximum number of lines in file. */
|
||||
|
||||
#define LINE_LEN 256 /* Maximum length of one text line. */
|
||||
|
||||
#define DEFAULT_FG_INDEX 1 /* Text foreground index. */
|
||||
|
||||
#define DEFAULT_COLOR_RED 255 /* Text foreground color. */
|
||||
#define DEFAULT_COLOR_GREEN 255
|
||||
#define DEFAULT_COLOR_BLUE 255
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- s%-ClrMapSize!d f%-FGClr!d c%-R|G|B!d!d!d t%-\"Text\"!s h%-";
|
||||
|
||||
static unsigned int
|
||||
RedColor = DEFAULT_COLOR_RED,
|
||||
GreenColor = DEFAULT_COLOR_GREEN,
|
||||
BlueColor = DEFAULT_COLOR_BLUE;
|
||||
|
||||
static void QuitGifError(GifFileType *GifFile);
|
||||
static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
|
||||
int BufferWidth, int ForeGroundIndex);
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and generate the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, l, ImageWidth, ImageHeight, NumOfLines, LogNumLevels,
|
||||
ErrorCode, NumLevels, ColorMapSize = 1,
|
||||
ForeGroundIndex = DEFAULT_FG_INDEX;
|
||||
bool Error, ClrMapSizeFlag = false, ForeGroundFlag = false,
|
||||
TextLineFlag = false, HelpFlag = false, ColorFlag = false;
|
||||
char *TextLines[MAX_NUM_TEXT_LINES];
|
||||
GifRowType RasterBuffer[GIF_FONT_HEIGHT];
|
||||
ColorMapObject *ColorMap;
|
||||
GifFileType *GifFile;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr,
|
||||
&GifNoisyPrint, &ClrMapSizeFlag, &ColorMapSize,
|
||||
&ForeGroundFlag, &ForeGroundIndex,
|
||||
&ColorFlag, &RedColor, &GreenColor, &BlueColor,
|
||||
&TextLineFlag, &TextLines[0],
|
||||
&HelpFlag)) != false) {
|
||||
GAPrintErrMsg(Error);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (ForeGroundIndex > 255 || ForeGroundIndex < 1)
|
||||
GIF_EXIT("Foregound (-f) should be in the range 1..255, aborted.");
|
||||
|
||||
if (ColorMapSize > 8 || ColorMapSize < 1)
|
||||
GIF_EXIT("ColorMapSize (-s) should be in the range 1..8, aborted.");
|
||||
|
||||
if (TextLineFlag) {
|
||||
NumOfLines = 1;
|
||||
ImageHeight = GIF_FONT_HEIGHT;
|
||||
ImageWidth = GIF_FONT_WIDTH * strlen(TextLines[0]);
|
||||
}
|
||||
else {
|
||||
char Line[LINE_LEN];
|
||||
NumOfLines = l = 0;
|
||||
while (fgets(Line, LINE_LEN - 1, stdin)) {
|
||||
for (i = strlen(Line); i > 0 && Line[i-1] <= ' '; i--);
|
||||
Line[i] = 0;
|
||||
if (l < i) l = i;
|
||||
TextLines[NumOfLines++] = strdup(Line);
|
||||
if (NumOfLines == MAX_NUM_TEXT_LINES)
|
||||
GIF_EXIT("Input file has too many lines, aborted.");
|
||||
}
|
||||
if (NumOfLines == 0)
|
||||
GIF_EXIT("No input text, aborted.");
|
||||
ImageHeight = GIF_FONT_HEIGHT * NumOfLines;
|
||||
ImageWidth = GIF_FONT_WIDTH * l;
|
||||
}
|
||||
|
||||
/* Allocate the raster buffer for GIF_FONT_HEIGHT scan lines (one text line). */
|
||||
for (i = 0; i < GIF_FONT_HEIGHT; i++)
|
||||
if ((RasterBuffer[i] = (GifRowType) malloc(sizeof(GifPixelType) *
|
||||
ImageWidth)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
/* Open stdout for the output file: */
|
||||
if ((GifFile = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Dump out screen description with given size and generated color map: */
|
||||
for (LogNumLevels = 1, NumLevels = 2;
|
||||
NumLevels < ForeGroundIndex;
|
||||
LogNumLevels++, NumLevels <<= 1);
|
||||
if (NumLevels < (1 << ColorMapSize)) {
|
||||
NumLevels = (1 << ColorMapSize);
|
||||
LogNumLevels = ColorMapSize;
|
||||
}
|
||||
|
||||
if ((ColorMap = GifMakeMapObject(NumLevels, NULL)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
for (i = 0; i < NumLevels; i++)
|
||||
ColorMap->Colors[i].Red = ColorMap->Colors[i].Green = ColorMap->Colors[i].Blue = 0;
|
||||
ColorMap->Colors[ForeGroundIndex].Red = RedColor;
|
||||
ColorMap->Colors[ForeGroundIndex].Green = GreenColor;
|
||||
ColorMap->Colors[ForeGroundIndex].Blue = BlueColor;
|
||||
|
||||
if (EGifPutScreenDesc(GifFile,
|
||||
ImageWidth, ImageHeight, LogNumLevels, 0, ColorMap)
|
||||
== GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
|
||||
/* Dump out the image descriptor: */
|
||||
if (EGifPutImageDesc(GifFile,
|
||||
0, 0, ImageWidth, ImageHeight, false, NULL) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
|
||||
GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
|
||||
GifFile->Image.Width, GifFile->Image.Height);
|
||||
|
||||
for (i = l = 0; i < NumOfLines; i++) {
|
||||
GenRasterTextLine(RasterBuffer, TextLines[i], ImageWidth,
|
||||
ForeGroundIndex);
|
||||
for (j = 0; j < GIF_FONT_HEIGHT; j++) {
|
||||
if (EGifPutLine(GifFile, RasterBuffer[j], ImageWidth) == GIF_ERROR)
|
||||
QuitGifError(GifFile);
|
||||
GifQprintf("\b\b\b\b%-4d", l++);
|
||||
}
|
||||
}
|
||||
|
||||
if (EGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Generate raster bits corresponding to given text
|
||||
******************************************************************************/
|
||||
static void GenRasterTextLine(GifRowType *RasterBuffer, char *TextLine,
|
||||
int BufferWidth, int ForeGroundIndex)
|
||||
{
|
||||
unsigned char Byte, Mask;
|
||||
int i, j, k, CharPosX, Len = strlen(TextLine);
|
||||
|
||||
for (i = 0; i < BufferWidth; i++)
|
||||
for (j = 0; j < GIF_FONT_HEIGHT; j++) RasterBuffer[j][i] = 0;
|
||||
|
||||
for (i = CharPosX = 0; i < Len; i++, CharPosX += GIF_FONT_WIDTH) {
|
||||
unsigned char c = TextLine[i];
|
||||
for (j = 0; j < GIF_FONT_HEIGHT; j++) {
|
||||
Byte = GifAsciiTable8x8[(unsigned short)c][j];
|
||||
for (k = 0, Mask = 128; k < GIF_FONT_WIDTH; k++, Mask >>= 1)
|
||||
if (Byte & Mask)
|
||||
RasterBuffer[j][CharPosX + k] = ForeGroundIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Close output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void QuitGifError(GifFileType *GifFile)
|
||||
{
|
||||
if (GifFile != NULL) {
|
||||
PrintGifError(GifFile->Error);
|
||||
EGifCloseFile(GifFile, NULL);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,154 @@
|
|||
/******************************************************************************
|
||||
|
||||
giffilter.c - skeleton file for generic GIF `filter' program
|
||||
|
||||
Sequentially read GIF records from stdin, process them, send them out.
|
||||
Most of the junk above `int main' isn't needed for the skeleton, but
|
||||
is likely to be for what you'll do with it.
|
||||
|
||||
If you compile this, it will turn into an expensive GIF copying routine;
|
||||
stdin to stdout with no changes and minimal validation. Well, it's a
|
||||
decent test of the low-level routines, anyway.
|
||||
|
||||
Note: due to the vicissitudes of Lempel-Ziv compression, the output of this
|
||||
copier may not be bitwise identical to its input. This can happen if you
|
||||
copy an image from a much more (or much *less*) memory-limited system; your
|
||||
compression may use more (or fewer) bits. The uncompressed rasters should,
|
||||
however, be identical (you can check this with gifbuild -d).
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "giffilter"
|
||||
|
||||
/******************************************************************************
|
||||
Close both input and output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
|
||||
{
|
||||
if (GifFileIn != NULL) {
|
||||
PrintGifError(GifFileIn->Error);
|
||||
EGifCloseFile(GifFileIn, NULL);
|
||||
}
|
||||
if (GifFileOut != NULL) {
|
||||
PrintGifError(GifFileOut->Error);
|
||||
EGifCloseFile(GifFileOut, NULL);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Main sequence
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
|
||||
GifRecordType RecordType;
|
||||
int CodeSize, ExtCode, ErrorCode;
|
||||
GifByteType *CodeBlock, *Extension;
|
||||
|
||||
/*
|
||||
* Command-line processing goes here.
|
||||
*/
|
||||
|
||||
/* Use stdin as input (note this also read screen descriptor in: */
|
||||
if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Use the stdout as output: */
|
||||
if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* And dump out its screen information: */
|
||||
if (EGifPutScreenDesc(GifFileOut,
|
||||
GifFileIn->SWidth, GifFileIn->SHeight,
|
||||
GifFileIn->SColorResolution, GifFileIn->SBackGroundColor,
|
||||
GifFileIn->SColorMap) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
/* Scan the content of the input GIF file and load the image(s) in: */
|
||||
do {
|
||||
if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
switch (RecordType) {
|
||||
case IMAGE_DESC_RECORD_TYPE:
|
||||
if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
/* Put image descriptor to out file: */
|
||||
if (EGifPutImageDesc(GifFileOut,
|
||||
GifFileIn->Image.Left, GifFileIn->Image.Top,
|
||||
GifFileIn->Image.Width, GifFileIn->Image.Height,
|
||||
GifFileIn->Image.Interlace,
|
||||
GifFileIn->Image.ColorMap) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
/* Now read image itself in decoded form as we dont really */
|
||||
/* care what we have there, and this is much faster. */
|
||||
if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) == GIF_ERROR ||
|
||||
EGifPutCode(GifFileOut, CodeSize, CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
while (CodeBlock != NULL) {
|
||||
if (DGifGetCodeNext(GifFileIn, &CodeBlock) == GIF_ERROR ||
|
||||
EGifPutCodeNext(GifFileOut, CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
break;
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
/* pass through extension records */
|
||||
if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR || Extension == NULL)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (EGifPutExtensionLeader(GifFileOut, ExtCode) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (EGifPutExtensionBlock(GifFileOut,
|
||||
Extension[0],
|
||||
Extension + 1) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
while (Extension != NULL) {
|
||||
if (DGifGetExtensionNext(GifFileIn, &Extension)==GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (Extension != NULL)
|
||||
if (EGifPutExtensionBlock(GifFileOut,
|
||||
Extension[0],
|
||||
Extension + 1) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
break;
|
||||
case TERMINATE_RECORD_TYPE:
|
||||
break;
|
||||
default: /* Should be trapped by DGifGetRecordType */
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (RecordType != TERMINATE_RECORD_TYPE);
|
||||
|
||||
if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,218 @@
|
|||
/*****************************************************************************
|
||||
|
||||
giffix - attempt to fix a truncated GIF
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "giffix"
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- h%- GifFile!*s";
|
||||
|
||||
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut);
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and scan the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, NumFiles, ExtCode, Row, Col, Width, Height, ErrorCode,
|
||||
DarkestColor = 0, ColorIntens = 10000;
|
||||
bool Error, HelpFlag = false;
|
||||
GifRecordType RecordType;
|
||||
GifByteType *Extension;
|
||||
char **FileName = NULL;
|
||||
GifRowType LineBuffer;
|
||||
ColorMapObject *ColorMap;
|
||||
GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
|
||||
int ImageNum = 0;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint, &HelpFlag,
|
||||
&NumFiles, &FileName)) != false ||
|
||||
(NumFiles > 1 && !HelpFlag)) {
|
||||
if (Error)
|
||||
GAPrintErrMsg(Error);
|
||||
else if (NumFiles > 1)
|
||||
GIF_MESSAGE("Error in command line parsing - one GIF file please.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (NumFiles == 1) {
|
||||
if ((GifFileIn = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use stdin instead: */
|
||||
if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Open stdout for the output file: */
|
||||
if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Dump out exactly same screen information: */
|
||||
/* coverity[var_deref_op] */
|
||||
if (EGifPutScreenDesc(GifFileOut,
|
||||
GifFileIn->SWidth, GifFileIn->SHeight,
|
||||
GifFileIn->SColorResolution, GifFileIn->SBackGroundColor,
|
||||
GifFileIn->SColorMap) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
if ((LineBuffer = (GifRowType) malloc(GifFileIn->SWidth)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
/* Scan the content of the GIF file and load the image(s) in: */
|
||||
do {
|
||||
if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
switch (RecordType) {
|
||||
case IMAGE_DESC_RECORD_TYPE:
|
||||
if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (GifFileIn->Image.Interlace)
|
||||
GIF_EXIT("Cannot fix interlaced images.");
|
||||
|
||||
Row = GifFileIn->Image.Top; /* Image Position relative to Screen. */
|
||||
Col = GifFileIn->Image.Left;
|
||||
Width = GifFileIn->Image.Width;
|
||||
Height = GifFileIn->Image.Height;
|
||||
GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
|
||||
if (Width > GifFileIn->SWidth)
|
||||
GIF_EXIT("Image is wider than total");
|
||||
|
||||
/* Put the image descriptor to out file: */
|
||||
if (EGifPutImageDesc(GifFileOut, Col, Row, Width, Height,
|
||||
false, GifFileIn->Image.ColorMap) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
/* Find the darkest color in color map to use as a filler. */
|
||||
ColorMap = (GifFileIn->Image.ColorMap ? GifFileIn->Image.ColorMap :
|
||||
GifFileIn->SColorMap);
|
||||
for (i = 0; i < ColorMap->ColorCount; i++) {
|
||||
j = ((int) ColorMap->Colors[i].Red) * 30 +
|
||||
((int) ColorMap->Colors[i].Green) * 59 +
|
||||
((int) ColorMap->Colors[i].Blue) * 11;
|
||||
if (j < ColorIntens) {
|
||||
ColorIntens = j;
|
||||
DarkestColor = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* Load the image, and dump it. */
|
||||
for (i = 0; i < Height; i++) {
|
||||
GifQprintf("\b\b\b\b%-4d", i);
|
||||
if (DGifGetLine(GifFileIn, LineBuffer, Width)
|
||||
== GIF_ERROR) break;
|
||||
if (EGifPutLine(GifFileOut, LineBuffer, Width)
|
||||
== GIF_ERROR) QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
|
||||
if (i < Height) {
|
||||
fprintf(stderr,"\nFollowing error occurred (and ignored):");
|
||||
PrintGifError(GifFileIn->Error);
|
||||
|
||||
/* Fill in with the darkest color in color map. */
|
||||
for (j = 0; j < Width; j++)
|
||||
LineBuffer[j] = DarkestColor;
|
||||
for (; i < Height; i++)
|
||||
if (EGifPutLine(GifFileOut, LineBuffer, Width)
|
||||
== GIF_ERROR) QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
break;
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
/* pass through extension records */
|
||||
if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (EGifPutExtensionLeader(GifFileOut, ExtCode) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (Extension != NULL)
|
||||
if (EGifPutExtensionBlock(GifFileOut,
|
||||
Extension[0],
|
||||
Extension + 1) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
while (Extension != NULL) {
|
||||
if (DGifGetExtensionNext(GifFileIn, &Extension)==GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
if (Extension != NULL)
|
||||
if (EGifPutExtensionBlock(GifFileOut,
|
||||
Extension[0],
|
||||
Extension + 1) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
if (EGifPutExtensionTrailer(GifFileOut) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
break;
|
||||
case TERMINATE_RECORD_TYPE:
|
||||
break;
|
||||
default: /* Should be trapped by DGifGetRecordType. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (RecordType != TERMINATE_RECORD_TYPE);
|
||||
|
||||
if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Close both input and output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
|
||||
{
|
||||
fprintf(stderr, "\nFollowing unrecoverable error occurred:");
|
||||
if (GifFileIn != NULL) {
|
||||
PrintGifError(GifFileIn->Error);
|
||||
EGifCloseFile(GifFileIn, NULL);
|
||||
}
|
||||
if (GifFileOut != NULL) {
|
||||
PrintGifError(GifFileOut->Error);
|
||||
EGifCloseFile(GifFileOut, NULL);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,259 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifhisto - make a color histogram from image color frequencies
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifhisto"
|
||||
|
||||
#define DEFAULT_HISTO_WIDTH 100 /* Histogram image diemnsions. */
|
||||
#define DEFAULT_HISTO_HEIGHT 256
|
||||
#define HISTO_BITS_PER_PIXEL 2 /* Size of bitmap for histogram GIF. */
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- t%- s%-Width|Height!d!d n%-ImageNumber!d b%- h%- GifFile!*s";
|
||||
|
||||
static int
|
||||
ImageWidth = DEFAULT_HISTO_WIDTH,
|
||||
ImageHeight = DEFAULT_HISTO_HEIGHT,
|
||||
ImageN = 1;
|
||||
static GifColorType
|
||||
HistoColorMap[] = { /* Constant bit map for histograms: */
|
||||
{ 0, 0, 0 },
|
||||
{ 255, 0, 0 },
|
||||
{ 0, 255, 0 },
|
||||
{ 0, 0, 255 }
|
||||
};
|
||||
|
||||
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut);
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and scan the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, ErrorCode, NumFiles, ExtCode, CodeSize, NumColors = 2, ImageNum = 0;
|
||||
bool Error, TextFlag = false, SizeFlag = false,
|
||||
ImageNFlag = false, BackGroundFlag = false, HelpFlag = false;
|
||||
long Histogram[256];
|
||||
GifRecordType RecordType;
|
||||
GifByteType *Extension, *CodeBlock;
|
||||
char **FileName = NULL;
|
||||
GifRowType Line;
|
||||
GifFileType *GifFileIn = NULL, *GifFileOut = NULL;
|
||||
|
||||
/* Same image dimension vars for both Image & ImageN as only one allowed */
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
|
||||
&TextFlag, &SizeFlag, &ImageWidth, &ImageHeight,
|
||||
&ImageNFlag, &ImageN, &BackGroundFlag,
|
||||
&HelpFlag, &NumFiles, &FileName)) != false ||
|
||||
(NumFiles > 1 && !HelpFlag)) {
|
||||
if (Error)
|
||||
GAPrintErrMsg(Error);
|
||||
else if (NumFiles > 1)
|
||||
GIF_MESSAGE("Error in command line parsing - one GIF file please.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (NumFiles == 1) {
|
||||
if ((GifFileIn = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Use stdin instead: */
|
||||
if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < 256; i++) Histogram[i] = 0; /* Reset counters. */
|
||||
|
||||
/* Scan the content of the GIF file and load the image(s) in: */
|
||||
do {
|
||||
if (DGifGetRecordType(GifFileIn, &RecordType) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
switch (RecordType) {
|
||||
case IMAGE_DESC_RECORD_TYPE:
|
||||
if (DGifGetImageDesc(GifFileIn) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
if (GifFileIn->Image.ColorMap)
|
||||
NumColors = GifFileIn->Image.ColorMap->ColorCount;
|
||||
else if (GifFileIn->SColorMap)
|
||||
NumColors = GifFileIn->SColorMap->ColorCount;
|
||||
else
|
||||
GIF_EXIT("Neither Screen nor Image color map exists.");
|
||||
|
||||
if ((ImageHeight / NumColors) * NumColors != ImageHeight)
|
||||
GIF_EXIT("Image height specified not dividable by #colors.");
|
||||
|
||||
if (++ImageNum == ImageN) {
|
||||
/* This is the image we should make histogram for: */
|
||||
Line = (GifRowType) malloc(GifFileIn->Image.Width *
|
||||
sizeof(GifPixelType));
|
||||
GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, ImageNum,
|
||||
GifFileIn->Image.Left, GifFileIn->Image.Top,
|
||||
GifFileIn->Image.Width, GifFileIn->Image.Height);
|
||||
|
||||
for (i = 0; i < GifFileIn->Image.Height; i++) {
|
||||
if (DGifGetLine(GifFileIn, Line, GifFileIn->Image.Width)
|
||||
== GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
for (j = 0; j < GifFileIn->Image.Width; j++)
|
||||
Histogram[Line[j]]++;
|
||||
GifQprintf("\b\b\b\b%-4d", i);
|
||||
}
|
||||
|
||||
free((char *) Line);
|
||||
}
|
||||
else {
|
||||
/* Skip the image: */
|
||||
/* Now read image itself in decoded form as we dont */
|
||||
/* really care what is there, and this is much faster. */
|
||||
if (DGifGetCode(GifFileIn, &CodeSize, &CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
while (CodeBlock != NULL)
|
||||
if (DGifGetCodeNext(GifFileIn, &CodeBlock) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
break;
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
/* Skip any extension blocks in file: */
|
||||
if (DGifGetExtension(GifFileIn, &ExtCode, &Extension) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
while (Extension != NULL) {
|
||||
if (DGifGetExtensionNext(GifFileIn, &Extension) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
}
|
||||
break;
|
||||
case TERMINATE_RECORD_TYPE:
|
||||
break;
|
||||
default: /* Should be trapped by DGifGetRecordType. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (RecordType != TERMINATE_RECORD_TYPE);
|
||||
|
||||
/* We requested suppression of the background count: */
|
||||
if (BackGroundFlag) Histogram[GifFileIn->SBackGroundColor] = 0;
|
||||
|
||||
if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
/* We may required to dump out the histogram as text file: */
|
||||
if (TextFlag) {
|
||||
for (i = 0; i < NumColors; i++)
|
||||
printf("%12ld %3d\n", Histogram[i], i);
|
||||
}
|
||||
else {
|
||||
int Color, Count;
|
||||
long Scaler;
|
||||
/* Open stdout for the histogram output file: */
|
||||
if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Dump out screen descriptor to fit histogram dimensions: */
|
||||
if (EGifPutScreenDesc(GifFileOut,
|
||||
ImageWidth, ImageHeight, HISTO_BITS_PER_PIXEL, 0,
|
||||
GifMakeMapObject(4, HistoColorMap)) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
/* Dump out image descriptor to fit histogram dimensions: */
|
||||
if (EGifPutImageDesc(GifFileOut,
|
||||
0, 0, ImageWidth, ImageHeight, false, NULL) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
|
||||
/* Prepare scan line for histogram file, and find scaler to scale */
|
||||
/* histogram to be between 0 and ImageWidth: */
|
||||
Line = (GifRowType) malloc(ImageWidth * sizeof(GifPixelType));
|
||||
for (Scaler = 0, i = 0; i < NumColors; i++) if (Histogram[i] > Scaler)
|
||||
Scaler = Histogram[i];
|
||||
Scaler /= ImageWidth;
|
||||
if (Scaler == 0) Scaler = 1; /* In case maximum is less than width. */
|
||||
|
||||
/* Dump out the image itself: */
|
||||
for (Count = ImageHeight, i = 0, Color = 1; i < NumColors; i++) {
|
||||
int Size;
|
||||
if ((Size = Histogram[i] / Scaler) > ImageWidth) Size = ImageWidth;
|
||||
for (j = 0; j < Size; j++)
|
||||
Line[j] = Color;
|
||||
for (j = Size; j < ImageWidth; j++)
|
||||
Line[j] = GifFileOut->SBackGroundColor;
|
||||
|
||||
/* Move to next color: */
|
||||
if (++Color >= (1 << HISTO_BITS_PER_PIXEL)) Color = 1;
|
||||
|
||||
/* Dump this histogram entry as many times as required: */
|
||||
for (j = 0; j < ImageHeight / NumColors; j++) {
|
||||
if (EGifPutLine(GifFileOut, Line, ImageWidth) == GIF_ERROR)
|
||||
QuitGifError(GifFileIn, GifFileOut);
|
||||
GifQprintf("\b\b\b\b%-4d", Count--);
|
||||
}
|
||||
}
|
||||
|
||||
if (EGifCloseFile(GifFileOut, &ErrorCode) == GIF_ERROR)
|
||||
{
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Close both input and output file (if open), and exit.
|
||||
******************************************************************************/
|
||||
static void QuitGifError(GifFileType *GifFileIn, GifFileType *GifFileOut)
|
||||
{
|
||||
if (GifFileIn != NULL) {
|
||||
PrintGifError(GifFileIn->Error);
|
||||
EGifCloseFile(GifFileIn, NULL);
|
||||
}
|
||||
if (GifFileOut != NULL) {
|
||||
PrintGifError(GifFileOut->Error);
|
||||
EGifCloseFile(GifFileOut, NULL);
|
||||
}
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,191 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifinto - save GIF on stdin to file if size over set threshold
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifinto"
|
||||
|
||||
#define STRLEN 512
|
||||
|
||||
#define DEFAULT_MIN_FILE_SIZE 14 /* More than GIF stamp + screen desc. */
|
||||
#define DEFAULT_OUT_NAME "GifInto.Gif"
|
||||
#define DEFAULT_TMP_NAME "TempInto.XXXXXX"
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- s%-MinFileSize!d h%- GifFile!*s";
|
||||
|
||||
static int
|
||||
MinFileSize = DEFAULT_MIN_FILE_SIZE;
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
int
|
||||
mkstemp(char *tpl)
|
||||
{
|
||||
int fd = -1;
|
||||
char *p;
|
||||
int e = errno;
|
||||
|
||||
errno = 0;
|
||||
p = _mktemp(tpl);
|
||||
if (*p && errno == 0)
|
||||
{
|
||||
errno = e;
|
||||
fd = _open(p, _O_RDWR | _O_CREAT | _O_EXCL | _O_BINARY,
|
||||
_S_IREAD | _S_IWRITE);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************************
|
||||
This is simply: read until EOF, then close the output, test its length, and
|
||||
if non zero then rename it.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int FD;
|
||||
int NumFiles;
|
||||
bool Error, MinSizeFlag = false, HelpFlag = false;
|
||||
char **FileName = NULL, FoutTmpName[STRLEN+1], FullPath[STRLEN+1], *p;
|
||||
FILE *Fin, *Fout;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr, &GifNoisyPrint,
|
||||
&MinSizeFlag, &MinFileSize, &HelpFlag,
|
||||
&NumFiles, &FileName)) != false ||
|
||||
(NumFiles > 1 && !HelpFlag)) {
|
||||
if (Error)
|
||||
GAPrintErrMsg(Error);
|
||||
else if (NumFiles != 1)
|
||||
GIF_MESSAGE("Error in command line parsing - one GIF file please.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Open the stdin in binary mode and increase its buffer size: */
|
||||
#ifdef _WIN32
|
||||
_setmode(0, O_BINARY); /* Make sure it is in binary mode. */
|
||||
#endif
|
||||
|
||||
Fin = fdopen(0, "rb"); /* Make it into a stream: */
|
||||
|
||||
if (Fin == NULL)
|
||||
{
|
||||
GIF_EXIT("Failed to open input.");
|
||||
}
|
||||
|
||||
/* Isolate the directory where our destination is, and set tmp file name */
|
||||
/* in the very same directory. This code is isecure because it creates */
|
||||
/* predictable names, but it's not worth the effort and risk to fix. */
|
||||
if ( *FileName == NULL ) GIF_EXIT("No valid Filename given.");
|
||||
if ( strlen(*FileName) > STRLEN-1 ) GIF_EXIT("Filename too long.");
|
||||
memset(FullPath, '\0', sizeof(FullPath));
|
||||
strncpy(FullPath, *FileName, STRLEN);
|
||||
if ((p = strrchr(FullPath, '/')) != NULL ||
|
||||
(p = strrchr(FullPath, '\\')) != NULL)
|
||||
p[1] = 0;
|
||||
else if ((p = strrchr(FullPath, ':')) != NULL)
|
||||
p[1] = 0;
|
||||
else
|
||||
FullPath[0] = 0; /* No directory or disk specified. */
|
||||
|
||||
if ( strlen(FullPath) > STRLEN-1 ) GIF_EXIT("Filename too long.");
|
||||
strncpy(FoutTmpName, FullPath, STRLEN); /* First setup the Path */
|
||||
/* then add a name for the tempfile */
|
||||
if ( (strlen(FoutTmpName) + strlen(DEFAULT_TMP_NAME)) > STRLEN-1 ) GIF_EXIT("Filename too long.");
|
||||
strcat(FoutTmpName, DEFAULT_TMP_NAME);
|
||||
#ifdef _WIN32
|
||||
char *tmpFN = _mktemp(FoutTmpName);
|
||||
if (tmpFN)
|
||||
FD = open(tmpFN, O_CREAT | O_EXCL | O_WRONLY);
|
||||
else
|
||||
FD = -1;
|
||||
#else
|
||||
FD = mkstemp(FoutTmpName); /* returns filedescriptor */
|
||||
#endif
|
||||
if (FD == -1 )
|
||||
{
|
||||
GIF_EXIT("Failed to open output.");
|
||||
}
|
||||
Fout = fdopen(FD, "wb"); /* returns a stream with FD */
|
||||
if (Fout == NULL )
|
||||
{
|
||||
GIF_EXIT("Failed to open output.");
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int c = getc(Fin);
|
||||
|
||||
if (feof(Fin))
|
||||
break;
|
||||
if (putc(c, Fout) == EOF)
|
||||
GIF_EXIT("Failed to write output.");
|
||||
}
|
||||
|
||||
fclose(Fin);
|
||||
if (ftell(Fout) >= (long) MinFileSize) {
|
||||
fclose(Fout);
|
||||
unlink(*FileName);
|
||||
if (rename(FoutTmpName, *FileName) != 0) {
|
||||
char DefaultName[STRLEN+1];
|
||||
memset(DefaultName, '\0', sizeof(DefaultName));
|
||||
if ( (strlen(FullPath) + strlen(DEFAULT_OUT_NAME)) > STRLEN-1 ) GIF_EXIT("Filename too long.");
|
||||
strncpy(DefaultName, FullPath, STRLEN);
|
||||
strcat(DefaultName, DEFAULT_OUT_NAME);
|
||||
if (rename(FoutTmpName, DefaultName) == 0) {
|
||||
char s[STRLEN];
|
||||
snprintf(s, STRLEN, "Failed to rename out file - left as %s.",
|
||||
DefaultName);
|
||||
GIF_MESSAGE(s);
|
||||
}
|
||||
else {
|
||||
unlink(FoutTmpName);
|
||||
GIF_MESSAGE("Failed to rename out file - deleted.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
fclose(Fout);
|
||||
unlink(FoutTmpName);
|
||||
GIF_MESSAGE("File too small - not renamed.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,79 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||
<CodeBlocks_project_file>
|
||||
<FileVersion major="1" minor="6" />
|
||||
<Project>
|
||||
<Option title="giflib" />
|
||||
<Option pch_mode="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Build>
|
||||
<Target title="Debug">
|
||||
<Option output="bin/Debug/giflib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="obj/Debug/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-Wall" />
|
||||
<Add option="-g" />
|
||||
</Compiler>
|
||||
</Target>
|
||||
<Target title="Release">
|
||||
<Option output="bin/Release/giflib" prefix_auto="1" extension_auto="1" />
|
||||
<Option working_dir="" />
|
||||
<Option object_output="obj/Release/" />
|
||||
<Option type="2" />
|
||||
<Option compiler="gcc" />
|
||||
<Option createDefFile="1" />
|
||||
<Compiler>
|
||||
<Add option="-Wall" />
|
||||
<Add option="-O2" />
|
||||
</Compiler>
|
||||
<Linker>
|
||||
<Add option="-s" />
|
||||
</Linker>
|
||||
</Target>
|
||||
</Build>
|
||||
<Compiler>
|
||||
<Add option="-fPIC" />
|
||||
</Compiler>
|
||||
<Unit filename="dgif_lib.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="egif_lib.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="getarg.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="getarg.h" />
|
||||
<Unit filename="gif_err.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="gif_font.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="gif_hash.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="gif_hash.h" />
|
||||
<Unit filename="gif_lib.h" />
|
||||
<Unit filename="gif_lib_private.h" />
|
||||
<Unit filename="gifalloc.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="openbsd-reallocarray.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="qprintf.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Unit filename="quantize.c">
|
||||
<Option compilerVar="CC" />
|
||||
</Unit>
|
||||
<Extensions>
|
||||
<code_completion />
|
||||
<debugger />
|
||||
</Extensions>
|
||||
</Project>
|
||||
</CodeBlocks_project_file>
|
|
@ -0,0 +1,87 @@
|
|||
/****************************************************************************
|
||||
|
||||
gifsponge.c - skeleton file for generic GIF `sponge' program
|
||||
|
||||
Slurp a GIF into core, operate on it, spew it out again. Most of the
|
||||
junk above `int main' isn't needed for the skeleton, but is likely to
|
||||
be for what you'll do with it.
|
||||
|
||||
If you compile this, it will turn into an expensive GIF copying routine;
|
||||
stdin to stdout with no changes and minimal validation. Well, it's a
|
||||
decent test of DGifSlurp() and EGifSpew(), anyway.
|
||||
|
||||
Note: due to the vicissitudes of Lempel-Ziv compression, the output of this
|
||||
copier may not be bitwise identical to its input. This can happen if you
|
||||
copy an image from a much more (or much *less*) memory-limited system; your
|
||||
compression may use more (or fewer) bits. The uncompressed rasters should,
|
||||
however, be identical (you can check this with gifbuild -d).
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifsponge"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, ErrorCode;
|
||||
GifFileType *GifFileIn, *GifFileOut = (GifFileType *)NULL;
|
||||
|
||||
if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (DGifSlurp(GifFileIn) == GIF_ERROR) {
|
||||
PrintGifError(GifFileIn->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Your operations on in-core structures go here.
|
||||
* This code just copies the header and each image from the incoming file.
|
||||
*/
|
||||
GifFileOut->SWidth = GifFileIn->SWidth;
|
||||
GifFileOut->SHeight = GifFileIn->SHeight;
|
||||
GifFileOut->SColorResolution = GifFileIn->SColorResolution;
|
||||
GifFileOut->SBackGroundColor = GifFileIn->SBackGroundColor;
|
||||
if (GifFileIn->SColorMap) {
|
||||
GifFileOut->SColorMap = GifMakeMapObject(
|
||||
GifFileIn->SColorMap->ColorCount,
|
||||
GifFileIn->SColorMap->Colors);
|
||||
} else {
|
||||
GifFileOut->SColorMap = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < GifFileIn->ImageCount; i++)
|
||||
(void) GifMakeSavedImage(GifFileOut, &GifFileIn->SavedImages[i]);
|
||||
|
||||
/*
|
||||
* Note: don't do DGifCloseFile early, as this will
|
||||
* deallocate all the memory containing the GIF data!
|
||||
*
|
||||
* Further note: EGifSpew() doesn't try to validity-check any of this
|
||||
* data; it's *your* responsibility to keep your changes consistent.
|
||||
* Caveat hacker!
|
||||
*/
|
||||
if (EGifSpew(GifFileOut) == GIF_ERROR)
|
||||
PrintGifError(GifFileOut->Error);
|
||||
|
||||
if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
|
||||
PrintGifError(ErrorCode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,466 @@
|
|||
/*****************************************************************************
|
||||
|
||||
giftext - dump GIF pixels and metadata as text
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "giftext"
|
||||
|
||||
#define MAKE_PRINTABLE(c) (isprint(c) ? (c) : ' ')
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- c%- e%- z%- p%- r%- h%- GifFile!*s";
|
||||
|
||||
static void PrintCodeBlock(GifFileType *GifFile, GifByteType *CodeBlock, bool Reset);
|
||||
static void PrintPixelBlock(GifByteType *PixelBlock, int Len, bool Reset);
|
||||
static void PrintExtBlock(GifByteType *Extension, bool Reset);
|
||||
static void PrintLZCodes(GifFileType *GifFile);
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and scan the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, ExtCode, ErrorCode, CodeSize, NumFiles, Len, ImageNum = 1;
|
||||
bool Error,
|
||||
ColorMapFlag = false, EncodedFlag = false, LZCodesFlag = false,
|
||||
PixelFlag = false, HelpFlag = false, RawFlag = false;
|
||||
char *GifFileName, **FileName = NULL;
|
||||
GifPixelType *Line;
|
||||
GifRecordType RecordType;
|
||||
GifByteType *CodeBlock, *Extension;
|
||||
GifFileType *GifFile;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr,
|
||||
&GifNoisyPrint, &ColorMapFlag, &EncodedFlag,
|
||||
&LZCodesFlag, &PixelFlag, &RawFlag, &HelpFlag,
|
||||
&NumFiles, &FileName)) != false ||
|
||||
(NumFiles > 1 && !HelpFlag)) {
|
||||
if (Error)
|
||||
GAPrintErrMsg(Error);
|
||||
else if (NumFiles > 1)
|
||||
GIF_MESSAGE("Error in command line parsing - one GIF file please.");
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (NumFiles == 1) {
|
||||
GifFileName = *FileName;
|
||||
if ((GifFile = DGifOpenFileName(*FileName, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Use stdin instead: */
|
||||
GifFileName = "Stdin";
|
||||
if ((GifFile = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Because we write binary data - make sure no text will be written. */
|
||||
if (RawFlag) {
|
||||
ColorMapFlag = EncodedFlag = LZCodesFlag = PixelFlag = false;
|
||||
#ifdef _WIN32
|
||||
_setmode(1, O_BINARY); /* Make sure it is in binary mode. */
|
||||
#endif /* _WIN32 */
|
||||
}
|
||||
else {
|
||||
printf("\n%s:\n\n\tScreen Size - Width = %d, Height = %d.\n",
|
||||
GifFileName, GifFile->SWidth, GifFile->SHeight);
|
||||
printf("\tColorResolution = %d, BitsPerPixel = %d, BackGround = %d, Aspect = %d.\n",
|
||||
GifFile->SColorResolution,
|
||||
GifFile->SColorMap ? GifFile->SColorMap->BitsPerPixel : 0,
|
||||
GifFile->SBackGroundColor,
|
||||
GifFile->AspectByte);
|
||||
if (GifFile->SColorMap)
|
||||
printf("\tHas Global Color Map.\n\n");
|
||||
else
|
||||
printf("\tNo Global Color Map.\n\n");
|
||||
if (ColorMapFlag && GifFile->SColorMap) {
|
||||
printf("\tGlobal Color Map:\n");
|
||||
Len = GifFile->SColorMap->ColorCount;
|
||||
printf("\tSort Flag: %s\n",
|
||||
GifFile->SColorMap->SortFlag ? "on":"off");
|
||||
for (i = 0; i < Len; i+=4) {
|
||||
for (j = 0; j < 4 && j < Len; j++) {
|
||||
printf("%3d: %02xh %02xh %02xh ", i + j,
|
||||
GifFile->SColorMap->Colors[i + j].Red,
|
||||
GifFile->SColorMap->Colors[i + j].Green,
|
||||
GifFile->SColorMap->Colors[i + j].Blue);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
switch (RecordType) {
|
||||
case IMAGE_DESC_RECORD_TYPE:
|
||||
if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!RawFlag) {
|
||||
printf("\nImage #%d:\n\n\tImage Size - Left = %d, Top = %d, Width = %d, Height = %d.\n",
|
||||
ImageNum++, GifFile->Image.Left, GifFile->Image.Top,
|
||||
GifFile->Image.Width, GifFile->Image.Height);
|
||||
printf("\tImage is %s",
|
||||
GifFile->Image.Interlace ? "Interlaced" :
|
||||
"Non Interlaced");
|
||||
if (GifFile->Image.ColorMap != NULL)
|
||||
printf(", BitsPerPixel = %d.\n",
|
||||
GifFile->Image.ColorMap->BitsPerPixel);
|
||||
else
|
||||
printf(".\n");
|
||||
if (GifFile->Image.ColorMap)
|
||||
printf("\tImage Has Color Map.\n");
|
||||
else
|
||||
printf("\tNo Image Color Map.\n");
|
||||
if (ColorMapFlag && GifFile->Image.ColorMap) {
|
||||
printf("\tSort Flag: %s\n",
|
||||
GifFile->Image.ColorMap->SortFlag ? "on":"off");
|
||||
Len = 1 << GifFile->Image.ColorMap->BitsPerPixel;
|
||||
for (i = 0; i < Len; i+=4) {
|
||||
for (j = 0; j < 4 && j < Len; j++) {
|
||||
printf("%3d: %02xh %02xh %02xh ", i + j,
|
||||
GifFile->Image.ColorMap->Colors[i + j].Red,
|
||||
GifFile->Image.ColorMap->Colors[i + j].Green,
|
||||
GifFile->Image.ColorMap->Colors[i + j].Blue);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EncodedFlag) {
|
||||
if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("\nImage LZ compressed Codes (Code Size = %d):\n",
|
||||
CodeSize);
|
||||
PrintCodeBlock(GifFile, CodeBlock, true);
|
||||
while (CodeBlock != NULL) {
|
||||
if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
PrintCodeBlock(GifFile, CodeBlock, false);
|
||||
}
|
||||
}
|
||||
else if (LZCodesFlag) {
|
||||
PrintLZCodes(GifFile);
|
||||
}
|
||||
else if (PixelFlag) {
|
||||
Line = (GifPixelType *) malloc(GifFile->Image.Width *
|
||||
sizeof(GifPixelType));
|
||||
for (i = 0; i < GifFile->Image.Height; i++) {
|
||||
if (DGifGetLine(GifFile, Line, GifFile->Image.Width)
|
||||
== GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
PrintPixelBlock(Line, GifFile->Image.Width, i == 0);
|
||||
}
|
||||
PrintPixelBlock(NULL, GifFile->Image.Width, false);
|
||||
free((char *) Line);
|
||||
}
|
||||
else if (RawFlag) {
|
||||
Line = (GifPixelType *) malloc(GifFile->Image.Width *
|
||||
sizeof(GifPixelType));
|
||||
for (i = 0; i < GifFile->Image.Height; i++) {
|
||||
if (DGifGetLine(GifFile, Line, GifFile->Image.Width)
|
||||
== GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
fwrite(Line, 1, GifFile->Image.Width, stdout);
|
||||
}
|
||||
free((char *) Line);
|
||||
}
|
||||
else {
|
||||
/* Skip the image: */
|
||||
if (DGifGetCode(GifFile, &CodeSize, &CodeBlock) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while (CodeBlock != NULL) {
|
||||
if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (!RawFlag) {
|
||||
putchar('\n');
|
||||
switch (ExtCode)
|
||||
{
|
||||
case COMMENT_EXT_FUNC_CODE:
|
||||
printf("GIF89 comment");
|
||||
break;
|
||||
case GRAPHICS_EXT_FUNC_CODE:
|
||||
printf("GIF89 graphics control");
|
||||
break;
|
||||
case PLAINTEXT_EXT_FUNC_CODE:
|
||||
printf("GIF89 plaintext");
|
||||
break;
|
||||
case APPLICATION_EXT_FUNC_CODE:
|
||||
printf("GIF89 application block");
|
||||
break;
|
||||
default:
|
||||
printf("Extension record of unknown type");
|
||||
break;
|
||||
}
|
||||
printf(" (Ext Code = %d [%c]):\n",
|
||||
ExtCode, MAKE_PRINTABLE(ExtCode));
|
||||
PrintExtBlock(Extension, true);
|
||||
|
||||
if (ExtCode == GRAPHICS_EXT_FUNC_CODE) {
|
||||
GraphicsControlBlock gcb;
|
||||
if (Extension == NULL) {
|
||||
printf("Invalid extension block\n");
|
||||
GifFile->Error = D_GIF_ERR_IMAGE_DEFECT;
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (DGifExtensionToGCB(Extension[0], Extension+1, &gcb) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
printf("\tDisposal Mode: %d\n", gcb.DisposalMode);
|
||||
printf("\tUser Input Flag: %d\n", gcb.UserInputFlag);
|
||||
printf("\tTransparency on: %s\n",
|
||||
gcb.TransparentColor != -1 ? "yes" : "no");
|
||||
printf("\tDelayTime: %d\n", gcb.DelayTime);
|
||||
printf("\tTransparent Index: %d\n", gcb.TransparentColor);
|
||||
}
|
||||
}
|
||||
for (;;) {
|
||||
if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (Extension == NULL)
|
||||
break;
|
||||
PrintExtBlock(Extension, false);
|
||||
}
|
||||
break;
|
||||
case TERMINATE_RECORD_TYPE:
|
||||
break;
|
||||
default: /* Should be trapped by DGifGetRecordType */
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (RecordType != TERMINATE_RECORD_TYPE);
|
||||
|
||||
if (DGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!RawFlag) printf("\nGIF file terminated normally.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Print the given CodeBlock - a string in pascal notation (size in first
|
||||
place). Save local information so printing can be performed continuously,
|
||||
or reset to start state if Reset. If CodeBlock is NULL, output is flushed
|
||||
******************************************************************************/
|
||||
static void PrintCodeBlock(GifFileType *GifFile, GifByteType *CodeBlock, bool Reset)
|
||||
{
|
||||
static int CrntPlace = 0;
|
||||
static long CodeCount = 0;
|
||||
int i, Len;
|
||||
|
||||
if (Reset || CodeBlock == NULL) {
|
||||
if (CodeBlock == NULL) {
|
||||
long NumBytes = 0;
|
||||
if (CrntPlace > 0) {
|
||||
printf("\n");
|
||||
CodeCount += CrntPlace - 16;
|
||||
}
|
||||
if (GifFile->Image.ColorMap)
|
||||
NumBytes = ((((long) GifFile->Image.Width) * GifFile->Image.Height)
|
||||
* GifFile->Image.ColorMap->BitsPerPixel) / 8;
|
||||
else if (GifFile->SColorMap != NULL)
|
||||
NumBytes = ((((long) GifFile->Image.Width) * GifFile->Image.Height)
|
||||
* GifFile->SColorMap->BitsPerPixel) / 8;
|
||||
/* FIXME: What should the compression ratio be if no color table? */
|
||||
if (NumBytes > 0) {
|
||||
int Percent = 100 * CodeCount / NumBytes;
|
||||
printf("\nCompression ratio: %ld/%ld (%d%%).\n",
|
||||
CodeCount, NumBytes, Percent);
|
||||
}
|
||||
return;
|
||||
}
|
||||
CrntPlace = 0;
|
||||
CodeCount = 0;
|
||||
}
|
||||
|
||||
Len = CodeBlock[0];
|
||||
for (i = 1; i <= Len; i++) {
|
||||
if (CrntPlace == 0) {
|
||||
printf("\n%05lxh: ", CodeCount);
|
||||
CodeCount += 16;
|
||||
}
|
||||
(void)printf(" %02xh", CodeBlock[i]);
|
||||
if (++CrntPlace >= 16) CrntPlace = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Print the given Extension - a string in pascal notation (size in first
|
||||
place). Save local information so printing can be performed continuously,
|
||||
or reset to start state if Reset. If Extension is NULL, output is flushed
|
||||
******************************************************************************/
|
||||
static void PrintExtBlock(GifByteType *Extension, bool Reset)
|
||||
{
|
||||
static int CrntPlace = 0;
|
||||
static long ExtCount = 0;
|
||||
static char HexForm[49], AsciiForm[17];
|
||||
|
||||
if (Reset || Extension == NULL) {
|
||||
if (Extension == NULL) {
|
||||
if (CrntPlace > 0) {
|
||||
HexForm[CrntPlace * 3] = 0;
|
||||
AsciiForm[CrntPlace] = 0;
|
||||
printf("\n%05lx: %-49s %-17s\n", ExtCount, HexForm, AsciiForm);
|
||||
return;
|
||||
}
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
CrntPlace = 0;
|
||||
ExtCount = 0;
|
||||
}
|
||||
|
||||
if (Extension != NULL) {
|
||||
int i, Len;
|
||||
Len = Extension[0];
|
||||
for (i = 1; i <= Len; i++) {
|
||||
(void)snprintf(&HexForm[CrntPlace * 3], 3,
|
||||
" %02x", Extension[i]);
|
||||
(void)snprintf(&AsciiForm[CrntPlace], 3,
|
||||
"%c", MAKE_PRINTABLE(Extension[i]));
|
||||
if (++CrntPlace == 16) {
|
||||
HexForm[CrntPlace * 3] = 0;
|
||||
AsciiForm[CrntPlace] = 0;
|
||||
printf("\n%05lx: %-49s %-17s", ExtCount, HexForm, AsciiForm);
|
||||
ExtCount += 16;
|
||||
CrntPlace = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Print the given PixelBlock of length Len.
|
||||
Save local information so printing can be performed continuously,
|
||||
or reset to start state if Reset. If PixelBlock is NULL, output is flushed
|
||||
******************************************************************************/
|
||||
static void PrintPixelBlock(GifByteType *PixelBlock, int Len, bool Reset)
|
||||
{
|
||||
static int CrntPlace = 0;
|
||||
static long ExtCount = 0;
|
||||
static char HexForm[49], AsciiForm[17];
|
||||
int i;
|
||||
|
||||
if (Reset || PixelBlock == NULL) {
|
||||
if (PixelBlock == NULL) {
|
||||
if (CrntPlace > 0) {
|
||||
HexForm[CrntPlace * 3] = 0;
|
||||
AsciiForm[CrntPlace] = 0;
|
||||
printf("\n%05lx: %-49s %-17s\n", ExtCount, HexForm, AsciiForm);
|
||||
}
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
CrntPlace = 0;
|
||||
ExtCount = 0;
|
||||
if (PixelBlock == NULL) return;
|
||||
}
|
||||
|
||||
for (i = 0; i < Len; i++) {
|
||||
(void)snprintf(&HexForm[CrntPlace * 3], 3,
|
||||
" %02x", PixelBlock[i]);
|
||||
(void)snprintf(&AsciiForm[CrntPlace], 3,
|
||||
"%c", MAKE_PRINTABLE(PixelBlock[i]));
|
||||
if (++CrntPlace == 16) {
|
||||
HexForm[CrntPlace * 3] = 0;
|
||||
AsciiForm[CrntPlace] = 0;
|
||||
printf("\n%05lx: %-49s %-17s", ExtCount, HexForm, AsciiForm);
|
||||
ExtCount += 16;
|
||||
CrntPlace = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Print the image as LZ codes (each 12bits), until EOF marker is reached.
|
||||
******************************************************************************/
|
||||
static void PrintLZCodes(GifFileType *GifFile)
|
||||
{
|
||||
int Code, CrntPlace = 0;
|
||||
long CodeCount = 0;
|
||||
|
||||
do {
|
||||
if (CrntPlace == 0) printf("\n%05lx:", CodeCount);
|
||||
if (DGifGetLZCodes(GifFile, &Code) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (Code >= 0)
|
||||
printf(" %03x", Code); /* EOF Code is returned as -1. */
|
||||
CodeCount++;
|
||||
if (++CrntPlace >= 16) CrntPlace = 0;
|
||||
}
|
||||
while (Code >= 0);
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,579 @@
|
|||
/****************************************************************************
|
||||
|
||||
giftool.c - GIF transformation tool.
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "getopt.h"
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "giftool"
|
||||
|
||||
#define MAX_OPERATIONS 256
|
||||
#define MAX_IMAGES 2048
|
||||
|
||||
enum boolmode {numeric, onoff, tf, yesno};
|
||||
|
||||
char *putbool(bool flag, enum boolmode mode)
|
||||
{
|
||||
if (flag)
|
||||
switch (mode) {
|
||||
case numeric: return "1"; break;
|
||||
case onoff: return "on"; break;
|
||||
case tf: return "true"; break;
|
||||
case yesno: return "yes"; break;
|
||||
}
|
||||
else
|
||||
switch (mode) {
|
||||
case numeric: return "0"; break;
|
||||
case onoff: return "off"; break;
|
||||
case tf: return "false"; break;
|
||||
case yesno: return "no"; break;
|
||||
}
|
||||
|
||||
return "FAIL"; /* should never happen */
|
||||
}
|
||||
|
||||
bool getbool(char *from)
|
||||
{
|
||||
struct valmap {char *name; bool val;}
|
||||
boolnames[] = {
|
||||
{"yes", true},
|
||||
{"on", true},
|
||||
{"1", true},
|
||||
{"t", true},
|
||||
{"no", false},
|
||||
{"off", false},
|
||||
{"0", false},
|
||||
{"f", false},
|
||||
{NULL, false},
|
||||
}, *sp;
|
||||
|
||||
for (sp = boolnames; sp->name; sp++)
|
||||
if (strcmp(sp->name, from) == 0)
|
||||
return sp->val;
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"giftool: %s is not a valid boolean argument.\n",
|
||||
sp->name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct operation {
|
||||
enum {
|
||||
aspect,
|
||||
delaytime,
|
||||
background,
|
||||
info,
|
||||
interlace,
|
||||
position,
|
||||
screensize,
|
||||
transparent,
|
||||
userinput,
|
||||
disposal,
|
||||
} mode;
|
||||
union {
|
||||
GifByteType numerator;
|
||||
int delay;
|
||||
int color;
|
||||
int dispose;
|
||||
char *format;
|
||||
bool flag;
|
||||
struct {
|
||||
int x, y;
|
||||
} p;
|
||||
};
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
extern char *optarg; /* set by getopt */
|
||||
extern int optind; /* set by getopt */
|
||||
struct operation operations[MAX_OPERATIONS];
|
||||
struct operation *top = operations;
|
||||
int selected[MAX_IMAGES], nselected = 0;
|
||||
bool have_selection = false;
|
||||
char *cp;
|
||||
int i, status, ErrorCode;
|
||||
GifFileType *GifFileIn, *GifFileOut = (GifFileType *)NULL;
|
||||
struct operation *op;
|
||||
|
||||
/*
|
||||
* Gather operations from the command line. We use regular
|
||||
* getopt(3) here rather than Gershom's argument getter because
|
||||
* preserving the order of operations is important.
|
||||
*/
|
||||
while ((status = getopt(argc, argv, "a:b:d:f:i:n:p:s:u:x:")) != EOF)
|
||||
{
|
||||
if (top >= operations + MAX_OPERATIONS) {
|
||||
(void)fprintf(stderr, "giftool: too many operations.");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
switch (status)
|
||||
{
|
||||
case 'a':
|
||||
top->mode = aspect;
|
||||
top->numerator = (GifByteType)atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
top->mode = background;
|
||||
top->color = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
top->mode = delaytime;
|
||||
top->delay = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
top->mode = info;
|
||||
top->format = optarg;
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
top->mode = interlace;
|
||||
top->flag = getbool(optarg);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
have_selection = true;
|
||||
nselected = 0;
|
||||
cp = optarg;
|
||||
for (;;)
|
||||
{
|
||||
size_t span = strspn(cp, "0123456789");
|
||||
|
||||
if (span > 0)
|
||||
{
|
||||
selected[nselected++] = atoi(cp)-1;
|
||||
cp += span;
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
else if (*cp == ',')
|
||||
continue;
|
||||
}
|
||||
|
||||
(void) fprintf(stderr, "giftool: bad selection.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
case 's':
|
||||
if (status == 'p')
|
||||
top->mode = position;
|
||||
else
|
||||
top->mode = screensize;
|
||||
cp = strchr(optarg, ',');
|
||||
if (cp == NULL)
|
||||
{
|
||||
(void) fprintf(stderr, "giftool: missing comma in coordinate pair.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
top->p.x = atoi(optarg);
|
||||
top->p.y = atoi(cp+1);
|
||||
if (top->p.x < 0 || top->p.y < 0)
|
||||
{
|
||||
(void) fprintf(stderr, "giftool: negative coordinate.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
top->mode = userinput;
|
||||
top->flag = getbool(optarg);
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
top->mode = disposal;
|
||||
top->dispose = atoi(optarg);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "usage: giftool [-b color] [-d delay] [-iI] [-t color] -[uU] [-x disposal]\n");
|
||||
break;
|
||||
}
|
||||
|
||||
++top;
|
||||
}
|
||||
|
||||
/* read in a GIF */
|
||||
if ((GifFileIn = DGifOpenFileHandle(0, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (DGifSlurp(GifFileIn) == GIF_ERROR) {
|
||||
PrintGifError(GifFileIn->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if ((GifFileOut = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* if the selection is defaulted, compute it; otherwise bounds-check it */
|
||||
if (!have_selection)
|
||||
for (i = nselected = 0; i < GifFileIn->ImageCount; i++)
|
||||
selected[nselected++] = i;
|
||||
else
|
||||
for (i = 0; i < nselected; i++)
|
||||
if (selected[i] >= GifFileIn->ImageCount || selected[i] < 0)
|
||||
{
|
||||
(void) fprintf(stderr,
|
||||
"giftool: selection index out of bounds.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* perform the operations we've gathered */
|
||||
for (op = operations; op < top; op++)
|
||||
switch (op->mode)
|
||||
{
|
||||
case background:
|
||||
GifFileIn->SBackGroundColor = op->color;
|
||||
break;
|
||||
|
||||
case delaytime:
|
||||
for (i = 0; i < nselected; i++)
|
||||
{
|
||||
GraphicsControlBlock gcb;
|
||||
|
||||
DGifSavedExtensionToGCB(GifFileIn, selected[i], &gcb);
|
||||
gcb.DelayTime = op->delay;
|
||||
EGifGCBToSavedExtension(&gcb, GifFileIn, selected[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case info:
|
||||
for (i = 0; i < nselected; i++) {
|
||||
SavedImage *ip = &GifFileIn->SavedImages[selected[i]];
|
||||
GraphicsControlBlock gcb;
|
||||
for (cp = op->format; *cp; cp++) {
|
||||
if (*cp == '\\')
|
||||
{
|
||||
char c;
|
||||
switch (*++cp)
|
||||
{
|
||||
case 'b':
|
||||
(void)putchar('\b');
|
||||
break;
|
||||
case 'e':
|
||||
(void)putchar(0x1b);
|
||||
break;
|
||||
case 'f':
|
||||
(void)putchar('\f');
|
||||
break;
|
||||
case 'n':
|
||||
(void)putchar('\n');
|
||||
break;
|
||||
case 'r':
|
||||
(void)putchar('\r');
|
||||
break;
|
||||
case 't':
|
||||
(void)putchar('\t');
|
||||
break;
|
||||
case 'v':
|
||||
(void)putchar('\v');
|
||||
break;
|
||||
case 'x':
|
||||
switch (*++cp) {
|
||||
case '0':
|
||||
c = (char)0x00;
|
||||
break;
|
||||
case '1':
|
||||
c = (char)0x10;
|
||||
break;
|
||||
case '2':
|
||||
c = (char)0x20;
|
||||
break;
|
||||
case '3':
|
||||
c = (char)0x30;
|
||||
break;
|
||||
case '4':
|
||||
c = (char)0x40;
|
||||
break;
|
||||
case '5':
|
||||
c = (char)0x50;
|
||||
break;
|
||||
case '6':
|
||||
c = (char)0x60;
|
||||
break;
|
||||
case '7':
|
||||
c = (char)0x70;
|
||||
break;
|
||||
case '8':
|
||||
c = (char)0x80;
|
||||
break;
|
||||
case '9':
|
||||
c = (char)0x90;
|
||||
break;
|
||||
case 'A':
|
||||
case 'a':
|
||||
c = (char)0xa0;
|
||||
break;
|
||||
case 'B':
|
||||
case 'b':
|
||||
c = (char)0xb0;
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
c = (char)0xc0;
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
c = (char)0xd0;
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
c = (char)0xe0;
|
||||
break;
|
||||
case 'F':
|
||||
case 'f':
|
||||
c = (char)0xf0;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
switch (*++cp) {
|
||||
case '0':
|
||||
c += 0x00;
|
||||
break;
|
||||
case '1':
|
||||
c += 0x01;
|
||||
break;
|
||||
case '2':
|
||||
c += 0x02;
|
||||
break;
|
||||
case '3':
|
||||
c += 0x03;
|
||||
break;
|
||||
case '4':
|
||||
c += 0x04;
|
||||
break;
|
||||
case '5':
|
||||
c += 0x05;
|
||||
break;
|
||||
case '6':
|
||||
c += 0x06;
|
||||
break;
|
||||
case '7':
|
||||
c += 0x07;
|
||||
break;
|
||||
case '8':
|
||||
c += 0x08;
|
||||
break;
|
||||
case '9':
|
||||
c += 0x09;
|
||||
break;
|
||||
case 'A':
|
||||
case 'a':
|
||||
c += 0x0a;
|
||||
break;
|
||||
case 'B':
|
||||
case 'b':
|
||||
c += 0x0b;
|
||||
break;
|
||||
case 'C':
|
||||
case 'c':
|
||||
c += 0x0c;
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
c += 0x0d;
|
||||
break;
|
||||
case 'E':
|
||||
case 'e':
|
||||
c += 0x0e;
|
||||
break;
|
||||
case 'F':
|
||||
case 'f':
|
||||
c += 0x0f;
|
||||
break;
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
putchar(c);
|
||||
break;
|
||||
default:
|
||||
putchar(*cp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (*cp == '%')
|
||||
{
|
||||
enum boolmode boolfmt;
|
||||
SavedImage *sp = &GifFileIn->SavedImages[i];
|
||||
|
||||
if (cp[1] == 't') {
|
||||
boolfmt = tf;
|
||||
++cp;
|
||||
} else if (cp[1] == 'o') {
|
||||
boolfmt = onoff;
|
||||
++cp;
|
||||
} else if (cp[1] == 'y') {
|
||||
boolfmt = yesno;
|
||||
++cp;
|
||||
} else if (cp[1] == '1') {
|
||||
boolfmt = numeric;
|
||||
++cp;
|
||||
} else
|
||||
boolfmt = numeric;
|
||||
|
||||
switch (*++cp)
|
||||
{
|
||||
case '%':
|
||||
putchar('%');
|
||||
break;
|
||||
case 'a':
|
||||
(void)printf("%d", GifFileIn->AspectByte);
|
||||
break;
|
||||
case 'b':
|
||||
(void)printf("%d", GifFileIn->SBackGroundColor);
|
||||
break;
|
||||
case 'd':
|
||||
DGifSavedExtensionToGCB(GifFileIn,
|
||||
selected[i],
|
||||
&gcb);
|
||||
(void)printf("%d", gcb.DelayTime);
|
||||
break;
|
||||
case 'h':
|
||||
(void)printf("%d", ip->ImageDesc.Height);
|
||||
break;
|
||||
case 'n':
|
||||
(void)printf("%d", selected[i]+1);
|
||||
break;
|
||||
case 'p':
|
||||
(void)printf("%d,%d",
|
||||
ip->ImageDesc.Left, ip->ImageDesc.Top);
|
||||
break;
|
||||
case 's':
|
||||
(void)printf("%d,%d",
|
||||
GifFileIn->SWidth,
|
||||
GifFileIn->SHeight);
|
||||
break;
|
||||
case 'w':
|
||||
(void)printf("%d", ip->ImageDesc.Width);
|
||||
break;
|
||||
case 't':
|
||||
DGifSavedExtensionToGCB(GifFileIn,
|
||||
selected[i],
|
||||
&gcb);
|
||||
(void)printf("%d", gcb.TransparentColor);
|
||||
break;
|
||||
case 'u':
|
||||
DGifSavedExtensionToGCB(GifFileIn,
|
||||
selected[i],
|
||||
&gcb);
|
||||
(void)printf("%s", putbool(gcb.UserInputFlag, boolfmt));
|
||||
break;
|
||||
case 'v':
|
||||
fputs(EGifGetGifVersion(GifFileIn), stdout);
|
||||
break;
|
||||
case 'x':
|
||||
DGifSavedExtensionToGCB(GifFileIn,
|
||||
selected[i],
|
||||
&gcb);
|
||||
(void)printf("%d", gcb.DisposalMode);
|
||||
break;
|
||||
case 'z':
|
||||
(void) printf("%s", putbool(sp->ImageDesc.ColorMap && sp->ImageDesc.ColorMap->SortFlag, boolfmt));
|
||||
break;
|
||||
default:
|
||||
(void)fprintf(stderr,
|
||||
"giftool: bad format %%%c\n", *cp);
|
||||
}
|
||||
}
|
||||
else
|
||||
(void)putchar(*cp);
|
||||
}
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
case interlace:
|
||||
for (i = 0; i < nselected; i++)
|
||||
GifFileIn->SavedImages[selected[i]].ImageDesc.Interlace = op->flag;
|
||||
break;
|
||||
|
||||
case position:
|
||||
for (i = 0; i < nselected; i++) {
|
||||
GifFileIn->SavedImages[selected[i]].ImageDesc.Left = op->p.x;
|
||||
GifFileIn->SavedImages[selected[i]].ImageDesc.Top = op->p.y;
|
||||
}
|
||||
break;
|
||||
|
||||
case screensize:
|
||||
GifFileIn->SWidth = op->p.x;
|
||||
GifFileIn->SHeight = op->p.y;
|
||||
break;
|
||||
|
||||
case transparent:
|
||||
for (i = 0; i < nselected; i++)
|
||||
{
|
||||
GraphicsControlBlock gcb;
|
||||
|
||||
DGifSavedExtensionToGCB(GifFileIn, selected[i], &gcb);
|
||||
gcb.TransparentColor = op->color;
|
||||
EGifGCBToSavedExtension(&gcb, GifFileIn, selected[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case userinput:
|
||||
for (i = 0; i < nselected; i++)
|
||||
{
|
||||
GraphicsControlBlock gcb;
|
||||
|
||||
DGifSavedExtensionToGCB(GifFileIn, selected[i], &gcb);
|
||||
gcb.UserInputFlag = op->flag;
|
||||
EGifGCBToSavedExtension(&gcb, GifFileIn, selected[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case disposal:
|
||||
for (i = 0; i < nselected; i++)
|
||||
{
|
||||
GraphicsControlBlock gcb;
|
||||
|
||||
DGifSavedExtensionToGCB(GifFileIn, selected[i], &gcb);
|
||||
gcb.DisposalMode = op->dispose;
|
||||
EGifGCBToSavedExtension(&gcb, GifFileIn, selected[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
(void)fprintf(stderr, "giftool: unknown operation mode\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* write out the results */
|
||||
GifFileOut->SWidth = GifFileIn->SWidth;
|
||||
GifFileOut->SHeight = GifFileIn->SHeight;
|
||||
GifFileOut->SColorResolution = GifFileIn->SColorResolution;
|
||||
GifFileOut->SBackGroundColor = GifFileIn->SBackGroundColor;
|
||||
if (GifFileIn->SColorMap != NULL)
|
||||
GifFileOut->SColorMap = GifMakeMapObject(
|
||||
GifFileIn->SColorMap->ColorCount,
|
||||
GifFileIn->SColorMap->Colors);
|
||||
|
||||
for (i = 0; i < GifFileIn->ImageCount; i++)
|
||||
(void) GifMakeSavedImage(GifFileOut, &GifFileIn->SavedImages[i]);
|
||||
|
||||
if (EGifSpew(GifFileOut) == GIF_ERROR)
|
||||
PrintGifError(GifFileOut->Error);
|
||||
else if (DGifCloseFile(GifFileIn, &ErrorCode) == GIF_ERROR)
|
||||
PrintGifError(ErrorCode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,143 @@
|
|||
/*****************************************************************************
|
||||
|
||||
gifwedge - create a GIF test pattern
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
#include "getarg.h"
|
||||
|
||||
#define PROGRAM_NAME "gifwedge"
|
||||
|
||||
#define DEFAULT_WIDTH 640
|
||||
#define DEFAULT_HEIGHT 350
|
||||
|
||||
#define DEFAULT_NUM_LEVELS 16 /* Number of colors to gen the image. */
|
||||
|
||||
static char
|
||||
*VersionStr =
|
||||
PROGRAM_NAME
|
||||
VERSION_COOKIE
|
||||
" Gershon Elber, "
|
||||
__DATE__ ", " __TIME__ "\n"
|
||||
"(C) Copyright 1989 Gershon Elber.\n";
|
||||
static char
|
||||
*CtrlStr =
|
||||
PROGRAM_NAME
|
||||
" v%- l%-#Lvls!d s%-Width|Height!d!d h%-";
|
||||
|
||||
static int
|
||||
NumLevels = DEFAULT_NUM_LEVELS,
|
||||
ImageWidth = DEFAULT_WIDTH,
|
||||
ImageHeight = DEFAULT_HEIGHT;
|
||||
|
||||
/******************************************************************************
|
||||
Interpret the command line and scan the given GIF file.
|
||||
******************************************************************************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, j, l, c, LevelStep, LogNumLevels, ErrorCode, Count = 0;
|
||||
bool Error, LevelsFlag = false, SizeFlag = false, HelpFlag = false;
|
||||
GifRowType Line;
|
||||
ColorMapObject *ColorMap;
|
||||
GifFileType *GifFile;
|
||||
|
||||
if ((Error = GAGetArgs(argc, argv, CtrlStr,
|
||||
&GifNoisyPrint, &LevelsFlag, &NumLevels,
|
||||
&SizeFlag, &ImageWidth, &ImageHeight,
|
||||
&HelpFlag)) != false) {
|
||||
GAPrintErrMsg(Error);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (HelpFlag) {
|
||||
(void)fprintf(stderr, VersionStr, GIFLIB_MAJOR, GIFLIB_MINOR);
|
||||
GAPrintHowTo(CtrlStr);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* Make sure the number of levels is power of 2 (up to 32 levels.). */
|
||||
for (i = 1; i < 6; i++) if (NumLevels == (1 << i)) break;
|
||||
if (i == 6) GIF_EXIT("#Lvls (-l option) is not power of 2 up to 32.");
|
||||
LogNumLevels = i + 3; /* Multiple by 8 (see below). */
|
||||
LevelStep = 256 / NumLevels;
|
||||
|
||||
/* Make sure the image dimension is a multiple of NumLevels horizontally */
|
||||
/* and 7 (White, Red, Green, Blue and Yellow Cyan Magenta) vertically. */
|
||||
ImageWidth = (ImageWidth / NumLevels) * NumLevels;
|
||||
ImageHeight = (ImageHeight / 7) * 7;
|
||||
|
||||
/* Open stdout for the output file: */
|
||||
if ((GifFile = EGifOpenFileHandle(1, &ErrorCode)) == NULL) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Dump out screen description with given size and generated color map: */
|
||||
/* The color map has 7 NumLevels colors for White, Red, Green and then */
|
||||
/* The secondary colors Yellow Cyan and magenta. */
|
||||
if ((ColorMap = GifMakeMapObject(8 * NumLevels, NULL)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
for (i = 0; i < 8; i++) /* Set color map. */
|
||||
for (j = 0; j < NumLevels; j++) {
|
||||
l = LevelStep * j;
|
||||
c = i * NumLevels + j;
|
||||
ColorMap->Colors[c].Red = (i == 0 || i == 1 || i == 4 || i == 6) * l;
|
||||
ColorMap->Colors[c].Green = (i == 0 || i == 2 || i == 4 || i == 5) * l;
|
||||
ColorMap->Colors[c].Blue = (i == 0 || i == 3 || i == 5 || i == 6) * l;
|
||||
}
|
||||
|
||||
if (EGifPutScreenDesc(GifFile, ImageWidth, ImageHeight, LogNumLevels, 0, ColorMap) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
}
|
||||
|
||||
/* Dump out the image descriptor: */
|
||||
if (EGifPutImageDesc(GifFile,
|
||||
0, 0, ImageWidth, ImageHeight,
|
||||
false, NULL) == GIF_ERROR) {
|
||||
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
GifQprintf("\n%s: Image 1 at (%d, %d) [%dx%d]: ",
|
||||
PROGRAM_NAME, GifFile->Image.Left, GifFile->Image.Top,
|
||||
GifFile->Image.Width, GifFile->Image.Height);
|
||||
|
||||
/* Allocate one scan line to be used for all image. */
|
||||
if ((Line = (GifRowType) malloc(sizeof(GifPixelType) * ImageWidth)) == NULL)
|
||||
GIF_EXIT("Failed to allocate memory required, aborted.");
|
||||
|
||||
/* Dump the pixels: */
|
||||
for (c = 0; c < 7; c++) {
|
||||
for (i = 0, l = 0; i < NumLevels; i++)
|
||||
for (j = 0; j < ImageWidth / NumLevels; j++)
|
||||
Line[l++] = i + NumLevels * c;
|
||||
for (i = 0; i < ImageHeight / 7; i++) {
|
||||
if (EGifPutLine(GifFile, Line, ImageWidth) == GIF_ERROR) {
|
||||
PrintGifError(GifFile->Error);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
GifQprintf("\b\b\b\b%-4d", Count++);
|
||||
}
|
||||
}
|
||||
|
||||
if (EGifCloseFile(GifFile, &ErrorCode) == GIF_ERROR) {
|
||||
PrintGifError(ErrorCode);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
#define SIZE_MAX UINTPTR_MAX
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
|
||||
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
|
||||
*/
|
||||
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
|
||||
|
||||
void *
|
||||
openbsd_reallocarray(void *optr, size_t nmemb, size_t size)
|
||||
{
|
||||
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
|
||||
nmemb > 0 && SIZE_MAX / nmemb < size) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Head off variations in realloc behavior on different
|
||||
* platforms (reported by MarkR <mrogers6@users.sf.net>)
|
||||
*
|
||||
* The behaviour of reallocarray is implementation-defined if
|
||||
* nmemb or size is zero. It can return NULL or non-NULL
|
||||
* depending on the platform.
|
||||
* https://www.securecoding.cert.org/confluence/display/c/MEM04-C.Beware+of+zero-lengthallocations
|
||||
*
|
||||
* Here are some extracts from realloc man pages on different platforms.
|
||||
*
|
||||
* void realloc( void memblock, size_t size );
|
||||
*
|
||||
* Windows:
|
||||
*
|
||||
* If there is not enough available memory to expand the block
|
||||
* to the given size, the original block is left unchanged,
|
||||
* and NULL is returned. If size is zero, then the block
|
||||
* pointed to by memblock is freed; the return value is NULL,
|
||||
* and memblock is left pointing at a freed block.
|
||||
*
|
||||
* OpenBSD:
|
||||
*
|
||||
* If size or nmemb is equal to 0, a unique pointer to an
|
||||
* access protected, zero sized object is returned. Access via
|
||||
* this pointer will generate a SIGSEGV exception.
|
||||
*
|
||||
* Linux:
|
||||
*
|
||||
* If size was equal to 0, either NULL or a pointer suitable
|
||||
* to be passed to free() is returned.
|
||||
*
|
||||
* OS X:
|
||||
*
|
||||
* If size is zero and ptr is not NULL, a new, minimum sized
|
||||
* object is allocated and the original object is freed.
|
||||
*
|
||||
* It looks like images with zero width or height can trigger
|
||||
* this, and fuzzing behaviour will differ by platform, so
|
||||
* fuzzing on one platform may not detect zero-size allocation
|
||||
* problems on other platforms.
|
||||
*/
|
||||
if (size == 0 || nmemb == 0)
|
||||
return NULL;
|
||||
return realloc(optr, size * nmemb);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*****************************************************************************
|
||||
|
||||
qprintf.c - module to emulate a printf with a possible quiet (disable mode.)
|
||||
|
||||
A global variable GifNoisyPrint controls the printing of this routine
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "gif_lib.h"
|
||||
|
||||
bool GifNoisyPrint = false;
|
||||
|
||||
/*****************************************************************************
|
||||
Same as fprintf to stderr but with optional print.
|
||||
******************************************************************************/
|
||||
void
|
||||
GifQprintf(char *Format, ...) {
|
||||
va_list ArgPtr;
|
||||
|
||||
va_start(ArgPtr, Format);
|
||||
|
||||
if (GifNoisyPrint) {
|
||||
char Line[128];
|
||||
(void)vsnprintf(Line, sizeof(Line), Format, ArgPtr);
|
||||
(void)fputs(Line, stderr);
|
||||
}
|
||||
|
||||
va_end(ArgPtr);
|
||||
}
|
||||
|
||||
void
|
||||
PrintGifError(int ErrorCode) {
|
||||
const char *Err = GifErrorString(ErrorCode);
|
||||
|
||||
if (Err != NULL)
|
||||
fprintf(stderr, "GIF-LIB error: %s.\n", Err);
|
||||
else
|
||||
fprintf(stderr, "GIF-LIB undefined error %d.\n", ErrorCode);
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,332 @@
|
|||
/*****************************************************************************
|
||||
|
||||
quantize.c - quantize a high resolution image into lower one
|
||||
|
||||
Based on: "Color Image Quantization for frame buffer Display", by
|
||||
Paul Heckbert SIGGRAPH 1982 page 297-307.
|
||||
|
||||
This doesn't really belong in the core library, was undocumented,
|
||||
and was removed in 4.2. Then it turned out some client apps were
|
||||
actually using it, so it was restored in 5.0.
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "gif_lib.h"
|
||||
#include "gif_lib_private.h"
|
||||
|
||||
#define ABS(x) ((x) > 0 ? (x) : (-(x)))
|
||||
|
||||
#define COLOR_ARRAY_SIZE 32768
|
||||
#define BITS_PER_PRIM_COLOR 5
|
||||
#define MAX_PRIM_COLOR 0x1f
|
||||
|
||||
static int SortRGBAxis;
|
||||
|
||||
typedef struct QuantizedColorType {
|
||||
GifByteType RGB[3];
|
||||
GifByteType NewColorIndex;
|
||||
long Count;
|
||||
struct QuantizedColorType *Pnext;
|
||||
} QuantizedColorType;
|
||||
|
||||
typedef struct NewColorMapType {
|
||||
GifByteType RGBMin[3], RGBWidth[3];
|
||||
unsigned int NumEntries; /* # of QuantizedColorType in linked list below */
|
||||
unsigned long Count; /* Total number of pixels in all the entries */
|
||||
QuantizedColorType *QuantizedColors;
|
||||
} NewColorMapType;
|
||||
|
||||
static int SubdivColorMap(NewColorMapType * NewColorSubdiv,
|
||||
unsigned int ColorMapSize,
|
||||
unsigned int *NewColorMapSize);
|
||||
static int SortCmpRtn(const void *Entry1, const void *Entry2);
|
||||
|
||||
/******************************************************************************
|
||||
Quantize high resolution image into lower one. Input image consists of a
|
||||
2D array for each of the RGB colors with size Width by Height. There is no
|
||||
Color map for the input. Output is a quantized image with 2D array of
|
||||
indexes into the output color map.
|
||||
Note input image can be 24 bits at the most (8 for red/green/blue) and
|
||||
the output has 256 colors at the most (256 entries in the color map.).
|
||||
ColorMapSize specifies size of color map up to 256 and will be updated to
|
||||
real size before returning.
|
||||
Also non of the parameter are allocated by this routine.
|
||||
This function returns GIF_OK if successful, GIF_ERROR otherwise.
|
||||
******************************************************************************/
|
||||
int
|
||||
GifQuantizeBuffer(unsigned int Width,
|
||||
unsigned int Height,
|
||||
int *ColorMapSize,
|
||||
GifByteType * RedInput,
|
||||
GifByteType * GreenInput,
|
||||
GifByteType * BlueInput,
|
||||
GifByteType * OutputBuffer,
|
||||
GifColorType * OutputColorMap) {
|
||||
|
||||
unsigned int Index, NumOfEntries;
|
||||
int i, j, MaxRGBError[3];
|
||||
unsigned int NewColorMapSize;
|
||||
long Red, Green, Blue;
|
||||
NewColorMapType NewColorSubdiv[256];
|
||||
QuantizedColorType *ColorArrayEntries, *QuantizedColor;
|
||||
|
||||
ColorArrayEntries = (QuantizedColorType *)malloc(
|
||||
sizeof(QuantizedColorType) * COLOR_ARRAY_SIZE);
|
||||
if (ColorArrayEntries == NULL) {
|
||||
return GIF_ERROR;
|
||||
}
|
||||
|
||||
for (i = 0; i < COLOR_ARRAY_SIZE; i++) {
|
||||
ColorArrayEntries[i].RGB[0] = i >> (2 * BITS_PER_PRIM_COLOR);
|
||||
ColorArrayEntries[i].RGB[1] = (i >> BITS_PER_PRIM_COLOR) &
|
||||
MAX_PRIM_COLOR;
|
||||
ColorArrayEntries[i].RGB[2] = i & MAX_PRIM_COLOR;
|
||||
ColorArrayEntries[i].Count = 0;
|
||||
}
|
||||
|
||||
/* Sample the colors and their distribution: */
|
||||
for (i = 0; i < (int)(Width * Height); i++) {
|
||||
Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||
(2 * BITS_PER_PRIM_COLOR)) +
|
||||
((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||
BITS_PER_PRIM_COLOR) +
|
||||
(BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
|
||||
ColorArrayEntries[Index].Count++;
|
||||
}
|
||||
|
||||
/* Put all the colors in the first entry of the color map, and call the
|
||||
* recursive subdivision process. */
|
||||
for (i = 0; i < 256; i++) {
|
||||
NewColorSubdiv[i].QuantizedColors = NULL;
|
||||
NewColorSubdiv[i].Count = NewColorSubdiv[i].NumEntries = 0;
|
||||
for (j = 0; j < 3; j++) {
|
||||
NewColorSubdiv[i].RGBMin[j] = 0;
|
||||
NewColorSubdiv[i].RGBWidth[j] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the non empty entries in the color table and chain them: */
|
||||
for (i = 0; i < COLOR_ARRAY_SIZE; i++)
|
||||
if (ColorArrayEntries[i].Count > 0)
|
||||
break;
|
||||
QuantizedColor = NewColorSubdiv[0].QuantizedColors = &ColorArrayEntries[i];
|
||||
NumOfEntries = 1;
|
||||
while (++i < COLOR_ARRAY_SIZE)
|
||||
if (ColorArrayEntries[i].Count > 0) {
|
||||
QuantizedColor->Pnext = &ColorArrayEntries[i];
|
||||
QuantizedColor = &ColorArrayEntries[i];
|
||||
NumOfEntries++;
|
||||
}
|
||||
QuantizedColor->Pnext = NULL;
|
||||
|
||||
NewColorSubdiv[0].NumEntries = NumOfEntries; /* Different sampled colors */
|
||||
NewColorSubdiv[0].Count = ((long)Width) * Height; /* Pixels */
|
||||
NewColorMapSize = 1;
|
||||
if (SubdivColorMap(NewColorSubdiv, *ColorMapSize, &NewColorMapSize) !=
|
||||
GIF_OK) {
|
||||
free((char *)ColorArrayEntries);
|
||||
return GIF_ERROR;
|
||||
}
|
||||
if (NewColorMapSize < *ColorMapSize) {
|
||||
/* And clear rest of color map: */
|
||||
for (i = NewColorMapSize; i < *ColorMapSize; i++)
|
||||
OutputColorMap[i].Red = OutputColorMap[i].Green =
|
||||
OutputColorMap[i].Blue = 0;
|
||||
}
|
||||
|
||||
/* Average the colors in each entry to be the color to be used in the
|
||||
* output color map, and plug it into the output color map itself. */
|
||||
for (i = 0; i < NewColorMapSize; i++) {
|
||||
if ((j = NewColorSubdiv[i].NumEntries) > 0) {
|
||||
QuantizedColor = NewColorSubdiv[i].QuantizedColors;
|
||||
Red = Green = Blue = 0;
|
||||
while (QuantizedColor) {
|
||||
QuantizedColor->NewColorIndex = i;
|
||||
Red += QuantizedColor->RGB[0];
|
||||
Green += QuantizedColor->RGB[1];
|
||||
Blue += QuantizedColor->RGB[2];
|
||||
QuantizedColor = QuantizedColor->Pnext;
|
||||
}
|
||||
OutputColorMap[i].Red = (Red << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||
OutputColorMap[i].Green = (Green << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||
OutputColorMap[i].Blue = (Blue << (8 - BITS_PER_PRIM_COLOR)) / j;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finally scan the input buffer again and put the mapped index in the
|
||||
* output buffer. */
|
||||
MaxRGBError[0] = MaxRGBError[1] = MaxRGBError[2] = 0;
|
||||
for (i = 0; i < (int)(Width * Height); i++) {
|
||||
Index = ((RedInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||
(2 * BITS_PER_PRIM_COLOR)) +
|
||||
((GreenInput[i] >> (8 - BITS_PER_PRIM_COLOR)) <<
|
||||
BITS_PER_PRIM_COLOR) +
|
||||
(BlueInput[i] >> (8 - BITS_PER_PRIM_COLOR));
|
||||
Index = ColorArrayEntries[Index].NewColorIndex;
|
||||
OutputBuffer[i] = Index;
|
||||
if (MaxRGBError[0] < ABS(OutputColorMap[Index].Red - RedInput[i]))
|
||||
MaxRGBError[0] = ABS(OutputColorMap[Index].Red - RedInput[i]);
|
||||
if (MaxRGBError[1] < ABS(OutputColorMap[Index].Green - GreenInput[i]))
|
||||
MaxRGBError[1] = ABS(OutputColorMap[Index].Green - GreenInput[i]);
|
||||
if (MaxRGBError[2] < ABS(OutputColorMap[Index].Blue - BlueInput[i]))
|
||||
MaxRGBError[2] = ABS(OutputColorMap[Index].Blue - BlueInput[i]);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,
|
||||
"Quantization L(0) errors: Red = %d, Green = %d, Blue = %d.\n",
|
||||
MaxRGBError[0], MaxRGBError[1], MaxRGBError[2]);
|
||||
#endif /* DEBUG */
|
||||
|
||||
free((char *)ColorArrayEntries);
|
||||
|
||||
*ColorMapSize = NewColorMapSize;
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
Routine to subdivide the RGB space recursively using median cut in each
|
||||
axes alternatingly until ColorMapSize different cubes exists.
|
||||
The biggest cube in one dimension is subdivide unless it has only one entry.
|
||||
Returns GIF_ERROR if failed, otherwise GIF_OK.
|
||||
*******************************************************************************/
|
||||
static int
|
||||
SubdivColorMap(NewColorMapType * NewColorSubdiv,
|
||||
unsigned int ColorMapSize,
|
||||
unsigned int *NewColorMapSize) {
|
||||
|
||||
unsigned int i, j, Index = 0;
|
||||
QuantizedColorType *QuantizedColor, **SortArray;
|
||||
|
||||
while (ColorMapSize > *NewColorMapSize) {
|
||||
/* Find candidate for subdivision: */
|
||||
long Sum, Count;
|
||||
int MaxSize = -1;
|
||||
unsigned int NumEntries, MinColor, MaxColor;
|
||||
for (i = 0; i < *NewColorMapSize; i++) {
|
||||
for (j = 0; j < 3; j++) {
|
||||
if ((((int)NewColorSubdiv[i].RGBWidth[j]) > MaxSize) &&
|
||||
(NewColorSubdiv[i].NumEntries > 1)) {
|
||||
MaxSize = NewColorSubdiv[i].RGBWidth[j];
|
||||
Index = i;
|
||||
SortRGBAxis = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (MaxSize == -1)
|
||||
return GIF_OK;
|
||||
|
||||
/* Split the entry Index into two along the axis SortRGBAxis: */
|
||||
|
||||
/* Sort all elements in that entry along the given axis and split at
|
||||
* the median. */
|
||||
SortArray = (QuantizedColorType **)malloc(
|
||||
sizeof(QuantizedColorType *) *
|
||||
NewColorSubdiv[Index].NumEntries);
|
||||
if (SortArray == NULL)
|
||||
return GIF_ERROR;
|
||||
for (j = 0, QuantizedColor = NewColorSubdiv[Index].QuantizedColors;
|
||||
j < NewColorSubdiv[Index].NumEntries && QuantizedColor != NULL;
|
||||
j++, QuantizedColor = QuantizedColor->Pnext)
|
||||
SortArray[j] = QuantizedColor;
|
||||
|
||||
/*
|
||||
* Because qsort isn't stable, this can produce differing
|
||||
* results for the order of tuples depending on platform
|
||||
* details of how qsort() is implemented.
|
||||
*
|
||||
* We mitigate this problem by sorting on all three axes rather
|
||||
* than only the one specied by SortRGBAxis; that way the instability
|
||||
* can only become an issue if there are multiple color indices
|
||||
* referring to identical RGB tuples. Older versions of this
|
||||
* sorted on only the one axis.
|
||||
*/
|
||||
qsort(SortArray, NewColorSubdiv[Index].NumEntries,
|
||||
sizeof(QuantizedColorType *), SortCmpRtn);
|
||||
|
||||
/* Relink the sorted list into one: */
|
||||
for (j = 0; j < NewColorSubdiv[Index].NumEntries - 1; j++)
|
||||
SortArray[j]->Pnext = SortArray[j + 1];
|
||||
SortArray[NewColorSubdiv[Index].NumEntries - 1]->Pnext = NULL;
|
||||
NewColorSubdiv[Index].QuantizedColors = QuantizedColor = SortArray[0];
|
||||
free((char *)SortArray);
|
||||
|
||||
/* Now simply add the Counts until we have half of the Count: */
|
||||
Sum = NewColorSubdiv[Index].Count / 2 - QuantizedColor->Count;
|
||||
NumEntries = 1;
|
||||
Count = QuantizedColor->Count;
|
||||
while (QuantizedColor->Pnext != NULL &&
|
||||
(Sum -= QuantizedColor->Pnext->Count) >= 0 &&
|
||||
QuantizedColor->Pnext->Pnext != NULL) {
|
||||
QuantizedColor = QuantizedColor->Pnext;
|
||||
NumEntries++;
|
||||
Count += QuantizedColor->Count;
|
||||
}
|
||||
/* Save the values of the last color of the first half, and first
|
||||
* of the second half so we can update the Bounding Boxes later.
|
||||
* Also as the colors are quantized and the BBoxes are full 0..255,
|
||||
* they need to be rescaled.
|
||||
*/
|
||||
MaxColor = QuantizedColor->RGB[SortRGBAxis]; /* Max. of first half */
|
||||
/* coverity[var_deref_op] */
|
||||
MinColor = QuantizedColor->Pnext->RGB[SortRGBAxis]; /* of second */
|
||||
MaxColor <<= (8 - BITS_PER_PRIM_COLOR);
|
||||
MinColor <<= (8 - BITS_PER_PRIM_COLOR);
|
||||
|
||||
/* Partition right here: */
|
||||
NewColorSubdiv[*NewColorMapSize].QuantizedColors =
|
||||
QuantizedColor->Pnext;
|
||||
QuantizedColor->Pnext = NULL;
|
||||
NewColorSubdiv[*NewColorMapSize].Count = Count;
|
||||
NewColorSubdiv[Index].Count -= Count;
|
||||
NewColorSubdiv[*NewColorMapSize].NumEntries =
|
||||
NewColorSubdiv[Index].NumEntries - NumEntries;
|
||||
NewColorSubdiv[Index].NumEntries = NumEntries;
|
||||
for (j = 0; j < 3; j++) {
|
||||
NewColorSubdiv[*NewColorMapSize].RGBMin[j] =
|
||||
NewColorSubdiv[Index].RGBMin[j];
|
||||
NewColorSubdiv[*NewColorMapSize].RGBWidth[j] =
|
||||
NewColorSubdiv[Index].RGBWidth[j];
|
||||
}
|
||||
NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] =
|
||||
NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] +
|
||||
NewColorSubdiv[*NewColorMapSize].RGBWidth[SortRGBAxis] - MinColor;
|
||||
NewColorSubdiv[*NewColorMapSize].RGBMin[SortRGBAxis] = MinColor;
|
||||
|
||||
NewColorSubdiv[Index].RGBWidth[SortRGBAxis] =
|
||||
MaxColor - NewColorSubdiv[Index].RGBMin[SortRGBAxis];
|
||||
|
||||
(*NewColorMapSize)++;
|
||||
}
|
||||
|
||||
return GIF_OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Routine called by qsort to compare two entries.
|
||||
*****************************************************************************/
|
||||
|
||||
static int
|
||||
SortCmpRtn(const void *Entry1,
|
||||
const void *Entry2) {
|
||||
QuantizedColorType *entry1 = (*((QuantizedColorType **) Entry1));
|
||||
QuantizedColorType *entry2 = (*((QuantizedColorType **) Entry2));
|
||||
|
||||
/* sort on all axes of the color space! */
|
||||
int hash1 = entry1->RGB[SortRGBAxis] * 256 * 256
|
||||
+ entry1->RGB[(SortRGBAxis+1) % 3] * 256
|
||||
+ entry1->RGB[(SortRGBAxis+2) % 3];
|
||||
int hash2 = entry2->RGB[SortRGBAxis] * 256 * 256
|
||||
+ entry2->RGB[(SortRGBAxis+1) % 3] * 256
|
||||
+ entry2->RGB[(SortRGBAxis+2) % 3];
|
||||
|
||||
return hash1 - hash2;
|
||||
}
|
||||
|
||||
/* end */
|
|
@ -0,0 +1,303 @@
|
|||
/******************************************************************************
|
||||
|
||||
gif_lib.h - service library for decoding and encoding GIF images
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _GIF_LIB_H_
|
||||
#define _GIF_LIB_H_ 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define GIFLIB_MAJOR 5
|
||||
#define GIFLIB_MINOR 2
|
||||
#define GIFLIB_RELEASE 1
|
||||
|
||||
#define GIF_ERROR 0
|
||||
#define GIF_OK 1
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define GIF_STAMP "GIFVER" /* First chars in file - GIF stamp. */
|
||||
#define GIF_STAMP_LEN sizeof(GIF_STAMP) - 1
|
||||
#define GIF_VERSION_POS 3 /* Version first character in stamp. */
|
||||
#define GIF87_STAMP "GIF87a" /* First chars in file - GIF stamp. */
|
||||
#define GIF89_STAMP "GIF89a" /* First chars in file - GIF stamp. */
|
||||
|
||||
typedef unsigned char GifPixelType;
|
||||
typedef unsigned char *GifRowType;
|
||||
typedef unsigned char GifByteType;
|
||||
typedef unsigned int GifPrefixType;
|
||||
typedef int GifWord;
|
||||
|
||||
typedef struct GifColorType {
|
||||
GifByteType Red, Green, Blue;
|
||||
} GifColorType;
|
||||
|
||||
typedef struct ColorMapObject {
|
||||
int ColorCount;
|
||||
int BitsPerPixel;
|
||||
bool SortFlag;
|
||||
GifColorType *Colors; /* on malloc(3) heap */
|
||||
} ColorMapObject;
|
||||
|
||||
typedef struct GifImageDesc {
|
||||
GifWord Left, Top, Width, Height; /* Current image dimensions. */
|
||||
bool Interlace; /* Sequential/Interlaced lines. */
|
||||
ColorMapObject *ColorMap; /* The local color map */
|
||||
} GifImageDesc;
|
||||
|
||||
typedef struct ExtensionBlock {
|
||||
int ByteCount;
|
||||
GifByteType *Bytes; /* on malloc(3) heap */
|
||||
int Function; /* The block function code */
|
||||
#define CONTINUE_EXT_FUNC_CODE 0x00 /* continuation subblock */
|
||||
#define COMMENT_EXT_FUNC_CODE 0xfe /* comment */
|
||||
#define GRAPHICS_EXT_FUNC_CODE 0xf9 /* graphics control (GIF89) */
|
||||
#define PLAINTEXT_EXT_FUNC_CODE 0x01 /* plaintext */
|
||||
#define APPLICATION_EXT_FUNC_CODE 0xff /* application block (GIF89) */
|
||||
} ExtensionBlock;
|
||||
|
||||
typedef struct SavedImage {
|
||||
GifImageDesc ImageDesc;
|
||||
GifByteType *RasterBits; /* on malloc(3) heap */
|
||||
int ExtensionBlockCount; /* Count of extensions before image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions before image */
|
||||
} SavedImage;
|
||||
|
||||
typedef struct GifFileType {
|
||||
GifWord SWidth, SHeight; /* Size of virtual canvas */
|
||||
GifWord SColorResolution; /* How many colors can we generate? */
|
||||
GifWord SBackGroundColor; /* Background color for virtual canvas */
|
||||
GifByteType AspectByte; /* Used to compute pixel aspect ratio */
|
||||
ColorMapObject *SColorMap; /* Global colormap, NULL if nonexistent. */
|
||||
int ImageCount; /* Number of current image (both APIs) */
|
||||
GifImageDesc Image; /* Current image (low-level API) */
|
||||
SavedImage *SavedImages; /* Image sequence (high-level API) */
|
||||
int ExtensionBlockCount; /* Count extensions past last image */
|
||||
ExtensionBlock *ExtensionBlocks; /* Extensions past last image */
|
||||
int Error; /* Last error condition reported */
|
||||
void *UserData; /* hook to attach user data (TVT) */
|
||||
void *Private; /* Don't mess with this! */
|
||||
} GifFileType;
|
||||
|
||||
#define GIF_ASPECT_RATIO(n) ((n)+15.0/64.0)
|
||||
|
||||
typedef enum {
|
||||
UNDEFINED_RECORD_TYPE,
|
||||
SCREEN_DESC_RECORD_TYPE,
|
||||
IMAGE_DESC_RECORD_TYPE, /* Begin with ',' */
|
||||
EXTENSION_RECORD_TYPE, /* Begin with '!' */
|
||||
TERMINATE_RECORD_TYPE /* Begin with ';' */
|
||||
} GifRecordType;
|
||||
|
||||
/* func type to read gif data from arbitrary sources (TVT) */
|
||||
typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
|
||||
|
||||
/* func type to write gif data to arbitrary targets.
|
||||
* Returns count of bytes written. (MRB)
|
||||
*/
|
||||
typedef int (*OutputFunc) (GifFileType *, const GifByteType *, int);
|
||||
|
||||
/******************************************************************************
|
||||
GIF89 structures
|
||||
******************************************************************************/
|
||||
|
||||
typedef struct GraphicsControlBlock {
|
||||
int DisposalMode;
|
||||
#define DISPOSAL_UNSPECIFIED 0 /* No disposal specified. */
|
||||
#define DISPOSE_DO_NOT 1 /* Leave image in place */
|
||||
#define DISPOSE_BACKGROUND 2 /* Set area too background color */
|
||||
#define DISPOSE_PREVIOUS 3 /* Restore to previous content */
|
||||
bool UserInputFlag; /* User confirmation required before disposal */
|
||||
int DelayTime; /* pre-display delay in 0.01sec units */
|
||||
int TransparentColor; /* Palette index for transparency, -1 if none */
|
||||
#define NO_TRANSPARENT_COLOR -1
|
||||
} GraphicsControlBlock;
|
||||
|
||||
/******************************************************************************
|
||||
GIF encoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *EGifOpenFileName(const char *GifFileName,
|
||||
const bool GifTestExistence, int *Error);
|
||||
GifFileType *EGifOpenFileHandle(const int GifFileHandle, int *Error);
|
||||
GifFileType *EGifOpen(void *userPtr, OutputFunc writeFunc, int *Error);
|
||||
int EGifSpew(GifFileType * GifFile);
|
||||
const char *EGifGetGifVersion(GifFileType *GifFile); /* new in 5.x */
|
||||
int EGifCloseFile(GifFileType *GifFile, int *ErrorCode);
|
||||
|
||||
#define E_GIF_SUCCEEDED 0
|
||||
#define E_GIF_ERR_OPEN_FAILED 1 /* And EGif possible errors. */
|
||||
#define E_GIF_ERR_WRITE_FAILED 2
|
||||
#define E_GIF_ERR_HAS_SCRN_DSCR 3
|
||||
#define E_GIF_ERR_HAS_IMAG_DSCR 4
|
||||
#define E_GIF_ERR_NO_COLOR_MAP 5
|
||||
#define E_GIF_ERR_DATA_TOO_BIG 6
|
||||
#define E_GIF_ERR_NOT_ENOUGH_MEM 7
|
||||
#define E_GIF_ERR_DISK_IS_FULL 8
|
||||
#define E_GIF_ERR_CLOSE_FAILED 9
|
||||
#define E_GIF_ERR_NOT_WRITEABLE 10
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int EGifPutScreenDesc(GifFileType *GifFile,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const int GifColorRes,
|
||||
const int GifBackGround,
|
||||
const ColorMapObject *GifColorMap);
|
||||
int EGifPutImageDesc(GifFileType *GifFile,
|
||||
const int GifLeft, const int GifTop,
|
||||
const int GifWidth, const int GifHeight,
|
||||
const bool GifInterlace,
|
||||
const ColorMapObject *GifColorMap);
|
||||
void EGifSetGifVersion(GifFileType *GifFile, const bool gif89);
|
||||
int EGifPutLine(GifFileType *GifFile, GifPixelType *GifLine,
|
||||
int GifLineLen);
|
||||
int EGifPutPixel(GifFileType *GifFile, const GifPixelType GifPixel);
|
||||
int EGifPutComment(GifFileType *GifFile, const char *GifComment);
|
||||
int EGifPutExtensionLeader(GifFileType *GifFile, const int GifExtCode);
|
||||
int EGifPutExtensionBlock(GifFileType *GifFile,
|
||||
const int GifExtLen, const void *GifExtension);
|
||||
int EGifPutExtensionTrailer(GifFileType *GifFile);
|
||||
int EGifPutExtension(GifFileType *GifFile, const int GifExtCode,
|
||||
const int GifExtLen,
|
||||
const void *GifExtension);
|
||||
int EGifPutCode(GifFileType *GifFile, int GifCodeSize,
|
||||
const GifByteType *GifCodeBlock);
|
||||
int EGifPutCodeNext(GifFileType *GifFile,
|
||||
const GifByteType *GifCodeBlock);
|
||||
|
||||
/******************************************************************************
|
||||
GIF decoding routines
|
||||
******************************************************************************/
|
||||
|
||||
/* Main entry points */
|
||||
GifFileType *DGifOpenFileName(const char *GifFileName, int *Error);
|
||||
GifFileType *DGifOpenFileHandle(int GifFileHandle, int *Error);
|
||||
int DGifSlurp(GifFileType * GifFile);
|
||||
GifFileType *DGifOpen(void *userPtr, InputFunc readFunc, int *Error); /* new one (TVT) */
|
||||
int DGifCloseFile(GifFileType * GifFile, int *ErrorCode);
|
||||
|
||||
#define D_GIF_SUCCEEDED 0
|
||||
#define D_GIF_ERR_OPEN_FAILED 101 /* And DGif possible errors. */
|
||||
#define D_GIF_ERR_READ_FAILED 102
|
||||
#define D_GIF_ERR_NOT_GIF_FILE 103
|
||||
#define D_GIF_ERR_NO_SCRN_DSCR 104
|
||||
#define D_GIF_ERR_NO_IMAG_DSCR 105
|
||||
#define D_GIF_ERR_NO_COLOR_MAP 106
|
||||
#define D_GIF_ERR_WRONG_RECORD 107
|
||||
#define D_GIF_ERR_DATA_TOO_BIG 108
|
||||
#define D_GIF_ERR_NOT_ENOUGH_MEM 109
|
||||
#define D_GIF_ERR_CLOSE_FAILED 110
|
||||
#define D_GIF_ERR_NOT_READABLE 111
|
||||
#define D_GIF_ERR_IMAGE_DEFECT 112
|
||||
#define D_GIF_ERR_EOF_TOO_SOON 113
|
||||
|
||||
/* These are legacy. You probably do not want to call them directly */
|
||||
int DGifGetScreenDesc(GifFileType *GifFile);
|
||||
int DGifGetRecordType(GifFileType *GifFile, GifRecordType *GifType);
|
||||
int DGifGetImageHeader(GifFileType *GifFile);
|
||||
int DGifGetImageDesc(GifFileType *GifFile);
|
||||
int DGifGetLine(GifFileType *GifFile, GifPixelType *GifLine, int GifLineLen);
|
||||
int DGifGetPixel(GifFileType *GifFile, GifPixelType GifPixel);
|
||||
int DGifGetExtension(GifFileType *GifFile, int *GifExtCode,
|
||||
GifByteType **GifExtension);
|
||||
int DGifGetExtensionNext(GifFileType *GifFile, GifByteType **GifExtension);
|
||||
int DGifGetCode(GifFileType *GifFile, int *GifCodeSize,
|
||||
GifByteType **GifCodeBlock);
|
||||
int DGifGetCodeNext(GifFileType *GifFile, GifByteType **GifCodeBlock);
|
||||
int DGifGetLZCodes(GifFileType *GifFile, int *GifCode);
|
||||
const char *DGifGetGifVersion(GifFileType *GifFile);
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
Error handling and reporting.
|
||||
******************************************************************************/
|
||||
extern const char *GifErrorString(int ErrorCode); /* new in 2012 - ESR */
|
||||
|
||||
/*****************************************************************************
|
||||
Everything below this point is new after version 1.2, supporting `slurp
|
||||
mode' for doing I/O in two big belts with all the image-bashing in core.
|
||||
******************************************************************************/
|
||||
|
||||
/******************************************************************************
|
||||
Color map handling from gif_alloc.c
|
||||
******************************************************************************/
|
||||
|
||||
extern ColorMapObject *GifMakeMapObject(int ColorCount,
|
||||
const GifColorType *ColorMap);
|
||||
extern void GifFreeMapObject(ColorMapObject *Object);
|
||||
extern ColorMapObject *GifUnionColorMap(const ColorMapObject *ColorIn1,
|
||||
const ColorMapObject *ColorIn2,
|
||||
GifPixelType ColorTransIn2[]);
|
||||
extern int GifBitSize(int n);
|
||||
|
||||
/******************************************************************************
|
||||
Support for the in-core structures allocation (slurp mode).
|
||||
******************************************************************************/
|
||||
|
||||
extern void GifApplyTranslation(SavedImage *Image, GifPixelType Translation[]);
|
||||
extern int GifAddExtensionBlock(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks,
|
||||
int Function,
|
||||
unsigned int Len, unsigned char ExtData[]);
|
||||
extern void GifFreeExtensions(int *ExtensionBlock_Count,
|
||||
ExtensionBlock **ExtensionBlocks);
|
||||
extern SavedImage *GifMakeSavedImage(GifFileType *GifFile,
|
||||
const SavedImage *CopyFrom);
|
||||
extern void GifFreeSavedImages(GifFileType *GifFile);
|
||||
|
||||
/******************************************************************************
|
||||
5.x functions for GIF89 graphics control blocks
|
||||
******************************************************************************/
|
||||
|
||||
int DGifExtensionToGCB(const size_t GifExtensionLength,
|
||||
const GifByteType *GifExtension,
|
||||
GraphicsControlBlock *GCB);
|
||||
size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
|
||||
GifByteType *GifExtension);
|
||||
|
||||
int DGifSavedExtensionToGCB(GifFileType *GifFile,
|
||||
int ImageIndex,
|
||||
GraphicsControlBlock *GCB);
|
||||
int EGifGCBToSavedExtension(const GraphicsControlBlock *GCB,
|
||||
GifFileType *GifFile,
|
||||
int ImageIndex);
|
||||
|
||||
/******************************************************************************
|
||||
The library's internal utility font
|
||||
******************************************************************************/
|
||||
|
||||
#define GIF_FONT_WIDTH 8
|
||||
#define GIF_FONT_HEIGHT 8
|
||||
extern const unsigned char GifAsciiTable8x8[][GIF_FONT_WIDTH];
|
||||
|
||||
extern void GifDrawText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend, const int color);
|
||||
|
||||
extern void GifDrawBox(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawRectangle(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const int w, const int d, const int color);
|
||||
|
||||
extern void GifDrawBoxedText8x8(SavedImage *Image,
|
||||
const int x, const int y,
|
||||
const char *legend,
|
||||
const int border, const int bg, const int fg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
#endif /* _GIF_LIB_H */
|
||||
|
||||
/* end */
|
Binary file not shown.
Loading…
Reference in New Issue