add asset select used to proxy list menu
[goodguy/cinelerra.git] / cinelerra-5.1 / 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 "interlacemodes.h"
29 #include "vframe.h"
30 #include <string.h>
31
32
33 static int gif_err = 0;
34 #define GIF_ERR ,&gif_err
35 #define GifErrorString(s) Gif##ErrorString(gif_err)
36 #define GifLastError(s) gif_err
37
38 const char *gifErrorString()
39 {
40         static char msg[32];
41         snprintf(msg, sizeof(msg), "Gif Error %d", GifLastError());
42         return msg;
43 }
44
45 FileGIF::FileGIF(Asset *asset, File *file)
46  : FileList(asset, file, "GIFLIST", ".gif", FILE_GIF, FILE_GIF_LIST)
47 {
48 }
49
50 FileGIF::~FileGIF()
51 {
52 }
53
54 int FileGIF::check_sig(Asset *asset)
55 {
56         FILE *stream = fopen(asset->path, "rb");
57
58         if(stream)
59         {
60                 char test[8];
61                 int ret = fread(test, 1, 6, stream);
62                 fclose(stream);
63
64                 if( ret >= 6 &&
65                         test[0] == 'G' && test[1] == 'I' && test[2] == 'F' &&
66                         test[3] == '8' && test[4] == '7' && test[5] == 'A')
67                 {
68                         eprintf("FileGIFF: version error (87A): \"%s\".\n", asset->path);
69                         return 1;
70                 }
71         }
72
73         if(strlen(asset->path) > 4)
74         {
75                 int len = strlen(asset->path);
76                 if(!strncasecmp(asset->path + len - 4, ".gif", 4)) return 1;
77         }
78         return 0;
79 }
80
81 int FileGIF::colormodel_supported(int colormodel)
82 {
83         return BC_RGB888;
84 }
85
86 int FileGIF::get_best_colormodel(Asset *asset, int driver)
87 {
88         return BC_RGB888;
89 }
90
91
92 int FileGIF::read_frame_header(char *path)
93 {
94         FILE *stream = fopen(path, "rb");
95
96         if(stream)
97         {
98                 unsigned char test[16];
99                 int ret = fread(test, 16, 1, stream);
100                 fclose(stream);
101                 if( ret < 1 ) return 1;
102                 asset->width = test[6] | (test[7] << 8);
103                 asset->height = test[8] | (test[9] << 8);
104 //printf("FileGIF::read_frame_header %d %d %d\n", __LINE__, asset->width, asset->height);
105                 return 0;
106         }
107
108         perror(path);
109         return 1;
110 }
111
112
113 static int input_func(GifFileType *gif_file, GifByteType *buffer, int bytes)
114 {
115         FileGIF *file = (FileGIF*)gif_file->UserData;
116         if(file->offset + bytes > file->size) bytes = file->size - file->offset;
117         if(bytes > 0)
118         {
119                 memcpy(buffer, file->data + file->offset, bytes);
120                 file->offset += bytes;
121         }
122         return bytes;
123 }
124
125 int FileGIF::read_frame(VFrame *output, VFrame *input)
126 {
127         data = input->get_data();
128         offset = 0;
129         size = input->get_compressed_size();
130
131         GifFileType *gif_file;
132         GifRowType *gif_buffer;
133         gif_file = DGifOpen(this, input_func GIF_ERR);
134
135
136         if(gif_file == 0)
137         {
138                 eprintf("FileGIF::read_frame %d: %s\n", __LINE__, GifErrorString());
139                 return 1;
140         }
141         gif_buffer = (GifRowType*)malloc(sizeof(GifRowType) * gif_file->SHeight);
142         int row_size = gif_file->SWidth * sizeof(GifPixelType);
143         gif_buffer[0] = (GifRowType)malloc(row_size);
144
145         for(int i = 0; i < gif_file->SWidth; i++)
146         {
147                 gif_buffer[0][i] = gif_file->SBackGroundColor;
148         }
149
150         for(int i = 0; i < gif_file->SHeight; i++)
151         {
152                 gif_buffer[i] = (GifRowType)malloc(row_size);
153                 memcpy(gif_buffer[i], gif_buffer[0], row_size);
154         }
155
156         GifRecordType record_type;
157         do
158         {
159                 if(DGifGetRecordType(gif_file, &record_type) == GIF_ERROR)
160                 {
161                         eprintf("FileGIF::read_frame %d: %s\n", __LINE__, GifErrorString());
162                         break;
163                 }
164
165                 switch(record_type)
166                 {
167                         case IMAGE_DESC_RECORD_TYPE:
168                         {
169                                 if(DGifGetImageDesc(gif_file) == GIF_ERROR)
170                                 {
171                                         eprintf("FileGIF::read_frame %d: %s\n", __LINE__, GifErrorString());
172                                         break;
173                                 }
174
175                                 int row = gif_file->Image.Top;
176                                 int col = gif_file->Image.Left;
177                                 int width = gif_file->Image.Width;
178                                 int height = gif_file->Image.Height;
179                                 if(gif_file->Image.Left + gif_file->Image.Width > gif_file->SWidth ||
180                                   gif_file->Image.Top + gif_file->Image.Height > gif_file->SHeight)
181                                 {
182                                         DGifCloseFile(gif_file GIF_ERR);
183                                         for(int k = 0; k < gif_file->SHeight; k++)
184                                         {
185                                                 free(gif_buffer[k]);
186                                         }
187                                         free(gif_buffer);
188                                         return 1;
189                                 }
190
191                                 if (gif_file->Image.Interlace)
192                                 {
193                                     static int InterlacedOffset[] = { 0, 4, 2, 1 };
194                                     static int InterlacedJumps[] = { 8, 8, 4, 2 };
195 /* Need to perform 4 passes on the images: */
196                                 for (int i = 0; i < 4; i++)
197                                         {
198                                                 for (int j = row + InterlacedOffset[i];
199                                                         j < row + height;
200                                                         j += InterlacedJumps[i])
201                                                 {
202                                                 if (DGifGetLine(gif_file,
203                                                                 &gif_buffer[j][col],
204                                                                 width) == GIF_ERROR)
205                                                         {
206                                                                 DGifCloseFile(gif_file GIF_ERR);
207                                                                 for(int k = 0; k < gif_file->SHeight; k++)
208                                                                 {
209                                                                         free(gif_buffer[k]);
210                                                                 }
211                                                                 free(gif_buffer);
212                                                                 return 1;
213                                                 }
214                                                 }
215                                         }
216                                 }
217                                 else
218                                 {
219                                 for (int i = 0; i < height; i++)
220                                         {
221                                                 if (DGifGetLine(gif_file, &gif_buffer[row++][col],
222                                                         width) == GIF_ERROR)
223                                                 {
224                                                         DGifCloseFile(gif_file GIF_ERR);
225                                                         for(int k = 0; k < gif_file->SHeight; k++)
226                                                         {
227                                                                 free(gif_buffer[k]);
228                                                         }
229                                                         free(gif_buffer);
230                                                 return 1;
231                                                 }
232                                 }
233                                 }
234
235                                 break;
236                         }
237                         default:
238                                 break;
239                 }
240
241         } while(record_type != TERMINATE_RECORD_TYPE);
242
243
244         //int background = gif_file->SBackGroundColor;
245         ColorMapObject *color_map = (gif_file->Image.ColorMap
246                 ? gif_file->Image.ColorMap
247                 : gif_file->SColorMap);
248         if(!color_map)
249         {
250                 DGifCloseFile(gif_file GIF_ERR);
251                 for(int k = 0; k < gif_file->SHeight; k++)
252                 {
253                         free(gif_buffer[k]);
254                 }
255                 free(gif_buffer);
256                 return 1;
257         }
258
259         int screen_width = gif_file->SWidth;
260         int screen_height = gif_file->SHeight;
261         for(int i = 0; i < screen_height; i++)
262         {
263                 GifRowType gif_row = gif_buffer[i];
264                 unsigned char *out_ptr = output->get_rows()[i];
265                 for(int j = 0; j < screen_width; j++)
266                 {
267                         GifColorType *color_map_entry = &color_map->Colors[gif_row[j]];
268                         *out_ptr++ = color_map_entry->Red;
269                         *out_ptr++ = color_map_entry->Green;
270                         *out_ptr++ = color_map_entry->Blue;
271                 }
272         }
273
274
275         for(int k = 0; k < gif_file->SHeight; k++)
276         {
277                 free(gif_buffer[k]);
278         }
279         free(gif_buffer);
280         DGifCloseFile(gif_file GIF_ERR);
281         return 0;
282 }
283