1 /*
2  *      Copyright (C) 2014 Team Kodi
3  *      http://kodi.tv
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #pragma once
22 
23 #include <gif_lib.h>
24 #ifndef CONTINUE_EXT_FUNC_CODE
25 #define CONTINUE_EXT_FUNC_CODE 0
26 #endif
27 
28 #ifndef DISPOSAL_UNSPECIFIED
29 #define DISPOSAL_UNSPECIFIED 0
30 #endif
31 
32 #ifndef DISPOSE_DO_NOT
33 #define DISPOSE_DO_NOT 1
34 #endif
35 
36 #ifndef DISPOSE_BACKGROUND
37 #define DISPOSE_BACKGROUND 2
38 #endif
39 
40 #ifndef DISPOSE_PREVIOUS
41 #define DISPOSE_PREVIOUS 3
42 #endif
43 
44 #include <vector>
45 #include <string>
46 #include <memory>
47 #include "SimpleFS.h"
48 
49 #pragma pack(1)
50 struct GifColor
51 {
52   uint8_t b, g, r, a;
53 };
54 #pragma pack()
55 
56 class CFile;
57 
58 class GifFrame
59 {
60   friend class GifHelper;
61 public:
62 
63   GifFrame() = default;
64   virtual ~GifFrame();
65 
66   unsigned char* m_pImage = nullptr;
67   unsigned int m_delay = 0;
68 
69 private:
70   GifFrame(const GifFrame& src);
71 
72   unsigned int m_top = 0;
73   unsigned int m_left = 0;
74   unsigned int m_disposal = 0;
75   unsigned int m_height = 0;
76   unsigned int m_width = 0;
77   unsigned int m_imageSize = 0;
78   std::vector<GifColor>   m_palette;
79 };
80 
81 
82 
83 class GifHelper
84 {
85   friend class GifFrame;
86 
87   typedef std::shared_ptr<GifFrame> FramePtr;
88 
89 public:
90   GifHelper();
91   virtual ~GifHelper();
92 
93 
94   bool LoadGif(const char* file);
95 
GetFrames()96   std::vector<FramePtr>& GetFrames() { return m_frames; }
GetPitch()97   unsigned int GetPitch() const { return m_pitch; }
GetNumLoops()98   unsigned int GetNumLoops() const { return m_loops; }
GetWidth()99   unsigned int GetWidth() const { return m_width; }
GetHeight()100   unsigned int GetHeight() const { return m_height; }
101 
102 private:
103   std::vector<FramePtr> m_frames;
104   unsigned int m_imageSize = 0;
105   unsigned int m_pitch = 0;
106   unsigned int m_loops = 0;
107   unsigned int m_numFrames = 0;
108 
109   std::string     m_filename;
110   GifFileType* m_gif = nullptr;
111   std::vector<GifColor> m_globalPalette;
112   unsigned char* m_pTemplate = nullptr;
113   CFile*          m_gifFile;
114 
115   unsigned int m_width;
116   unsigned int m_height;
117 
118   bool Open(GifFileType *& gif, void * dataPtr, InputFunc readFunc);
119   void Close(GifFileType * gif);
120 
121   const char* Reason(int reason);
122 
123   bool LoadGifMetaData(const char* file);
124   bool Slurp(GifFileType* gif);
125   void InitTemplateAndColormap();
126   bool LoadGifMetaData(GifFileType* gif);
127   static void ConvertColorTable(std::vector<GifColor> &dest, ColorMapObject* src, unsigned int size);
128   bool GcbToFrame(GifFrame &frame, unsigned int imgIdx);
129   int ExtractFrames(unsigned int count);
130   void ClearFrameAreaToTransparency(unsigned char* dest, const GifFrame &frame);
131   void ConstructFrame(GifFrame &frame, const unsigned char* src) const;
132   bool PrepareTemplate(GifFrame &frame);
133   void Release();
134 
135 #if GIFLIB_MAJOR != 5
136   /*
137   taken from giflib 5.1.0
138   */
GifErrorString(int ErrorCode)139   const char* GifErrorString(int ErrorCode)
140   {
141     const char *Err;
142 
143     switch (ErrorCode) {
144     case E_GIF_ERR_OPEN_FAILED:
145       Err = "Failed to open given file";
146       break;
147     case E_GIF_ERR_WRITE_FAILED:
148       Err = "Failed to write to given file";
149       break;
150     case E_GIF_ERR_HAS_SCRN_DSCR:
151       Err = "Screen descriptor has already been set";
152       break;
153     case E_GIF_ERR_HAS_IMAG_DSCR:
154       Err = "Image descriptor is still active";
155       break;
156     case E_GIF_ERR_NO_COLOR_MAP:
157       Err = "Neither global nor local color map";
158       break;
159     case E_GIF_ERR_DATA_TOO_BIG:
160       Err = "Number of pixels bigger than width * height";
161       break;
162     case E_GIF_ERR_NOT_ENOUGH_MEM:
163       Err = "Failed to allocate required memory";
164       break;
165     case E_GIF_ERR_DISK_IS_FULL:
166       Err = "Write failed (disk full?)";
167       break;
168     case E_GIF_ERR_CLOSE_FAILED:
169       Err = "Failed to close given file";
170       break;
171     case E_GIF_ERR_NOT_WRITEABLE:
172       Err = "Given file was not opened for write";
173       break;
174     case D_GIF_ERR_OPEN_FAILED:
175       Err = "Failed to open given file";
176       break;
177     case D_GIF_ERR_READ_FAILED:
178       Err = "Failed to read from given file";
179       break;
180     case D_GIF_ERR_NOT_GIF_FILE:
181       Err = "Data is not in GIF format";
182       break;
183     case D_GIF_ERR_NO_SCRN_DSCR:
184       Err = "No screen descriptor detected";
185       break;
186     case D_GIF_ERR_NO_IMAG_DSCR:
187       Err = "No Image Descriptor detected";
188       break;
189     case D_GIF_ERR_NO_COLOR_MAP:
190       Err = "Neither global nor local color map";
191       break;
192     case D_GIF_ERR_WRONG_RECORD:
193       Err = "Wrong record type detected";
194       break;
195     case D_GIF_ERR_DATA_TOO_BIG:
196       Err = "Number of pixels bigger than width * height";
197       break;
198     case D_GIF_ERR_NOT_ENOUGH_MEM:
199       Err = "Failed to allocate required memory";
200       break;
201     case D_GIF_ERR_CLOSE_FAILED:
202       Err = "Failed to close given file";
203       break;
204     case D_GIF_ERR_NOT_READABLE:
205       Err = "Given file was not opened for read";
206       break;
207     case D_GIF_ERR_IMAGE_DEFECT:
208       Err = "Image is defective, decoding aborted";
209       break;
210     case D_GIF_ERR_EOF_TOO_SOON:
211       Err = "Image EOF detected before image complete";
212       break;
213     default:
214       Err = NULL;
215       break;
216     }
217     return Err;
218   }
219 #endif
220 };
221