1 /*****************************************************************************
2 * This file is part of gfxprim library. *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
19 * Copyright (C) 2009-2014 Cyril Hrubis <metan@ucw.cz> *
21 *****************************************************************************/
25 General functions for loading and saving bitmaps.
32 #include <sys/types.h>
37 #include "core/GP_Debug.h"
39 #include "loaders/GP_Loaders.h"
40 #include "loaders/GP_Loader.h"
42 #define MAX_LOADERS 64
44 static const GP_Loader
*loaders
[MAX_LOADERS
] = {
60 static unsigned int get_last_loader(void)
64 for (i
= 0; i
< MAX_LOADERS
; i
++) {
72 int GP_LoaderRegister(const GP_Loader
*self
)
76 GP_DEBUG(1, "Registering loader for '%s'", self
->fmt_name
);
78 /* We have to keep the last terminating NULL */
79 for (i
= 0; i
< MAX_LOADERS
- 2; i
++) {
80 if (loaders
[i
] == self
) {
81 GP_DEBUG(1, "Loader '%s' allready registered",
92 GP_DEBUG(1, "Loaders table is full");
102 void GP_LoaderUnregister(const GP_Loader
*self
)
104 unsigned int i
, last
= get_last_loader();
109 GP_DEBUG(1, "Unregistering loader for '%s'", self
->fmt_name
);
111 for (i
= 0; loaders
[i
]; i
++) {
112 if (loaders
[i
] == self
) {
113 loaders
[i
] = loaders
[last
];
114 loaders
[last
] = NULL
;
119 GP_WARN("Loader '%s' (%p) wasn't registered", self
->fmt_name
, self
);
122 void GP_ListLoaders(void)
126 for (i
= 0; loaders
[i
]; i
++) {
127 printf("Format: %s\n", loaders
[i
]->fmt_name
);
128 printf("Read:\t%s\n", loaders
[i
]->Read
? "Yes" : "No");
129 printf("Write:\t%s\n", loaders
[i
]->Write
? "Yes" : "No");
130 if (loaders
[i
]->save_ptypes
) {
131 printf("Write Pixel Types: ");
132 for (j
= 0; loaders
[i
]->save_ptypes
[j
]; j
++) {
133 GP_PixelType ptype
= loaders
[i
]->save_ptypes
[j
];
134 printf("%s ", GP_PixelTypeName(ptype
));
138 printf("Match:\t%s\n", loaders
[i
]->Match
? "Yes" : "No");
139 printf("Extensions: ");
140 for (j
= 0; loaders
[i
]->extensions
[j
]; j
++)
141 printf("%s ", loaders
[i
]->extensions
[j
]);
144 if (loaders
[i
+1] != NULL
)
149 static const GP_Loader
*loader_by_extension(const char *ext
)
153 for (i
= 0; loaders
[i
]; i
++) {
154 for (j
= 0; loaders
[i
]->extensions
[j
] != NULL
; j
++) {
155 if (!strcasecmp(ext
, loaders
[i
]->extensions
[j
])) {
156 GP_DEBUG(1, "Found loader '%s'",
157 loaders
[i
]->fmt_name
);
166 static const char *get_ext(const char *path
)
168 size_t len
= strlen(path
);
171 for (i
= len
- 1; i
>= 0; i
--)
181 const GP_Loader
*GP_LoaderByFilename(const char *path
)
183 const char *ext
= get_ext(path
);
188 GP_DEBUG(1, "Loading file by filename extension '%s'", ext
);
190 return loader_by_extension(ext
);
193 static const GP_Loader
*loader_by_signature(const char *path
)
199 const GP_Loader
*ret
;
201 GP_DEBUG(1, "Trying to load by file signature");
203 f
= fopen(path
, "rb");
207 GP_DEBUG(1, "Failed to open file '%s'", path
);
211 if (fread(buf
, sizeof(buf
), 1, f
) < 1) {
212 GP_DEBUG(1, "Failed to read start of the file '%s'", path
);
219 ret
= GP_LoaderBySignature(buf
);
232 GP_Context
*GP_ReadImage(GP_IO
*io
, GP_ProgressCallback
*callback
)
236 const GP_Loader
*loader
;
238 start
= GP_IOTell(io
);
239 if (start
== (off_t
)-1) {
240 GP_DEBUG(1, "Failed to get IO stream offset: %s",
245 if (GP_IOFill(io
, buf
, sizeof(buf
))) {
246 GP_DEBUG(1, "Failed to read first 32 bytes: %s",
251 if (GP_IOSeek(io
, start
, GP_IO_SEEK_SET
) != start
) {
252 GP_DEBUG(1, "Failed to seek at the start of the stream: %s",
257 loader
= GP_LoaderBySignature(buf
);
260 GP_DEBUG(1, "Failed to find a loader by signature for"
261 "(%x (%c) %x (%c)...)",
262 buf
[0], isprint(buf
[0]) ? buf
[0] : ' ',
263 buf
[1], isprint(buf
[1]) ? buf
[1] : ' ');
269 GP_DEBUG(1, "Loader for '%s' does not support reading",
275 return loader
->Read(io
, callback
);
278 GP_Context
*GP_LoaderLoadImage(const GP_Loader
*self
, const char *src_path
,
279 GP_ProgressCallback
*callback
)
285 GP_DEBUG(1, "Loading Image '%s'", src_path
);
292 io
= GP_IOFile(src_path
, GP_IO_RDONLY
);
296 res
= self
->Read(io
, callback
);
305 GP_Context
*GP_LoadImage(const char *src_path
, GP_ProgressCallback
*callback
)
310 if (access(src_path
, R_OK
)) {
312 GP_DEBUG(1, "Failed to access file '%s' : %s",
313 src_path
, strerror(errno
));
318 if (stat(src_path
, &st
)) {
319 GP_WARN("Failed to stat '%s': %s", src_path
, strerror(errno
));
321 if (st
.st_mode
& S_IFDIR
) {
328 const GP_Loader
*ext_load
= NULL
, *sig_load
;
330 ext_load
= GP_LoaderByFilename(src_path
);
333 img
= GP_LoaderLoadImage(ext_load
, src_path
, callback
);
339 sig_load
= loader_by_signature(src_path
);
342 * Avoid further work if extension matches the signature but image
343 * couldn't be loaded. Probably unimplemented format or damaged file.
345 if (ext_load
== sig_load
)
348 if (ext_load
&& sig_load
) {
349 GP_WARN("File '%s': Extension says %s but signature %s",
350 src_path
, ext_load
->fmt_name
, sig_load
->fmt_name
);
354 return GP_LoaderLoadImage(sig_load
, src_path
, callback
);
360 int GP_LoadMetaData(const char *src_path
, GP_MetaData
*data
)
365 if (access(src_path
, R_OK
)) {
367 GP_DEBUG(1, "Failed to access file '%s' : %s",
368 src_path
, strerror(errno
));
373 ext
= get_ext(src_path
);
378 if (!strcasecmp(ext
, "jpg") || !strcasecmp(ext
, "jpeg"))
379 return GP_LoadJPGMetaData(src_path
, data
);
381 if (!strcasecmp(ext
, "png"))
382 return GP_LoadPNGMetaData(src_path
, data
);
389 int GP_LoaderSaveImage(const GP_Loader
*self
, const GP_Context
*src
,
390 const char *dst_path
, GP_ProgressCallback
*callback
)
394 GP_DEBUG(1, "Saving image '%s' format %s", dst_path
, self
->fmt_name
);
401 io
= GP_IOFile(dst_path
, GP_IO_WRONLY
);
406 if (self
->Write(src
, io
, callback
)) {
412 if (GP_IOClose(io
)) {
420 int GP_SaveImage(const GP_Context
*src
, const char *dst_path
,
421 GP_ProgressCallback
*callback
)
423 const GP_Loader
*l
= GP_LoaderByFilename(dst_path
);
430 return GP_LoaderSaveImage(l
, src
, dst_path
, callback
);
433 const GP_Loader
*GP_LoaderBySignature(const void *buf
)
437 for (i
= 0; loaders
[i
]; i
++) {
438 if (loaders
[i
]->Match
&& loaders
[i
]->Match(buf
) == 1) {
439 GP_DEBUG(1, "Found loader '%s'", loaders
[i
]->fmt_name
);
444 GP_DEBUG(1, "Loader not found");