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