initial commit
[goodguy/history.git] / cinelerra-5.0 / cinelerra / filegif.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2014 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "file.h"
25 #include "filegif.h"
26 #include "gif_lib.h"
27 #include "mainerror.h"
28 #include "vframe.h"
29 #include <string.h>
30
31
32 static int gif_err = 0;
33 #define GIF_ERR ,&gif_err
34 #define GifErrorString(s) Gif##ErrorString(gif_err)
35 #define GifLastError(s) gif_err
36
37 const char *gifErrorString()
38 {
39         static char msg[32];
40         snprintf(msg, sizeof(msg), "Gif Error %d", GifLastError());
41         return msg;
42 }
43
44 FileGIF::FileGIF(Asset *asset, File *file)
45  : FileList(asset, file, "GIFLIST", ".gif", FILE_GIF, FILE_GIF_LIST)
46 {
47 }
48
49 FileGIF::~FileGIF()
50 {
51 }
52
53 int FileGIF::check_sig(Asset *asset)
54 {
55         FILE *stream = fopen(asset->path, "rb");
56
57         if(stream)
58         {
59                 char test[8];
60                 int ret = fread(test, 1, 6, stream);
61                 fclose(stream);
62
63                 if( ret >= 6 &&
64                         test[0] == 'G' && test[1] == 'I' && test[2] == 'F' &&
65                         test[3] == '8' && test[4] == '7' && test[5] == 'A')
66                 {
67                         return 1;
68                 }
69         }
70
71         if(strlen(asset->path) > 4)
72         {
73                 int len = strlen(asset->path);
74                 if(!strncasecmp(asset->path + len - 4, ".gif", 4)) return 1;
75         }
76         return 0;
77 }
78
79 int FileGIF::colormodel_supported(int colormodel)
80 {
81         return BC_RGB888;
82 }
83
84 int FileGIF::get_best_colormodel(Asset *asset, int driver)
85 {
86         return BC_RGB888;
87 }
88
89
90 int FileGIF::read_frame_header(char *path)
91 {
92         FILE *stream = fopen(path, "rb");
93
94         if(stream)
95         {
96                 unsigned char test[16];
97                 int ret = fread(test, 16, 1, stream);
98                 fclose(stream);
99                 if( ret < 1 ) return 1;
100                 asset->width = test[6] | (test[7] << 8);
101                 asset->height = test[8] | (test[9] << 8);
102 //printf("FileGIF::read_frame_header %d %d %d\n", __LINE__, asset->width, asset->height);
103                 return 0;
104         }
105
106         perror(path);
107         return 1;
108 }
109
110
111 static int input_func(GifFileType *gif_file, GifByteType *buffer, int bytes)
112 {
113         FileGIF *file = (FileGIF*)gif_file->UserData;
114         if(file->offset + bytes > file->size) bytes = file->size - file->offset;
115         if(bytes > 0)
116         {
117                 memcpy(buffer, file->data + file->offset, bytes);
118                 file->offset += bytes;
119         }
120         return bytes;
121 }
122
123 int FileGIF::read_frame(VFrame *output, VFrame *input)
124 {
125         data = input->get_data();
126         offset = 0;
127         size = input->get_compressed_size();
128
129         GifFileType *gif_file;
130         GifRowType *gif_buffer;
131         gif_file = DGifOpen(this, input_func GIF_ERR);
132
133
134         if(gif_file == 0)
135         {
136                 eprintf("FileGIF::read_frame %d: %s\n", __LINE__, GifErrorString());
137                 return 1;
138         }
139         gif_buffer = (GifRowType*)malloc(sizeof(GifRowType) * gif_file->SHeight);
140         int row_size = gif_file->SWidth * sizeof(GifPixelType);
141         gif_buffer[0] = (GifRowType)malloc(row_size);
142
143         for(int i = 0; i < gif_file->SWidth; i++)
144         {
145                 gif_buffer[0][i] = gif_file->SBackGroundColor;
146         }
147
148         for(int i = 0; i < gif_file->SHeight; i++)
149         {
150                 gif_buffer[i] = (GifRowType)malloc(row_size);
151                 memcpy(gif_buffer[i], gif_buffer[0], row_size);
152         }
153
154         GifRecordType record_type;
155         do
156         {
157                 if(DGifGetRecordType(gif_file, &record_type) == GIF_ERROR)
158                 {
159                         eprintf("FileGIF::read_frame %d: %s\n", __LINE__, GifErrorString());
160                         break;
161                 }
162
163                 switch(record_type)
164                 {
165                         case IMAGE_DESC_RECORD_TYPE:
166                         {
167                                 if(DGifGetImageDesc(gif_file) == GIF_ERROR)
168                                 {
169                                         eprintf("FileGIF::read_frame %d: %s\n", __LINE__, GifErrorString());
170                                         break;
171                                 }
172
173                                 int row = gif_file->Image.Top;
174                                 int col = gif_file->Image.Left;
175                                 int width = gif_file->Image.Width;
176                                 int height = gif_file->Image.Height;
177                                 if(gif_file->Image.Left + gif_file->Image.Width > gif_file->SWidth ||
178                                   gif_file->Image.Top + gif_file->Image.Height > gif_file->SHeight)
179                                 {
180                                         DGifCloseFile(gif_file GIF_ERR);
181                                         for(int k = 0; k < gif_file->SHeight; k++)
182                                         {
183                                                 free(gif_buffer[k]);
184                                         }
185                                         free(gif_buffer);
186                                         return 1;
187                                 }
188
189                                 if (gif_file->Image.Interlace)
190                                 {
191                                     static int InterlacedOffset[] = { 0, 4, 2, 1 };
192                                     static int InterlacedJumps[] = { 8, 8, 4, 2 };
193 /* Need to perform 4 passes on the images: */
194                                 for (int i = 0; i < 4; i++)
195                                         {
196                                                 for (int j = row + InterlacedOffset[i];
197                                                         j < row + height;
198                                                         j += InterlacedJumps[i])
199                                                 {
200                                                 if (DGifGetLine(gif_file,
201                                                                 &gif_buffer[j][col],
202                                                                 width) == GIF_ERROR)
203                                                         {
204                                                                 DGifCloseFile(gif_file GIF_ERR);
205                                                                 for(int k = 0; k < gif_file->SHeight; k++)
206                                                                 {
207                                                                         free(gif_buffer[k]);
208                                                                 }
209                                                                 free(gif_buffer);
210                                                                 return 1;
211                                                 }
212                                                 }
213                                         }
214                                 }
215                                 else
216                                 {
217                                 for (int i = 0; i < height; i++)
218                                         {
219                                                 if (DGifGetLine(gif_file, &gif_buffer[row++][col],
220                                                         width) == GIF_ERROR)
221                                                 {
222                                                         DGifCloseFile(gif_file GIF_ERR);
223                                                         for(int k = 0; k < gif_file->SHeight; k++)
224                                                         {
225                                                                 free(gif_buffer[k]);
226                                                         }
227                                                         free(gif_buffer);
228                                                 return 1;
229                                                 }
230                                 }
231                                 }
232
233                                 break;
234                         }
235                         default:
236                                 break;
237                 }
238
239         } while(record_type != TERMINATE_RECORD_TYPE);
240
241
242         //int background = gif_file->SBackGroundColor;
243         ColorMapObject *color_map = (gif_file->Image.ColorMap
244                 ? gif_file->Image.ColorMap
245                 : gif_file->SColorMap);
246         if(!color_map)
247         {
248                 DGifCloseFile(gif_file GIF_ERR);
249                 for(int k = 0; k < gif_file->SHeight; k++)
250                 {
251                         free(gif_buffer[k]);
252                 }
253                 free(gif_buffer);
254                 return 1;
255         }
256
257         int screen_width = gif_file->SWidth;
258         int screen_height = gif_file->SHeight;
259         for(int i = 0; i < screen_height; i++)
260         {
261                 GifRowType gif_row = gif_buffer[i];
262                 unsigned char *out_ptr = output->get_rows()[i];
263                 for(int j = 0; j < screen_width; j++)
264                 {
265                         GifColorType *color_map_entry = &color_map->Colors[gif_row[j]];
266                         *out_ptr++ = color_map_entry->Red;
267                         *out_ptr++ = color_map_entry->Green;
268                         *out_ptr++ = color_map_entry->Blue;
269                 }
270         }
271
272
273         for(int k = 0; k < gif_file->SHeight; k++)
274         {
275                 free(gif_buffer[k]);
276         }
277         free(gif_buffer);
278         DGifCloseFile(gif_file GIF_ERR);
279         return 0;
280 }
281