1 
2 #include "studiox_includes.h"
3 #include "image_reader.h"
4 #include "png.h"
5 
6 extern png_structp png_instance;
7 extern png_infop   png_info_ptr;
8 
gif_reader()9 gif_reader::gif_reader() : png_reader()
10 {
11 }
12 
~gif_reader()13 gif_reader::~gif_reader()
14 {
15 }
16 
CheckImageHasAlphaChannel(CString & path)17 BOOL gif_reader::CheckImageHasAlphaChannel(CString& path)
18 {
19     return FALSE;
20 }
21 
GetEncoderClsid(const WCHAR * format,CLSID * pClsid)22 int gif_reader::GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
23 {
24     UINT  num = 0;          // number of image encoders
25     UINT  size = 0;         // size of the image encoder array in bytes
26 
27     ImageCodecInfo* pImageCodecInfo = NULL;
28 
29     GetImageEncodersSize(&num, &size);
30     if (size == 0)
31         return -1;  // Failure
32 
33     pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
34     if (pImageCodecInfo == NULL)
35         return -1;  // Failure
36 
37     GetImageEncoders(num, size, pImageCodecInfo);
38 
39     for (UINT j = 0; j < num; ++j)
40     {
41         if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0)
42         {
43             *pClsid = pImageCodecInfo[j].Clsid;
44             free(pImageCodecInfo);
45             return j;  // Success
46         }
47     }
48 
49     free(pImageCodecInfo);
50     return -1;  // Failure
51 }
52 
53 ///////////////////////////////////////////////////////////////////////////////
GetFrameCount(CString & path)54 INT gif_reader::GetFrameCount(CString& path)
55 {
56     Image img(path);
57 
58     UINT count = img.GetFrameDimensionsCount();
59     if (count < 0)
60     {
61         return FALSE;
62     }
63 
64     GUID* p_dimension_ids = new GUID[count];
65     img.GetFrameDimensionsList(p_dimension_ids, count);
66     int frame_count = img.GetFrameCount(&p_dimension_ids[0]);
67 
68     if (p_dimension_ids)
69     {
70         delete[]p_dimension_ids;
71     }
72 
73     return frame_count;
74 }
75 
76 ///////////////////////////////////////////////////////////////////////////////
GetDelayTime(int frame_id)77 INT gif_reader::GetDelayTime(int frame_id)
78 {
79     if (frame_id < mDelayTimeList.GetCount())
80     {
81         return mDelayTimeList.GetAt(frame_id);
82     }
83     else
84     {
85         return 0;
86     }
87 }
88 
89 ///////////////////////////////////////////////////////////////////////////////
ReadImage(CString & path,int frame_id)90 BOOL gif_reader::ReadImage(CString& path, int frame_id)
91 {
92     Image img(path);
93 
94     UINT count = img.GetFrameDimensionsCount();
95     if (count < 0)
96     {
97         return FALSE;
98     }
99 
100     GUID* p_dimension_ids = new GUID[count];
101     img.GetFrameDimensionsList(p_dimension_ids, count);
102     int frame_count = img.GetFrameCount(&p_dimension_ids[0]);
103 
104     CLSID pngClsid;
105     GetEncoderClsid(L"image/png", &pngClsid);
106 
107     IStorage* pIStorage = NULL;
108     IStream* pIStream = NULL;
109     HRESULT hr;
110 
111     hr = CoInitialize(NULL);
112 
113     if (FAILED(hr))
114     {
115         return FALSE;
116     }
117 
118     if (SUCCEEDED(hr))
119     {
120         // Create a compound file object, and get
121         // a pointer to its IStorage interface.
122 
123         hr = StgCreateDocfile(
124             NULL,
125             STGM_READWRITE | STGM_CREATE | STGM_SHARE_EXCLUSIVE,
126             0,
127             &pIStorage);
128     }
129 
130     if (SUCCEEDED(hr))
131     {
132         // Create a stream in the compound file.
133         hr = pIStorage->CreateStream(
134             L"StreamImage",
135             STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
136             0,
137             0,
138             &pIStream);
139     }
140 
141     LARGE_INTEGER dlibMove = { 0 };
142 
143     BOOL result = 0;
144     palette_info palinfo;
145 
146     palinfo.total_size = image_reader::GetPalSize();
147     GX_COLOR *palette = image_reader::GetPalette();
148 
149     UINT buffer_size = img.GetPropertyItemSize(PropertyTagFrameDelay);
150     PropertyItem* p_item = (PropertyItem*)(new byte[buffer_size]);
151     img.GetPropertyItem(PropertyTagFrameDelay, buffer_size, p_item);
152 
153     mDelayTimeList.RemoveAll();
154     int delay;
155     int start_frame;
156     int end_frame;
157     BOOL copy_palette = FALSE;
158 
159     if (palette && (GetDisplayFormat() > GX_COLOR_FORMAT_8BIT_PALETTE))
160     {
161         copy_palette = TRUE;
162     }
163 
164     if (frame_id >= 0 && frame_id < frame_count)
165     {
166         start_frame = frame_id;
167         end_frame = frame_id;
168     }
169     else
170     {
171         start_frame = 0;
172         end_frame = frame_count - 1;
173     }
174 
175     for (int index = start_frame; index <= end_frame; index++)
176     {
177         delay = ((UINT*)p_item[0].value)[index] * 10;
178         mDelayTimeList.Add(delay);
179 
180         if ((index != start_frame) && copy_palette)
181         {
182             palinfo.palette = new GX_COLOR[palinfo.total_size];
183             memcpy_s(palinfo.palette, palinfo.total_size * sizeof(GX_COLOR), palette, (palinfo.total_size * sizeof(GX_COLOR)));
184             SetPalette(palinfo.palette, palinfo.total_size, palinfo.total_size);
185         }
186 
187         pIStream->Seek(dlibMove, STREAM_SEEK_SET, NULL);
188 
189         img.SelectActiveFrame(&p_dimension_ids[0], index);
190         img.Save(pIStream, &pngClsid);
191 
192         pIStream->Seek(dlibMove, STREAM_SEEK_SET, NULL);
193 
194         result += png_reader::ReadImage(pIStream);
195     }
196 
197     if (p_item)
198     {
199         delete p_item;
200     }
201 
202     if (pIStream)
203     {
204         pIStream->Release();
205     }
206 
207     if (pIStorage)
208     {
209         pIStorage->Release();
210     }
211 
212     if (p_dimension_ids)
213     {
214         delete []p_dimension_ids;
215     }
216 
217     return result;
218 }
219 
220 ///////////////////////////////////////////////////////////////////////////////
ReadImage(unsigned char * data,int data_size)221 BOOL gif_reader::ReadImage(unsigned char* data, int data_size)
222 {
223     // This route is not needed at present, return FALSE directly.
224     return FALSE;
225 }