Merge pull request #4314 from MartijnKaijser/beta1
[vuplus_xbmc] / lib / cximage-6.0 / CxImage / DllInterface.cpp
1 #ifdef _DLL
2 #include "ximage.h"
3 #include "ximajpg.h"
4
5 #if defined(_LINUX) || defined(__APPLE__)
6 #include <unistd.h>
7 #include <sys/stat.h>
8 #include <errno.h>
9 #define strcmpi strcasecmp
10 #else //win32
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
14 #define strcmpi _strcmpi
15 #endif
16
17 #define RESAMPLE_QUALITY 0
18 #undef USE_EXIF_THUMBS
19
20 extern "C" struct ImageInfo
21 {
22   unsigned int width;
23   unsigned int height;
24   unsigned int originalwidth;
25   unsigned int originalheight;
26   EXIFINFO exifInfo;
27   BYTE *texture;
28   void *context;
29   BYTE *alpha;
30 };
31
32 // helper functions
33
34 // determines based on file extension the type of file
35 DWORD GetImageType(const char *file)
36
37   if ( !file || ( 0 == *file ) ) // ensure file is not NULL and has non-zero length
38     return CXIMAGE_FORMAT_UNKNOWN;
39
40   // try to determine extension using '.' or use entire filename
41   // if '.' is absent.
42   const char *ext = strrchr(file, '.');
43   if (ext == NULL)
44     ext = (char*)file;
45   else
46     ext++;
47
48   if ( 0 == *ext ) // if filename ends in '.', we can't identify based on extension
49     return CXIMAGE_FORMAT_UNKNOWN;
50
51   if ( 0 == strcmpi(ext, "bmp") ) return CXIMAGE_FORMAT_BMP;
52   else if ( 0 == strcmpi(ext, "bitmap") ) return CXIMAGE_FORMAT_BMP;
53   else if ( 0 == strcmpi(ext, "gif") )    return CXIMAGE_FORMAT_GIF;
54   else if ( 0 == strcmpi(ext, "jpg") )    return CXIMAGE_FORMAT_JPG;
55   else if ( 0 == strcmpi(ext, "tbn") )    return CXIMAGE_FORMAT_JPG;
56   else if ( 0 == strcmpi(ext, "jpeg") )   return CXIMAGE_FORMAT_JPG;
57   else if ( 0 == strcmpi(ext, "png") )    return CXIMAGE_FORMAT_PNG;
58   else if ( 0 == strcmpi(ext, "ico") )    return CXIMAGE_FORMAT_ICO;
59   else if ( 0 == strcmpi(ext, "tif") )    return CXIMAGE_FORMAT_TIF;
60   else if ( 0 == strcmpi(ext, "tiff") )   return CXIMAGE_FORMAT_TIF;
61   else if ( 0 == strcmpi(ext, "tga") )    return CXIMAGE_FORMAT_TGA;
62   else if ( 0 == strcmpi(ext, "pcx") )    return CXIMAGE_FORMAT_PCX;
63
64   // RAW camera formats
65   else if ( 0 == strcmpi(ext, "cr2") ) return CXIMAGE_FORMAT_RAW;  
66   else if ( 0 == strcmpi(ext, "nef") ) return CXIMAGE_FORMAT_RAW;
67   else if ( 0 == strcmpi(ext, "dng") ) return CXIMAGE_FORMAT_RAW;
68   else if ( 0 == strcmpi(ext, "crw") ) return CXIMAGE_FORMAT_RAW;
69   else if ( 0 == strcmpi(ext, "orf") ) return CXIMAGE_FORMAT_RAW;
70   else if ( 0 == strcmpi(ext, "arw") ) return CXIMAGE_FORMAT_RAW;
71   else if ( 0 == strcmpi(ext, "erf") ) return CXIMAGE_FORMAT_RAW;
72   else if ( 0 == strcmpi(ext, "3fr") ) return CXIMAGE_FORMAT_RAW;
73   else if ( 0 == strcmpi(ext, "dcr") ) return CXIMAGE_FORMAT_RAW;
74   else if ( 0 == strcmpi(ext, "x3f") ) return CXIMAGE_FORMAT_RAW;
75   else if ( 0 == strcmpi(ext, "mef") ) return CXIMAGE_FORMAT_RAW;
76   else if ( 0 == strcmpi(ext, "raf") ) return CXIMAGE_FORMAT_RAW;
77   else if ( 0 == strcmpi(ext, "mrw") ) return CXIMAGE_FORMAT_RAW;
78   else if ( 0 == strcmpi(ext, "pef") ) return CXIMAGE_FORMAT_RAW;
79   else if ( 0 == strcmpi(ext, "sr2") ) return CXIMAGE_FORMAT_RAW;
80
81   // fallback to unknown
82   return CXIMAGE_FORMAT_UNKNOWN;
83 }
84
85 int DetectFileType(const BYTE* pBuffer, int nBufSize)
86 {
87   if (nBufSize <= 5)
88     return CXIMAGE_FORMAT_UNKNOWN;
89   if (pBuffer[1] == 'P' && pBuffer[2] == 'N' && pBuffer[3] == 'G')
90     return CXIMAGE_FORMAT_PNG;
91   if (pBuffer[0] == 'B' && pBuffer[1] == 'M')
92     return CXIMAGE_FORMAT_BMP;
93   if (pBuffer[0] == 0xFF && pBuffer[1] == 0xD8 && pBuffer[2] == 0xFF)
94     // don't include the last APP0 byte (0xE0), as some (non-conforming) JPEG/JFIF files might have some other
95     // APPn-specific data here, and we should skip over this.
96     return CXIMAGE_FORMAT_JPG;
97   if (pBuffer[0] == 'G' && pBuffer[1] == 'I' && pBuffer[2] == 'F')
98     return CXIMAGE_FORMAT_GIF;
99   return CXIMAGE_FORMAT_UNKNOWN;
100 }
101
102 int ResampleKeepAspect(CxImage &image, unsigned int width, unsigned int height)
103 {
104   bool bResize = false;
105   float fAspect = ((float)image.GetWidth()) / ((float)image.GetHeight());
106   unsigned int newwidth = image.GetWidth();
107   unsigned int newheight = image.GetHeight();
108   if (newwidth > width)
109   {
110     bResize = true;
111     newwidth = width;
112     newheight = (DWORD)( ( (float)newwidth) / fAspect);
113   }
114   if (newheight > height)
115   {
116     bResize = true;
117     newheight = height;
118     newwidth = (DWORD)( fAspect * ( (float)newheight) );
119   }
120   if (bResize)
121   {
122     if (!image.Resample(newwidth, newheight, RESAMPLE_QUALITY) || !image.IsValid())
123     {
124       printf("PICTURE::SaveThumb: Unable to resample picture: Error:%s\n", image.GetLastError());
125       return -1;
126     }
127   }
128   return bResize ? 1 : 0;
129 }
130
131 #ifdef LoadImage
132 #undef LoadImage
133 #endif
134
135 #if defined(_LINUX) || defined(__APPLE__)
136 #define __declspec(x) 
137 #endif
138
139 extern "C"
140 {
141   bool IsDir(const char* file)
142   {
143     struct stat holder;
144     if (stat(file, &holder) == -1)
145       return false;
146     if (S_ISDIR(holder.st_mode))
147       return true;
148
149     return false;
150   }
151
152   __declspec(dllexport) bool ReleaseImage(ImageInfo *info) 
153   {
154     if (info && info->context)
155     {
156       delete ((CxImage *)info->context);
157       return true;
158     }
159
160           return false;
161   }
162
163   __declspec(dllexport) bool LoadImage(const char *file, unsigned int maxwidth, unsigned int maxheight, ImageInfo *info)
164   {
165     if (!file || !info) return false;
166
167         if (IsDir(file))
168                 return false;
169
170           // load the image
171     DWORD dwImageType = GetImageType(file);
172     CxImage *image = new CxImage(dwImageType);
173     if (!image) return false;
174
175     int actualwidth = maxwidth;
176     int actualheight = maxheight;
177     try
178     {
179       if (!image->Load(file, dwImageType, actualwidth, actualheight) || !image->IsValid())
180       {
181 #if !defined(_LINUX) && !defined(__APPLE__)
182             int nErr = GetLastError();
183 #else
184             int nErr = errno;
185 #endif
186         printf("PICTURE::LoadImage: Unable to open image: %s Error:%s (%d)\n", file, image->GetLastError(),nErr);
187         delete image;
188         return false;
189       }
190     }
191     catch (...)
192     {
193       printf("PICTURE::LoadImage: Unable to open image: %s\n", file);
194       delete image;
195       return false;
196     }
197     // ok, now resample the image down if necessary
198     if (ResampleKeepAspect(*image, maxwidth, maxheight) < 0)
199     {
200       printf("PICTURE::LoadImage: Unable to resample picture: %s\n", file);
201       delete image;
202       return false;
203     }
204
205     // make sure our image is 24bit minimum
206     image->IncreaseBpp(24);
207
208     // fill in our struct
209     info->width = image->GetWidth();
210     info->height = image->GetHeight();
211     info->originalwidth = actualwidth;
212     info->originalheight = actualheight;
213     memcpy(&info->exifInfo, image->GetExifInfo(), sizeof(EXIFINFO));
214
215     // create our texture
216     info->context = image;
217     info->texture = image->GetBits();
218     info->alpha = image->AlphaGetBits();
219     return (info->texture != NULL);
220   };
221
222   __declspec(dllexport) bool LoadImageFromMemory(const BYTE *buffer, unsigned int size, const char *mime, unsigned int maxwidth, unsigned int maxheight, ImageInfo *info)
223   {
224     if (!buffer || !size || !mime || !info) return false;
225
226     // load the image
227     DWORD dwImageType = CXIMAGE_FORMAT_UNKNOWN;
228     if (strlen(mime))
229       dwImageType = GetImageType(mime);
230     if (dwImageType == CXIMAGE_FORMAT_UNKNOWN)
231       dwImageType = DetectFileType(buffer, size);
232     if (dwImageType == CXIMAGE_FORMAT_UNKNOWN)
233     {
234       printf("PICTURE::LoadImageFromMemory: Unable to determine image type.");
235       return false;
236     }
237
238     CxImage *image = new CxImage(dwImageType);
239     if (!image)
240       return false;
241
242     int actualwidth = maxwidth;
243     int actualheight = maxheight;
244
245     try
246     {
247       bool success = image->Decode((BYTE*)buffer, size, dwImageType, actualwidth, actualheight);
248       if (!success && dwImageType != CXIMAGE_FORMAT_UNKNOWN)
249       { // try to decode with unknown imagetype
250         success = image->Decode((BYTE*)buffer, size, CXIMAGE_FORMAT_UNKNOWN);
251       }
252       if (!success || !image->IsValid())
253       {
254         printf("PICTURE::LoadImageFromMemory: Unable to decode image. Error:%s\n", image->GetLastError());
255         delete image;
256         return false;
257       }
258     }
259     catch (...)
260     {
261       printf("PICTURE::LoadImageFromMemory: Unable to decode image.");
262       delete image;
263       return false;
264     }
265
266     // ok, now resample the image down if necessary
267     if (ResampleKeepAspect(*image, maxwidth, maxheight) < 0)
268     {
269       printf("PICTURE::LoadImage: Unable to resample picture\n");
270       delete image;
271       return false;
272     }
273
274     // make sure our image is 24bit minimum
275     image->IncreaseBpp(24);
276
277     // fill in our struct
278     info->width = image->GetWidth();
279     info->height = image->GetHeight();
280     info->originalwidth = actualwidth;
281     info->originalheight = actualheight;
282     memcpy(&info->exifInfo, image->GetExifInfo(), sizeof(EXIFINFO));
283
284     // create our texture
285     info->context = image;
286     info->texture = image->GetBits();
287     info->alpha = image->AlphaGetBits();
288     return (info->texture != NULL);
289   };
290
291   __declspec(dllexport) bool CreateThumbnailFromSurface(BYTE *buffer, unsigned int width, unsigned int height, unsigned int stride, const char *thumb)
292   {
293     if (!buffer || !thumb) return false;
294     // creates an image, and copies the surface data into it.
295     CxImage image(width, height, 24, CXIMAGE_FORMAT_PNG);
296     if (!image.IsValid()) return false;
297     image.AlphaCreate();
298     if (!image.AlphaIsValid()) return false;
299     bool fullyTransparent(true);
300     bool fullyOpaque(true);
301     for (unsigned int y = 0; y < height; y++)
302     {
303       BYTE *ptr = buffer + (y * stride);
304       for (unsigned int x = 0; x < width; x++)
305       {
306         BYTE b = *ptr++;
307         BYTE g = *ptr++;
308         BYTE r = *ptr++;
309         BYTE a = *ptr++;  // alpha
310         if (a)
311           fullyTransparent = false;
312         if (a != 0xff)
313           fullyOpaque = false;
314         image.SetPixelColor(x, height - 1 - y, RGB(r, g, b));
315         image.AlphaSet(x, height - 1 - y, a);
316       }
317     }
318     if (fullyTransparent || fullyOpaque)
319       image.AlphaDelete();
320     image.SetJpegQuality(90);
321
322     DWORD type;
323     if (image.AlphaIsValid() || GetImageType(thumb) == CXIMAGE_FORMAT_PNG)
324       type = CXIMAGE_FORMAT_PNG;
325     else
326       type = CXIMAGE_FORMAT_JPG;
327
328     if (!image.Save(thumb, type))
329     {
330       printf("PICTURE::CreateThumbnailFromSurface: Unable to save thumb to %s", thumb);
331       return false;
332     }
333     return true;
334   };
335
336   __declspec(dllexport) bool CreateThumbnailFromSurface2(BYTE * bufferin, unsigned int width, unsigned int height, unsigned int stride, const char *thumb, 
337                                                          BYTE * &bufferout, unsigned int &bufferoutSize)
338   {
339     if (!bufferin) return false;
340     // creates an image, and copies the surface data into it.
341     CxImage image(width, height, 24, CXIMAGE_FORMAT_PNG);
342     if (!image.IsValid()) return false;
343     image.AlphaCreate();
344     if (!image.AlphaIsValid()) return false;
345     bool fullyTransparent(true);
346     bool fullyOpaque(true);
347     for (unsigned int y = 0; y < height; y++)
348     {
349       BYTE *ptr = bufferin + (y * stride);
350       for (unsigned int x = 0; x < width; x++)
351       {
352         BYTE b = *ptr++;
353         BYTE g = *ptr++;
354         BYTE r = *ptr++;
355         BYTE a = *ptr++;  // alpha
356         if (a)
357           fullyTransparent = false;
358         if (a != 0xff)
359           fullyOpaque = false;
360         image.SetPixelColor(x, height - 1 - y, RGB(r, g, b));
361         image.AlphaSet(x, height - 1 - y, a);
362       }
363     }
364     if (fullyTransparent || fullyOpaque)
365       image.AlphaDelete();
366     image.SetJpegQuality(90);
367
368     DWORD type;
369     if (image.AlphaIsValid() || GetImageType(thumb) == CXIMAGE_FORMAT_PNG)
370       type = CXIMAGE_FORMAT_PNG;
371     else
372       type = CXIMAGE_FORMAT_JPG;
373
374     long buffout=0;
375
376     if (!image.Encode(bufferout, buffout, type))
377     {
378       printf("PICTURE::CreateThumbnailFromSurface: Unable to save thumb to %s", thumb);
379       return false;
380     }
381     bufferoutSize = buffout;
382     return true;
383   };
384
385   __declspec(dllexport) void    FreeMemory(void* memblock)
386   {
387     if (memblock)
388                   free(memblock);
389   };
390 }
391
392 #endif