1 /********************************************************************************
2 *                                                                               *
3 *                            I c o n   S o u r c e                              *
4 *                                                                               *
5 *********************************************************************************
6 * Copyright (C) 2005,2021 by Jeroen van der Zijp.   All Rights Reserved.        *
7 *********************************************************************************
8 * This library is free software; you can redistribute it and/or modify          *
9 * it under the terms of the GNU Lesser General Public License as published by   *
10 * the Free Software Foundation; either version 3 of the License, or             *
11 * (at your option) any later version.                                           *
12 *                                                                               *
13 * This library is distributed in the hope that it will be useful,               *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of                *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                 *
16 * GNU Lesser General Public License for more details.                           *
17 *                                                                               *
18 * You should have received a copy of the GNU Lesser General Public License      *
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>          *
20 ********************************************************************************/
21 #include "xincs.h"
22 #include "fxver.h"
23 #include "fxdefs.h"
24 #include "fxmath.h"
25 #include "FXArray.h"
26 #include "FXHash.h"
27 #include "FXStream.h"
28 #include "FXFile.h"
29 #include "FXFileStream.h"
30 #include "FXMemoryStream.h"
31 #include "FXString.h"
32 #include "FXPath.h"
33 #include "FXIcon.h"
34 #include "FXImage.h"
35 #include "FXIconSource.h"
36 
37 // Built-in icon formats
38 #include "FXBMPIcon.h"
39 #include "FXGIFIcon.h"
40 #include "FXICOIcon.h"
41 #include "FXIFFIcon.h"
42 #include "FXPCXIcon.h"
43 #include "FXPPMIcon.h"
44 #include "FXRASIcon.h"
45 #include "FXRGBIcon.h"
46 #include "FXTGAIcon.h"
47 #include "FXXBMIcon.h"
48 #include "FXXPMIcon.h"
49 #include "FXDDSIcon.h"
50 #include "FXEXEIcon.h"
51 
52 // Built-in image formats
53 #include "FXBMPImage.h"
54 #include "FXGIFImage.h"
55 #include "FXICOImage.h"
56 #include "FXIFFImage.h"
57 #include "FXPCXImage.h"
58 #include "FXPPMImage.h"
59 #include "FXRASImage.h"
60 #include "FXRGBImage.h"
61 #include "FXTGAImage.h"
62 #include "FXXBMImage.h"
63 #include "FXXPMImage.h"
64 #include "FXDDSImage.h"
65 #include "FXEXEImage.h"
66 
67 // Formats requiring external libraries
68 #ifndef CORE_IMAGE_FORMATS
69 #ifdef HAVE_JPEG_H
70 #include "FXJPGIcon.h"
71 #include "FXJPGImage.h"
72 #endif
73 #ifdef HAVE_PNG_H
74 #include "FXPNGIcon.h"
75 #include "FXPNGImage.h"
76 #endif
77 #ifdef HAVE_TIFF_H
78 #include "FXTIFIcon.h"
79 #include "FXTIFImage.h"
80 #endif
81 #endif
82 #ifdef HAVE_JP2_H
83 #include "FXJP2Icon.h"
84 #include "FXJP2Image.h"
85 #endif
86 #ifdef HAVE_WEBP_H
87 #include "FXWEBPIcon.h"
88 #include "FXWEBPImage.h"
89 #endif
90 
91 /*
92   Notes:
93   - Either load an icon from a file, or load from already open stream.
94   - Recognition of some image/icon types based on contents may be less
95     certain due to poorly defined signature information in the file.
96 */
97 
98 
99 using namespace FX;
100 
101 /*******************************************************************************/
102 
103 namespace FX {
104 
105 
106 // Default icon source used when none provided
107 FXIconSource FXIconSource::defaultIconSource;
108 
109 
110 // Object implementation
111 FXIMPLEMENT(FXIconSource,FXObject,NULL,0)
112 
113 
114 // Scale image or icon to size
scaleToSize(FXImage * image,FXint size,FXint qual) const115 FXImage* FXIconSource::scaleToSize(FXImage *image,FXint size,FXint qual) const {
116   if(image){
117     if((image->getWidth()>size) || (image->getHeight()>size)){
118       if(image->getWidth()>image->getHeight()){
119         image->scale(size,(size*image->getHeight())/image->getWidth(),qual);
120         }
121       else{
122         image->scale((size*image->getWidth())/image->getHeight(),size,qual);
123         }
124       }
125     }
126   return image;
127   }
128 
129 
130 // Create icon from file type
iconFromType(FXApp * app,const FXString & type) const131 FXIcon *FXIconSource::iconFromType(FXApp* app,const FXString& type) const {
132   if(comparecase(FXBMPIcon::fileExt,type)==0){
133     return new FXBMPIcon(app,NULL,0,IMAGE_ALPHAGUESS);
134     }
135   if(comparecase(FXGIFIcon::fileExt,type)==0){
136     return new FXGIFIcon(app);
137     }
138   if(comparecase(FXICOIcon::fileExt,type)==0 || comparecase("cur",type)==0){
139     return new FXICOIcon(app);
140     }
141   if(comparecase(FXIFFIcon::fileExt,type)==0 || comparecase("lbm",type)==0){
142     return new FXIFFIcon(app);
143     }
144   if(comparecase(FXPCXIcon::fileExt,type)==0){
145     return new FXPCXIcon(app);
146     }
147   if(comparecase(FXPPMIcon::fileExt,type)==0 || comparecase("pbm",type)==0 || comparecase("pgm",type)==0 || comparecase("pnm",type)==0){
148     return new FXPPMIcon(app);
149     }
150   if(comparecase(FXRASIcon::fileExt,type)==0){
151     return new FXRASIcon(app);
152     }
153   if(comparecase(FXRGBIcon::fileExt,type)==0){
154     return new FXRGBIcon(app);
155     }
156   if(comparecase(FXTGAIcon::fileExt,type)==0){
157     return new FXTGAIcon(app);
158     }
159   if(comparecase(FXXBMIcon::fileExt,type)==0){
160     return new FXXBMIcon(app);
161     }
162   if(comparecase(FXXPMIcon::fileExt,type)==0){
163     return new FXXPMIcon(app);
164     }
165   if(comparecase(FXDDSIcon::fileExt,type)==0){
166     return new FXDDSIcon(app);
167     }
168   if(comparecase(FXEXEIcon::fileExt,type)==0){
169     return new FXEXEIcon(app);
170     }
171 #ifndef CORE_IMAGE_FORMATS
172 #ifdef HAVE_JPEG_H
173   if(comparecase(FXJPGIcon::fileExt,type)==0 || comparecase("jpeg",type)==0){
174     return new FXJPGIcon(app);
175     }
176 #endif
177 #ifdef HAVE_PNG_H
178   if(comparecase(FXPNGIcon::fileExt,type)==0){
179     return new FXPNGIcon(app);
180     }
181 #endif
182 #ifdef HAVE_TIFF_H
183   if(comparecase(FXTIFIcon::fileExt,type)==0 || comparecase("tiff",type)==0){
184     return new FXTIFIcon(app);
185     }
186 #endif
187 #ifdef HAVE_JP2_H
188   if(comparecase(FXJP2Icon::fileExt,type)==0){
189     return new FXJP2Icon(app);
190     }
191 #endif
192 #ifdef HAVE_WEBP_H
193   if(comparecase(FXWEBPIcon::fileExt,type)==0){
194     return new FXWEBPIcon(app);
195     }
196 #endif
197 #endif
198   return NULL;
199   }
200 
201 
202 // Create image from file type
imageFromType(FXApp * app,const FXString & type) const203 FXImage *FXIconSource::imageFromType(FXApp* app,const FXString& type) const {
204   if(comparecase(FXBMPImage::fileExt,type)==0){
205     return new FXBMPImage(app);
206     }
207   if(comparecase(FXGIFImage::fileExt,type)==0){
208     return new FXGIFImage(app);
209     }
210   if(comparecase(FXICOImage::fileExt,type)==0 || comparecase("cur",type)==0){
211     return new FXICOImage(app);
212     }
213   if(comparecase(FXIFFImage::fileExt,type)==0 || comparecase("lbm",type)==0){
214     return new FXIFFImage(app);
215     }
216   if(comparecase(FXPCXImage::fileExt,type)==0){
217     return new FXPCXImage(app);
218     }
219   if(comparecase(FXPPMImage::fileExt,type)==0 || comparecase("pbm",type)==0 || comparecase("pgm",type)==0 || comparecase("pnm",type)==0){
220     return new FXPPMImage(app);
221     }
222   if(comparecase(FXRASImage::fileExt,type)==0){
223     return new FXRASImage(app);
224     }
225   if(comparecase(FXRGBImage::fileExt,type)==0){
226     return new FXRGBImage(app);
227     }
228   if(comparecase(FXTGAImage::fileExt,type)==0){
229     return new FXTGAImage(app);
230     }
231   if(comparecase(FXXBMImage::fileExt,type)==0){
232     return new FXXBMImage(app);
233     }
234   if(comparecase(FXXPMImage::fileExt,type)==0){
235     return new FXXPMImage(app);
236     }
237   if(comparecase(FXDDSImage::fileExt,type)==0){
238     return new FXDDSImage(app);
239     }
240   if(comparecase(FXEXEImage::fileExt,type)==0){
241     return new FXEXEImage(app);
242     }
243 #ifndef CORE_IMAGE_FORMATS
244 #ifdef HAVE_JPEG_H
245   if(comparecase(FXJPGImage::fileExt,type)==0 || comparecase("jpeg",type)==0){
246     return new FXJPGImage(app);
247     }
248 #endif
249 #ifdef HAVE_PNG_H
250   if(comparecase(FXPNGImage::fileExt,type)==0){
251     return new FXPNGImage(app);
252     }
253 #endif
254 #ifdef HAVE_TIFF_H
255   if(comparecase(FXTIFImage::fileExt,type)==0 || comparecase("tiff",type)==0){
256     return new FXTIFImage(app);
257     }
258 #endif
259 #ifdef HAVE_JP2_H
260   if(comparecase(FXJP2Image::fileExt,type)==0){
261     return new FXJP2Image(app);
262     }
263 #endif
264 #ifdef HAVE_WEBP_H
265   if(comparecase(FXWEBPImage::fileExt,type)==0){
266     return new FXWEBPImage(app);
267     }
268 #endif
269 #endif
270   return NULL;
271   }
272 
273 
274 // Determine icon type from first header bytes in stream
iconFromStream(FXApp * app,FXStream & store) const275 FXIcon *FXIconSource::iconFromStream(FXApp* app,FXStream& store) const {
276   if(fxcheckBMP(store)){
277     return new FXBMPIcon(app,NULL,0,IMAGE_ALPHAGUESS);
278     }
279   if(fxcheckGIF(store)){
280     return new FXGIFIcon(app);
281     }
282   if(fxcheckIFF(store)){
283     return new FXIFFIcon(app);
284     }
285   if(fxcheckPPM(store)){
286     return new FXPPMIcon(app);
287     }
288   if(fxcheckRAS(store)){
289     return new FXRASIcon(app);
290     }
291   if(fxcheckXBM(store)){
292     return new FXXBMIcon(app);
293     }
294   if(fxcheckXPM(store)){
295     return new FXXPMIcon(app);
296     }
297   if(fxcheckDDS(store)){
298     return new FXDDSIcon(app);
299     }
300   if(fxcheckEXE(store)){
301     return new FXEXEIcon(app);
302     }
303 #ifndef CORE_IMAGE_FORMATS
304 #ifdef HAVE_JPEG_H
305   if(fxcheckJPG(store)){
306     return new FXJPGIcon(app);
307     }
308 #endif
309 #ifdef HAVE_PNG_H
310   if(fxcheckPNG(store)){
311     return new FXPNGIcon(app);
312     }
313 #endif
314 #ifdef HAVE_TIFF_H
315   if(fxcheckTIF(store)){
316     return new FXTIFIcon(app);
317     }
318 #endif
319 #ifdef HAVE_JP2_H
320   if(fxcheckJP2(store)){
321     return new FXJP2Icon(app);
322     }
323 #endif
324 #ifdef HAVE_WEBP_H
325   if(fxcheckWEBP(store)){
326     return new FXWEBPIcon(app);
327     }
328 #endif
329 #endif
330   if(fxcheckPCX(store)){
331     return new FXPCXIcon(app);
332     }
333   if(fxcheckICO(store)){
334     return new FXICOIcon(app);
335     }
336   if(fxcheckRGB(store)){
337     return new FXRGBIcon(app);
338     }
339   if(fxcheckTGA(store)){
340     return new FXTGAIcon(app);
341     }
342   return NULL;
343   }
344 
345 
346 // Determine image type from first header bytes in stream
imageFromStream(FXApp * app,FXStream & store) const347 FXImage *FXIconSource::imageFromStream(FXApp* app,FXStream& store) const {
348   if(fxcheckBMP(store)){
349     return new FXBMPImage(app);
350     }
351   if(fxcheckGIF(store)){
352     return new FXGIFImage(app);
353     }
354   if(fxcheckIFF(store)){
355     return new FXIFFImage(app);
356     }
357   if(fxcheckPPM(store)){
358     return new FXPPMImage(app);
359     }
360   if(fxcheckRAS(store)){
361     return new FXRASImage(app);
362     }
363   if(fxcheckXBM(store)){
364     return new FXXBMImage(app);
365     }
366   if(fxcheckXPM(store)){
367     return new FXXPMImage(app);
368     }
369   if(fxcheckDDS(store)){
370     return new FXDDSImage(app);
371     }
372   if(fxcheckEXE(store)){
373     return new FXEXEImage(app);
374     }
375 #ifndef CORE_IMAGE_FORMATS
376 #ifdef HAVE_JPEG_H
377   if(fxcheckJPG(store)){
378     return new FXJPGImage(app);
379     }
380 #endif
381 #ifdef HAVE_PNG_H
382   if(fxcheckPNG(store)){
383     return new FXPNGImage(app);
384     }
385 #endif
386 #ifdef HAVE_TIFF_H
387   if(fxcheckTIF(store)){
388     return new FXTIFImage(app);
389     }
390 #endif
391 #ifdef HAVE_JP2_H
392   if(fxcheckJP2(store)){
393     return new FXJP2Image(app);
394     }
395 #endif
396 #ifdef HAVE_WEBP_H
397   if(fxcheckWEBP(store)){
398     return new FXWEBPImage(app);
399     }
400 #endif
401 #endif
402   if(fxcheckPCX(store)){
403     return new FXPCXImage(app);
404     }
405   if(fxcheckICO(store)){
406     return new FXICOImage(app);
407     }
408   if(fxcheckRGB(store)){
409     return new FXRGBImage(app);
410     }
411   if(fxcheckTGA(store)){
412     return new FXTGAImage(app);
413     }
414   return NULL;
415   }
416 
417 
418 // Load from file
loadIconFile(FXApp * app,const FXString & filename,const FXString & type) const419 FXIcon *FXIconSource::loadIconFile(FXApp* app,const FXString& filename,const FXString& type) const {
420   FXIcon *icon=NULL;
421   FXTRACE((150,"FXIconSource loadIcon(%s)\n",filename.text()));
422   if(!filename.empty()){
423     FXFileStream store;
424     if(store.open(filename,FXStreamLoad,65536)){
425       if(type.empty()){
426         icon=loadIconStream(app,store,FXPath::extension(filename));
427         }
428       else{
429         icon=loadIconStream(app,store,type);
430         }
431       store.close();
432       }
433     }
434   return icon;
435   }
436 
437 
438 // Load from data array
loadIconData(FXApp * app,const void * pixels,const FXString & type) const439 FXIcon *FXIconSource::loadIconData(FXApp* app,const void *pixels,const FXString& type) const {
440   FXIcon *icon=NULL;
441   if(pixels){
442     FXMemoryStream store;
443     store.open(FXStreamLoad,(FXuchar*)pixels);
444     icon=loadIconStream(app,store,type);
445     store.close();
446     }
447   return icon;
448   }
449 
450 
451 // Load from already open stream
loadIconStream(FXApp * app,FXStream & store,const FXString & type) const452 FXIcon *FXIconSource::loadIconStream(FXApp* app,FXStream& store,const FXString& type) const {
453   FXIcon *icon=NULL;
454   if(!type.empty()){
455     icon=iconFromType(app,type);
456     }
457   if(!icon){
458     icon=iconFromStream(app,store);
459     }
460   if(icon){
461     if(icon->loadPixels(store)) return icon;
462     delete icon;
463     }
464   return NULL;
465   }
466 
467 
468 // Load from file
loadImageFile(FXApp * app,const FXString & filename,const FXString & type) const469 FXImage *FXIconSource::loadImageFile(FXApp* app,const FXString& filename,const FXString& type) const {
470   FXImage *image=NULL;
471   FXTRACE((150,"FXIconSource loadImage(%s)\n",filename.text()));
472   if(!filename.empty()){
473     FXFileStream store;
474     if(store.open(filename,FXStreamLoad,65536)){
475       if(type.empty()){
476         image=loadImageStream(app,store,FXPath::extension(filename));
477         }
478       else{
479         image=loadImageStream(app,store,type);
480         }
481       store.close();
482       }
483     }
484   return image;
485   }
486 
487 
488 // Load from data array
loadImageData(FXApp * app,const void * pixels,const FXString & type) const489 FXImage *FXIconSource::loadImageData(FXApp* app,const void *pixels,const FXString& type) const {
490   FXImage *image=NULL;
491   if(pixels){
492     FXMemoryStream store;
493     store.open(FXStreamLoad,(FXuchar*)pixels);
494     image=loadImageStream(app,store,type);
495     store.close();
496     }
497   return image;
498   }
499 
500 
501 // Load from already open stream
loadImageStream(FXApp * app,FXStream & store,const FXString & type) const502 FXImage *FXIconSource::loadImageStream(FXApp* app,FXStream& store,const FXString& type) const {
503   FXImage *image=NULL;
504   if(!type.empty()){
505     image=imageFromType(app,type);
506     }
507   if(!image){
508     image=imageFromStream(app,store);
509     }
510   if(image){
511     if(image->loadPixels(store)) return image;
512     delete image;
513     }
514   return NULL;
515   }
516 
517 
518 // Load icon and scale it such that its dimensions does not exceed given size
loadScaledIconFile(FXApp * app,const FXString & filename,FXint size,FXint qual,const FXString & type) const519 FXIcon *FXIconSource::loadScaledIconFile(FXApp* app,const FXString& filename,FXint size,FXint qual,const FXString& type) const {
520   return (FXIcon*)scaleToSize(loadIconFile(app,filename,type),size,qual);
521   }
522 
523 
524 // Load from data array
loadScaledIconData(FXApp * app,const void * pixels,FXint size,FXint qual,const FXString & type) const525 FXIcon *FXIconSource::loadScaledIconData(FXApp* app,const void *pixels,FXint size,FXint qual,const FXString& type) const {
526   return (FXIcon*)scaleToSize(loadIconData(app,pixels,type),size,qual);
527   }
528 
529 
530 // Load icon and scale it such that its dimensions does not exceed given size
loadScaledIconStream(FXApp * app,FXStream & store,FXint size,FXint qual,const FXString & type) const531 FXIcon *FXIconSource::loadScaledIconStream(FXApp* app,FXStream& store,FXint size,FXint qual,const FXString& type) const {
532   return (FXIcon*)scaleToSize(loadIconStream(app,store,type),size,qual);
533   }
534 
535 
536 // Load image and scale it such that its dimensions does not exceed given size
loadScaledImageFile(FXApp * app,const FXString & filename,FXint size,FXint qual,const FXString & type) const537 FXImage *FXIconSource::loadScaledImageFile(FXApp* app,const FXString& filename,FXint size,FXint qual,const FXString& type) const {
538   return scaleToSize(loadImageFile(app,filename,type),size,qual);
539   }
540 
541 
542 // Load from data array
loadScaledImageData(FXApp * app,const void * pixels,FXint size,FXint qual,const FXString & type) const543 FXImage *FXIconSource::loadScaledImageData(FXApp* app,const void *pixels,FXint size,FXint qual,const FXString& type) const {
544   return (FXImage*)scaleToSize(loadImageData(app,pixels,type),size,qual);
545   }
546 
547 
548 // Load image and scale it such that its dimensions does not exceed given size
loadScaledImageStream(FXApp * app,FXStream & store,FXint size,FXint qual,const FXString & type) const549 FXImage *FXIconSource::loadScaledImageStream(FXApp* app,FXStream& store,FXint size,FXint qual,const FXString& type) const {
550   return scaleToSize(loadImageStream(app,store,type),size,qual);
551   }
552 
553 }
554