Git init
[external/giflib.git] / util / gifrotat.c
1 /*****************************************************************************
2 *   "Gif-Lib" - Yet another gif library.                                     *
3 *                                                                            *
4 * Written by:  Gershon Elber                            Ver 0.1, Aug. 1991   *
5 ******************************************************************************
6 * Program to rotate a GIF image by an arbitrary angle.                       *
7 * Options:                                                                   *
8 * -q : quiet printing mode.                                                  *
9 * -a Angle : angle to rotate with respect to the X axis.                     *
10 * -s Width Height : specifies size of output image.                          *
11 * -h : on-line help.                                                         *
12 ******************************************************************************
13 * History:                                                                   *
14 *  2 Aug 91 - Version 1.0 by Gershon Elber.                                  *
15 *****************************************************************************/
16
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20
21 #ifdef __MSDOS__
22 #include <graphics.h>
23 #include <stdlib.h>
24 #include <alloc.h>
25 #include <io.h>
26 #include <dos.h>
27 #include <bios.h>
28 #endif /* __MSDOS__ */
29
30 #ifndef __MSDOS__
31 #include <stdlib.h>
32 #endif
33 #include <stdio.h>
34 #include <math.h>
35 #include <ctype.h>
36 #include <string.h>
37 #ifdef HAVE_FCNTL_H
38 #include <fcntl.h>
39 #endif /* HAVE_FCNTL_H */
40 #include "gif_lib.h"
41 #include "getarg.h"
42
43 #ifndef M_PI
44 #define M_PI        3.14159265358979323846
45 #endif /* M_PI */
46
47 #define PROGRAM_NAME    "GifRotat"
48
49 #ifdef __MSDOS__
50 extern unsigned int
51     _stklen = 16384;                         /* Increase default stack size. */
52 #endif /* __MSDOS__ */
53
54 #ifdef SYSV
55 static char *VersionStr =
56         "Gif toolkit module,\t\tGershon Elber\n\
57         (C) Copyright 1989 Gershon Elber.\n";
58 static char
59     *CtrlStr = "GifRotat a!-Angle!d q%- s%-Width|Height!d!d h%- GifFile!*s";
60 #else
61 static char
62     *VersionStr =
63         PROGRAM_NAME
64         GIF_LIB_VERSION
65         "       Gershon Elber,  "
66         __DATE__ ",   " __TIME__ "\n"
67         "(C) Copyright 1989 Gershon Elber.\n";
68 static char
69     *CtrlStr =
70         PROGRAM_NAME
71         " a!-Angle!d q%- s%-Width|Height!d!d h%- GifFile!*s";
72 #endif /* SYSV */
73
74 static int
75     InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
76     InterlacedJumps[] = { 8, 8, 4, 2 };    /* be read - offsets and jumps... */
77
78 static void RotateGifImage(GifRowType *ScreenBuffer, GifFileType *SrcGifFile,
79                            int Angle, ColorMapObject *ColorMap,
80                            int DstWidth, int DstHeight);
81 static void RotateGifLine(GifRowType *ScreenBuffer, int BackGroundColor,
82                           int SrcWidth, int SrcHeight,
83                           int Angle, GifRowType DstLine,
84                           int DstWidth, int DstHeight, int y);
85 static void QuitGifError(GifFileType *DstGifFile);
86
87 /******************************************************************************
88 * Interpret the command line and scan the given GIF file.                     *
89 ******************************************************************************/
90 int main(int argc, char **argv)
91 {
92     int i, j, Size, Error, NumFiles, Col, Row, Count, ExtCode,
93         DstWidth, DstHeight, Width, Height,
94         ImageNum = 0,
95         DstSizeFlag = FALSE,
96         AngleFlag = FALSE,
97         Angle = 0,
98         HelpFlag = FALSE;
99     char **FileName = NULL;
100     GifRecordType RecordType;
101     GifByteType *Extension;
102     GifFileType *GifFile;
103     GifRowType *ScreenBuffer;
104     ColorMapObject *ColorMap = NULL;
105
106     if ((Error = GAGetArgs(argc, argv, CtrlStr,
107                 &AngleFlag, &Angle, &GifQuietPrint,
108                 &DstSizeFlag, &DstWidth, &DstHeight, &HelpFlag,
109                 &NumFiles, &FileName)) != FALSE ||
110                 (NumFiles > 1 && !HelpFlag)) {
111         if (Error)
112             GAPrintErrMsg(Error);
113         else if (NumFiles > 1)
114             GIF_MESSAGE("Error in command line parsing - one GIF file please.");
115         GAPrintHowTo(CtrlStr);
116         exit(EXIT_FAILURE);
117     }
118
119     if (HelpFlag) {
120         fprintf(stderr, VersionStr);
121         GAPrintHowTo(CtrlStr);
122         exit(EXIT_SUCCESS);
123     }
124
125     if (NumFiles == 1) {
126         if ((GifFile = DGifOpenFileName(*FileName)) == NULL) {
127             PrintGifError();
128             exit(EXIT_FAILURE);
129         }
130     }
131     else {
132         /* Use the stdin instead: */
133
134 #ifdef __MSDOS__
135         setmode(0, O_BINARY);
136 #endif /* __MSDOS__ */
137         if ((GifFile = DGifOpenFileHandle(0)) == NULL) {
138             PrintGifError();
139             exit(EXIT_FAILURE);
140         }
141     }
142
143     /* Allocate the screen as vector of column of rows. We cannt allocate    */
144     /* the all screen at once, as this broken minded CPU can allocate up to  */
145     /* 64k at a time and our image can be bigger than that:                  */
146     /* Note this screen is device independent - its the screen as defined by */
147     /* the GIF file parameters itself.                                       */
148     if ((ScreenBuffer = (GifRowType *)
149         malloc(GifFile->SHeight * sizeof(GifRowType *))) == NULL)
150             GIF_EXIT("Failed to allocate memory required, aborted.");
151
152     Size = GifFile->SWidth * sizeof(GifPixelType);/* Size in bytes one row.*/
153     if ((ScreenBuffer[0] = (GifRowType) malloc(Size)) == NULL) /* First row. */
154         GIF_EXIT("Failed to allocate memory required, aborted.");
155
156     for (i = 0; i < GifFile->SWidth; i++)  /* Set its color to BackGround. */
157         ScreenBuffer[0][i] = GifFile->SBackGroundColor;
158     for (i = 1; i < GifFile->SHeight; i++) {
159         /* Allocate the other rows, and set their color to background too: */
160         if ((ScreenBuffer[i] = (GifRowType) malloc(Size)) == NULL)
161             GIF_EXIT("Failed to allocate memory required, aborted.");
162
163         memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
164     }
165
166     /* Scan the content of the GIF file and load the image(s) in: */
167     do {
168         if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
169             PrintGifError();
170             exit(EXIT_FAILURE);
171         }
172         switch (RecordType) {
173             case IMAGE_DESC_RECORD_TYPE:
174                 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
175                     PrintGifError();
176                     exit(EXIT_FAILURE);
177                 }
178                 Row = GifFile->Image.Top; /* Image Position relative to Screen. */
179                 Col = GifFile->Image.Left;
180                 Width = GifFile->Image.Width;
181                 Height = GifFile->Image.Height;
182                 GifQprintf("\n%s: Image %d at (%d, %d) [%dx%d]:     ",
183                     PROGRAM_NAME, ++ImageNum, Col, Row, Width, Height);
184                 if (GifFile->Image.Left + GifFile->Image.Width > GifFile->SWidth ||
185                    GifFile->Image.Top + GifFile->Image.Height > GifFile->SHeight) {
186                     fprintf(stderr, "Image %d is not confined to screen dimension, aborted.\n",ImageNum);
187                     exit(EXIT_FAILURE);
188                 }
189                 if (GifFile->Image.Interlace) {
190                     /* Need to perform 4 passes on the images: */
191                     for (Count = i = 0; i < 4; i++)
192                         for (j = Row + InterlacedOffset[i]; j < Row + Height;
193                                                  j += InterlacedJumps[i]) {
194                             GifQprintf("\b\b\b\b%-4d", Count++);
195                             if (DGifGetLine(GifFile, &ScreenBuffer[j][Col],
196                                 Width) == GIF_ERROR) {
197                                 PrintGifError();
198                                 exit(EXIT_FAILURE);
199                             }
200                         }
201                 }
202                 else {
203                     for (i = 0; i < Height; i++) {
204                         GifQprintf("\b\b\b\b%-4d", i);
205                         if (DGifGetLine(GifFile, &ScreenBuffer[Row++][Col],
206                                 Width) == GIF_ERROR) {
207                             PrintGifError();
208                             exit(EXIT_FAILURE);
209                         }
210                     }
211                 }
212                 break;
213             case EXTENSION_RECORD_TYPE:
214                 /* Skip any extension blocks in file: */
215                 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
216                     PrintGifError();
217                     exit(EXIT_FAILURE);
218                 }
219                 while (Extension != NULL) {
220                     if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
221                         PrintGifError();
222                         exit(EXIT_FAILURE);
223                     }
224                 }
225                 break;
226             case TERMINATE_RECORD_TYPE:
227                 break;
228             default:                /* Should be traps by DGifGetRecordType. */
229                 break;
230         }
231     }
232     while (RecordType != TERMINATE_RECORD_TYPE);
233
234     ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap :
235                                        GifFile->SColorMap);
236
237     if (!DstSizeFlag) {
238         DstWidth = GifFile->SWidth;
239         DstHeight = GifFile->SHeight;
240     }
241
242     /* Perform the actual rotation and dump the image: */
243     RotateGifImage(ScreenBuffer, GifFile, Angle, ColorMap,
244                    DstWidth, DstHeight);
245
246     return 0;
247 }
248
249 /******************************************************************************
250 * Save the GIF resulting image.                                               *
251 ******************************************************************************/
252 static void RotateGifImage(GifRowType *ScreenBuffer, GifFileType *SrcGifFile,
253                            int Angle, ColorMapObject *ColorMap,
254                            int DstWidth, int DstHeight)
255 {
256     int i,
257         LineSize = DstWidth * sizeof(GifPixelType);
258     GifFileType *DstGifFile;
259     GifRowType LineBuffer;
260
261     if ((LineBuffer = (GifRowType) malloc(LineSize)) == NULL)
262         GIF_EXIT("Failed to allocate memory required, aborted.");
263
264     /* Open stdout for the output file: */
265     if ((DstGifFile = EGifOpenFileHandle(1)) == NULL)
266         QuitGifError(DstGifFile);
267
268     if (EGifPutScreenDesc(DstGifFile, DstWidth, DstHeight,
269                           ColorMap->BitsPerPixel, 0, ColorMap) == GIF_ERROR ||
270         EGifPutImageDesc(DstGifFile, 0, 0, DstWidth, DstHeight,
271                          FALSE, NULL) == GIF_ERROR)
272         QuitGifError(DstGifFile);
273
274     for (i = 0; i < DstHeight; i++) {
275         RotateGifLine(ScreenBuffer, SrcGifFile->SBackGroundColor,
276                       SrcGifFile->SWidth, SrcGifFile->SHeight,
277                       Angle, LineBuffer, DstWidth, DstHeight, i);
278         if (EGifPutLine(DstGifFile, LineBuffer, DstWidth) == GIF_ERROR)
279             QuitGifError(DstGifFile);
280         GifQprintf("\b\b\b\b%-4d", DstHeight - i - 1);
281     }
282
283     if (EGifCloseFile(DstGifFile) == GIF_ERROR)
284         QuitGifError(DstGifFile);
285 }
286
287
288 /******************************************************************************
289 * Save the GIF resulting image.                                               *
290 ******************************************************************************/
291 static void RotateGifLine(GifRowType *ScreenBuffer, int BackGroundColor,
292                           int SrcWidth, int SrcHeight,
293                           int Angle, GifRowType DstLine,
294                           int DstWidth, int DstHeight, int y)
295 {
296     int x,
297         TransSrcX = SrcWidth / 2,
298         TransSrcY = SrcHeight / 2,
299         TransDstX = DstWidth / 2,
300         TransDstY = DstHeight / 2;
301     double SinAngle = sin(Angle * M_PI / 180.0),
302            CosAngle = cos(Angle * M_PI / 180.0);
303
304     for (x = 0; x < DstWidth; x++)
305     {
306         int xc = x - TransDstX,
307             yc = y - TransDstY,
308             SrcX = xc * CosAngle - yc * SinAngle + TransSrcX,
309             SrcY = xc * SinAngle + yc * CosAngle + TransSrcY;
310
311         if (SrcX < 0 || SrcX >= SrcWidth ||
312             SrcY < 0 || SrcY >= SrcHeight)
313         {
314             /* Out of the source image domain - set it to background color. */
315             *DstLine++ = BackGroundColor;
316         }
317         else
318             *DstLine++ = ScreenBuffer[SrcY][SrcX];
319     }
320 }
321
322 /******************************************************************************
323 * Close output file (if open), and exit.                                      *
324 ******************************************************************************/
325 static void QuitGifError(GifFileType *DstGifFile)
326 {
327     PrintGifError();
328     if (DstGifFile != NULL) EGifCloseFile(DstGifFile);
329     exit(EXIT_FAILURE);
330 }