1 /*****************************************************************************
2 * "Gif-Lib" - Yet another gif library. *
4 * Written by: Gershon Elber Ver 0.1, Aug. 1991 *
5 ******************************************************************************
6 * Program to rotate a GIF image by an arbitrary angle. *
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 ******************************************************************************
14 * 2 Aug 91 - Version 1.0 by Gershon Elber. *
15 *****************************************************************************/
28 #endif /* __MSDOS__ */
39 #endif /* HAVE_FCNTL_H */
44 #define M_PI 3.14159265358979323846
47 #define PROGRAM_NAME "GifRotat"
51 _stklen = 16384; /* Increase default stack size. */
52 #endif /* __MSDOS__ */
55 static char *VersionStr =
56 "Gif toolkit module,\t\tGershon Elber\n\
57 (C) Copyright 1989 Gershon Elber.\n";
59 *CtrlStr = "GifRotat a!-Angle!d q%- s%-Width|Height!d!d h%- GifFile!*s";
66 __DATE__ ", " __TIME__ "\n"
67 "(C) Copyright 1989 Gershon Elber.\n";
71 " a!-Angle!d q%- s%-Width|Height!d!d h%- GifFile!*s";
75 InterlacedOffset[] = { 0, 4, 2, 1 }, /* The way Interlaced image should. */
76 InterlacedJumps[] = { 8, 8, 4, 2 }; /* be read - offsets and jumps... */
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);
87 /******************************************************************************
88 * Interpret the command line and scan the given GIF file. *
89 ******************************************************************************/
90 int main(int argc, char **argv)
92 int i, j, Size, Error, NumFiles, Col, Row, Count, ExtCode,
93 DstWidth, DstHeight, Width, Height,
99 char **FileName = NULL;
100 GifRecordType RecordType;
101 GifByteType *Extension;
102 GifFileType *GifFile;
103 GifRowType *ScreenBuffer;
104 ColorMapObject *ColorMap = NULL;
106 if ((Error = GAGetArgs(argc, argv, CtrlStr,
107 &AngleFlag, &Angle, &GifQuietPrint,
108 &DstSizeFlag, &DstWidth, &DstHeight, &HelpFlag,
109 &NumFiles, &FileName)) != FALSE ||
110 (NumFiles > 1 && !HelpFlag)) {
112 GAPrintErrMsg(Error);
113 else if (NumFiles > 1)
114 GIF_MESSAGE("Error in command line parsing - one GIF file please.");
115 GAPrintHowTo(CtrlStr);
120 fprintf(stderr, VersionStr);
121 GAPrintHowTo(CtrlStr);
126 if ((GifFile = DGifOpenFileName(*FileName)) == NULL) {
132 /* Use the stdin instead: */
135 setmode(0, O_BINARY);
136 #endif /* __MSDOS__ */
137 if ((GifFile = DGifOpenFileHandle(0)) == NULL) {
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.");
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.");
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.");
163 memcpy(ScreenBuffer[i], ScreenBuffer[0], Size);
166 /* Scan the content of the GIF file and load the image(s) in: */
168 if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR) {
172 switch (RecordType) {
173 case IMAGE_DESC_RECORD_TYPE:
174 if (DGifGetImageDesc(GifFile) == GIF_ERROR) {
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);
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) {
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) {
213 case EXTENSION_RECORD_TYPE:
214 /* Skip any extension blocks in file: */
215 if (DGifGetExtension(GifFile, &ExtCode, &Extension) == GIF_ERROR) {
219 while (Extension != NULL) {
220 if (DGifGetExtensionNext(GifFile, &Extension) == GIF_ERROR) {
226 case TERMINATE_RECORD_TYPE:
228 default: /* Should be traps by DGifGetRecordType. */
232 while (RecordType != TERMINATE_RECORD_TYPE);
234 ColorMap = (GifFile->Image.ColorMap ? GifFile->Image.ColorMap :
238 DstWidth = GifFile->SWidth;
239 DstHeight = GifFile->SHeight;
242 /* Perform the actual rotation and dump the image: */
243 RotateGifImage(ScreenBuffer, GifFile, Angle, ColorMap,
244 DstWidth, DstHeight);
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)
257 LineSize = DstWidth * sizeof(GifPixelType);
258 GifFileType *DstGifFile;
259 GifRowType LineBuffer;
261 if ((LineBuffer = (GifRowType) malloc(LineSize)) == NULL)
262 GIF_EXIT("Failed to allocate memory required, aborted.");
264 /* Open stdout for the output file: */
265 if ((DstGifFile = EGifOpenFileHandle(1)) == NULL)
266 QuitGifError(DstGifFile);
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);
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);
283 if (EGifCloseFile(DstGifFile) == GIF_ERROR)
284 QuitGifError(DstGifFile);
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)
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);
304 for (x = 0; x < DstWidth; x++)
306 int xc = x - TransDstX,
308 SrcX = xc * CosAngle - yc * SinAngle + TransSrcX,
309 SrcY = xc * SinAngle + yc * CosAngle + TransSrcY;
311 if (SrcX < 0 || SrcX >= SrcWidth ||
312 SrcY < 0 || SrcY >= SrcHeight)
314 /* Out of the source image domain - set it to background color. */
315 *DstLine++ = BackGroundColor;
318 *DstLine++ = ScreenBuffer[SrcY][SrcX];
322 /******************************************************************************
323 * Close output file (if open), and exit. *
324 ******************************************************************************/
325 static void QuitGifError(GifFileType *DstGifFile)
328 if (DstGifFile != NULL) EGifCloseFile(DstGifFile);