This is an automated email from the git hooks/post-receive script. It was generated because a ref change was pushed to the repository containing the project gfxprim.git.
The branch, master has been updated via 10a52540db85b4635b27062dc42e5be14f760088 (commit) via 342537c6df7ca58ca4ac35d0b6f1dae16ef6746a (commit) via f36c5f6d8df50ad268711cc97c9bc369672b7fe8 (commit) from 40750bfe2c6ba222376f458bb80e8e48ecf93e52 (commit)
Those revisions listed above that are new to this repository have not appeared on any other notification email; so we list those revisions in full, below.
- Log ----------------------------------------------------------------- http://repo.or.cz/w/gfxprim.git/commit/10a52540db85b4635b27062dc42e5be14f760...
commit 10a52540db85b4635b27062dc42e5be14f760088 Author: Cyril Hrubis metan@ucw.cz Date: Sat Jan 4 00:55:28 2014 +0100
loaders: Add I/O abstraction and convert loaders.
This commit adds and abstract I/O interface and converts all image loaders to use it. This is a big step towards better faster and nicer containers (i.e. tar, tar.bz2, tar, etc...). It also allows you to read images from memory or whatever else for what by implementing simple read() and seek() wrappers.
It also updates loaders documentation, adds a few testcases and example for loading images from a memory buffer.
BEWARE: The work is not finalized and only basically tested. The ZIP loader is a bit broken (seeking does not work correctly). (More tests and fixes will come soon)
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/build/syms/Loaders_symbols.txt b/build/syms/Loaders_symbols.txt index e424e98..d2121fe 100644 --- a/build/syms/Loaders_symbols.txt +++ b/build/syms/Loaders_symbols.txt @@ -2,7 +2,6 @@ GP_FWrite GP_FRead
GP_MatchJPG -GP_OpenJPG GP_ReadJPG GP_LoadJPG GP_SaveJPG @@ -10,7 +9,6 @@ GP_ReadJPGMetaData GP_LoadJPGMetaData
GP_MatchPNG -GP_OpenPNG GP_ReadPNG GP_LoadPNG GP_ReadPNGMetaData @@ -18,45 +16,44 @@ GP_LoadPNGMetaData GP_SavePNG
GP_MatchBMP -GP_OpenBMP GP_LoadBMP GP_ReadBMP GP_SaveBMP
GP_MatchPSP -GP_OpenPSP GP_ReadPSP GP_LoadPSP
GP_MatchGIF GP_LoadGIF GP_ReadGIF -GP_OpenGIF
GP_MatchTIFF -GP_OpenTIFF GP_ReadTIFF GP_LoadTIFF GP_SaveTIFF
-GP_SavePBM +GP_ReadPBM GP_LoadPBM +GP_SavePBM GP_MatchPBM
-GP_SavePGM +GP_ReadPGM GP_LoadPGM +GP_SavePGM GP_MatchPGM
-GP_SavePPM +GP_ReadPPM GP_LoadPPM +GP_SavePPM GP_MatchPPM
+GP_ReadPNM GP_LoadPNM GP_SavePNM GP_MatchPNM
GP_ReadJP2 -GP_OpenJP2 GP_LoadJP2 GP_MatchJP2
@@ -94,3 +91,10 @@ GP_OpenZip
GP_LineConvertible GP_LineConvertGet + +GP_IOFile +GP_IOMem +GP_IOMark +GP_IOSize +GP_IOFill +GP_IOReadF diff --git a/demos/c_simple/Makefile b/demos/c_simple/Makefile index 2d91834..68fa14a 100644 --- a/demos/c_simple/Makefile +++ b/demos/c_simple/Makefile @@ -19,7 +19,7 @@ APPS=backend_example loaders_example loaders filters_symmetry gfx_koch input_example fileview linetest randomshapetest fonttest loaders_register blittest textaligntest sin_AA x11_windows debug_handler gaussian_noise byte_utils version pretty_print timers- zip_container backend_timers_example + zip_container backend_timers_example memory_io
ifeq ($(HAVE_LIBSDL),yes) APPS+=SDL_glue @@ -57,6 +57,7 @@ blittest: LDLIBS+=$(LDLIBS_BACKENDS) $(LDLIBS_LOADERS) sin_AA: LDLIBS+=$(LDLIBS_BACKENDS) x11_windows: LDLIBS+=$(LDLIBS_BACKENDS) zip_container: LDLIBS+=$(LDLIBS_LOADERS) $(LDLIBS_BACKENDS) +memory_io: LDLIBS+=$(LDLIBS_BACKENDS) $(LDLIBS_LOADERS)
include $(TOPDIR)/app.mk include $(TOPDIR)/post.mk diff --git a/demos/c_simple/memory_io.c b/demos/c_simple/memory_io.c new file mode 100644 index 0000000..873b27c --- /dev/null +++ b/demos/c_simple/memory_io.c @@ -0,0 +1,118 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + + /* + + Simple memory IO example. + + */ + +#include <stdio.h> +#include <GP.h> + +/* + * Binary PGM stored in an array + */ +static char pgm[] = { + /* header */ + 'P', '5', 'n', + '1', '0', ' ', '1', '0', 'n', + '2', '5', '5', 'n', + /* data */ + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, +}; + +#define WIN_W 100 +#define WIN_H 100 + +int main(void) +{ + GP_Backend *b; + GP_Context *img; + GP_IO *io; + + io = GP_IOMem(pgm, sizeof(pgm), NULL); + + if (!io) { + fprintf(stderr, "Failed to initialize IOn"); + return 1; + } + + img = GP_ReadPGM(io, NULL); + GP_IOClose(io); + + if (!img) { + fprintf(stderr, "Failed to load imagen"); + return 1; + } + + b = GP_BackendX11Init(NULL, 0, 0, WIN_W, WIN_H, "IO Example", 0); + + if (!b) { + fprintf(stderr, "Failed to initialize backendn"); + return 1; + } + + GP_Fill(b->context, 0); + GP_Blit_Clipped(img, 0, 0, img->w, img->h, b->context, + (WIN_W - img->w)/2, (WIN_H - img->h)/2); + GP_BackendFlip(b); + + for (;;) { + GP_Event ev; + + GP_BackendWaitEvent(b, &ev); + + switch (ev.type) { + case GP_EV_KEY: + switch (ev.val.val) { + case GP_KEY_ESC: + case GP_KEY_Q: + GP_BackendExit(b); + return 0; + break; + } + break; + case GP_EV_SYS: + switch (ev.code) { + case GP_EV_SYS_RESIZE: + case GP_EV_SYS_QUIT: + GP_BackendExit(b); + return 0; + break; + } + break; + } + } + + GP_BackendExit(b); + return 0; +} diff --git a/doc/Makefile b/doc/Makefile index 05ae191..ac8868c 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -5,7 +5,7 @@ SOURCES=index.html about.txt context.txt loaders.txt filters.txt get_put_pixel.txt blits.txt progress_callback.txt text.txt event_queue.txt compilation.txt filters_resize.txt filters_dithering.txt filters_python.txt spiv.txt core_common.txt - convert.txt news_1_0_0-rc1.txt + convert.txt news_1_0_0-rc1.txt loaders_io.txt
SOURCES+=core_python.txt gfx_python.txt loaders_python.txt backends_python.txt
diff --git a/doc/example_memory_io.txt b/doc/example_memory_io.txt new file mode 100644 index 0000000..1488bba --- /dev/null +++ b/doc/example_memory_io.txt @@ -0,0 +1,9 @@ +Memory IO with Loaders +---------------------- + +This example shows how to read an image from a memory buffer. + +[source,c] +------------------------------------------------------------------ +include::../demos/c_simple/memory_io.c[] +------------------------------------------------------------------ diff --git a/doc/loaders.txt b/doc/loaders.txt index b42c47e..5ac5743 100644 --- a/doc/loaders.txt +++ b/doc/loaders.txt @@ -3,22 +3,25 @@ Context loaders This part of GFXprim library aims to create API to load and save images from/to common image file formats.
-Currently we support JPEG, PNG, BMP, TIFF and PNM images for loading and -saving and GIF, JPEG2000 and PSP for loading. +Currently we support 'JPEG', 'PNG', 'BMP', 'TIFF' and 'PNM' images for loading +and saving and 'GIF', 'JPEG2000' and 'PSP' for loading.
Have a look at the link:about.html#Loaders[supported formats].
Image Loaders and Savers ~~~~~~~~~~~~~~~~~~~~~~~~
-All loading functions returns a pointer to allocated and loaded image or upon -a failure 'NULL'. +All loading functions exists in at least two flavors. One that works with a +path to a file and one that reads from an link:loaders_io.html[IO stream]. + +All loading functions returns a pointer to newly allocated and loaded image +or upon a failure 'NULL' and 'errno' is set.
All saving functions returns zero on success and non-zero on failure. If image saving is aborted by a callback, the opened file is closed and removed -from a filesystem before the call returns. +from a file-system before the call returns.
-The signature matching functions takes a 32 bytes long buffer and looks for a +The signature matching functions takes a 32 bytes long buffer and looks for a valid image signature. If signature is found non-zero is returned.
In case of a failure 'errno' is set, possible 'errno' values are: @@ -36,7 +39,6 @@ In case of a failure 'errno' is set, possible 'errno' values are: You can get more information about the error condition by turning on GFXprim link:environment_variables.html#GP_DEBUG[debug messages].
- [[Load_Image]] [source,c] ------------------------------------------------------------------------------- @@ -50,7 +52,7 @@ GP_Context *GP_LoadImage(const char *src_path, GP_ProgressCallback *callback); Loads an image from a file.
The image format is first guessed by the file extension. If loader for the -file extension is found it's called and if it succedes the image data is +file extension is found it's called and if it succeeds the image data is returned.
If file extension based guess fails either because the extension wasn't @@ -105,7 +107,7 @@ typedef struct GP_Loader { /* * Save an image. * - * Returns zero on succes, non-zero on failure and errno must be set. + * Returns zero on success, non-zero on failure and errno must be set. */ int (*Save)(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback); @@ -192,9 +194,9 @@ const GP_Loader *GP_MatchExtension(const char *path)
Matches loader by the file extension. This function does not check that the file exists or that it could be opened it only looks at the extension (i.e. -string after the dot) and matches it agains known extensions. +string after the dot) and matches it against known extensions.
-WARNING: If you attempt to modify the content of the strucutre the behavior is +WARNING: If you attempt to modify the content of the structure the behavior is undefined. Most likely the program will crash.
PNG Loader @@ -207,28 +209,14 @@ The 'PNG' image support is implemented by the libpng library. /* or */ #include <GP.h>
-int GP_OpenPNG(const char *src_path, FILE **f); +GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Opens file and checks for 'PNG' signature. Returns zero on success (file -could be opened, signature matches), the opened file is returned and the file -position points right after the end of the 'PNG' signature. +Reads a 'PNG' image from readable 'GP_IO'. The link:loaders_io.html[IO stream] +is expected to start exactly at the 'PNG' file signature.
-This function is semi-internal, you should rather use functions listed below. - -[source,c] -------------------------------------------------------------------------------- -#include <loaders/GP_PNG.h> -/* or */ -#include <GP.h> - -GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback); -------------------------------------------------------------------------------- - -Loads 'PNG' file into context the file pointer must point to the start of the -'PNG' data stream (i.e. should point right after the signature). The context, -to store the image to, is allocated. The loading process could by aborted by a -callback, in such case all memory is freed. +Returns newly allocated context (containing decompressed image) or in case of +failure 'NULL' and 'errno' is set.
[source,c] ------------------------------------------------------------------------------- @@ -239,8 +227,10 @@ callback, in such case all memory is freed. GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the -signature. Basically this combines both of the calls above. +Loads a 'PNG' image from a file. + +Returns a pointer to newly allocated loaded image, or in case of failure +'NULL' and 'errno' is set.
[source,c] ------------------------------------------------------------------------------- @@ -252,9 +242,11 @@ int GP_SavePNG(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Currently only 'RGB888' format is supported, you should convert the -'GP_Context' to 'RGB888' before calling this function otherwise non-zero is -returned and 'errno' is set to 'ENOSYS'. +Saves a 'Context' into a 'PNG' image, in case particular pixel type is not +supported non-zero is returned and 'errno' is set to 'ENOSYS'. + +Supports 'G1', 'G2', 'G4', 'G8', 'G16', and 8-bit 'RGB' and 'RGBA' pixel +types.
[source,c] ------------------------------------------------------------------------------- @@ -265,7 +257,7 @@ returned and 'errno' is set to 'ENOSYS'. int GP_MatchPNG(const void *buf); -------------------------------------------------------------------------------
-Matches a PNG signature. +Matches a 'PNG' file signature. Returns non-zero if found.
JPEG Loader ~~~~~~~~~~~ @@ -277,32 +269,14 @@ The 'JPEG' image support is implemented by the jpeg library. /* or */ #include <GP.h>
-int GP_OpenJPG(const char *src_path, FILE **f); +GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Opens file and checks for 'JPG' signature upon successful return (file could -be opened, signature matches), the opened file is returned and the file -position points right after the end of the 'JPG' signature. +Reads a 'JPEG' image from readable 'GP_IO'. The link:loaders_io.html[IO +stream] is expected to start exactly at the 'JPEG' file signature.
-This function is semi-internal, you should rather use functions listed below. - -'TODO:' This is not finished yet, currently this just opens and returns the -file and the 'GP_ReadJPG()' reads the signature instead. - -[source,c] -------------------------------------------------------------------------------- -#include <loaders/GP_JPG.h> -/* or */ -#include <GP.h> - -GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback); -------------------------------------------------------------------------------- - -Loads 'JPG' file into context the file pointer must point to the start of the -'JPG' data stream (i.e. should point right after the signature). The context, -to store the image to, is allocated. The loading process could by aborted by a -callback, in such case all memory is freed and the call returns 'NULL' and -'errno' is set to 'ECANCELED'. +Returns newly allocated context (containing decompressed image) or in case of +failure 'NULL' and 'errno' is set.
[source,c] ------------------------------------------------------------------------------- @@ -313,8 +287,10 @@ callback, in such case all memory is freed and the call returns 'NULL' and GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the -signature. Basically this combines both of the calls above. +Loads an 'JPEG' image from a file. + +Returns a pointer to newly allocated loaded image, or in case of failure +'NULL' and 'errno' is set.
[source,c] ------------------------------------------------------------------------------- @@ -326,12 +302,11 @@ int GP_SaveJPG(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Writes a Context into a 'JPG' image. If aborted by a callback, the opened file -is closed and removed before the call returns non-zero and 'errno' is set to -'ECANCELED'. +Writes a 'Context' into a 'JPEG' image. If aborted by a callback, the opened +file is closed and removed before the call returns non-zero and 'errno' is set +to 'ECANCELED'.
-The 'JPG' format could store either 'G8' or 'RGB888' pixeltypes and you must -convert the context into one of them before this functions is called. +The 'JPEG' format could store either 'G8' or 8-bit 'RGB' pixel-types.
[source,c] ------------------------------------------------------------------------------- @@ -342,7 +317,7 @@ convert the context into one of them before this functions is called. int GP_MatchJPG(const void *buf); -------------------------------------------------------------------------------
-Matches a JPG signature. +Matches a 'JPEG' file signature. Returns non-zero if found.
JPEG 2000 Loader ~~~~~~~~~~~~~~~~ @@ -354,32 +329,45 @@ The 'JPEG 2000' image support is implemented using the openjpeg library. /* or */ #include <GP.h>
-GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback); +GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Loads 'JPEG 2000' image. +Reads a 'JPEG2000' image from readable 'GP_IO'. The link:loaders_io.html[IO +stream] is expected to start exactly at the 'JPEG2000' file signature.
-Due to limitations of the openjpeg library progress callback does not work. +Returns newly allocated context (containing decompressed image) or in case of +failure 'NULL' and 'errno' is set.
-GIF Loader -~~~~~~~~~~ +NOTE: Due to limitations of the openjpeg library progress callback does not work.
-The 'GIF' image support is implemented by the giflib library. +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_JP2.h> +/* or */ +#include <GP.h> + +GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback); +------------------------------------------------------------------------------- + +Loads 'JPEG2000' image from a file. + +NOTE: Due to limitations of the openjpeg library progress callback does not work.
[source,c] ------------------------------------------------------------------------------- -#include <loaders/GP_GIF.h> +#include <loaders/GP_JP2.h> /* or */ #include <GP.h>
-int GP_OpenGIF(const char *src_path, void **f); +int GP_MatchJP2(const void *buf); -------------------------------------------------------------------------------
-Opens file and checks for 'GIF' signature upon successful return (file could -be opened, signature matches) zero is returned and gif handle f is set -otherwise non-zero is returned and 'errno' is set. +Matches a 'JPEG2000' file signature. Returns non-zero if found. + +GIF Loader +~~~~~~~~~~
-This function is semi-internal, you should rather use functions listed below. +The 'GIF' image support is implemented by the giflib library.
[source,c] ------------------------------------------------------------------------------- @@ -387,16 +375,16 @@ This function is semi-internal, you should rather use functions listed below. /* or */ #include <GP.h>
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback); +GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Loads 'GIF' file into context. The pointer must point to the 'GIF' handle as -returned by 'GP_OpenGIF()' function. The context, to store the image to, is -allocated. The loading process could by aborted by a callback, in such case -all memory is freed and the call returns 'NULL' and 'errno' is set to -'ECANCELED'. +Reads a 'GIF' image from readable 'GP_IO'. The link:loaders_io.html[IO stream] +is expected to start exactly at the 'GIF' file signature. + +Returns newly allocated context (containing decompressed image) or in case of +failure 'NULL' and 'errno' is set.
-Currently this function loads only first image from the gif container. +NOTE: Currently this function loads only first image from the 'GIF' container.
[source,c] ------------------------------------------------------------------------------- @@ -407,8 +395,7 @@ Currently this function loads only first image from the gif container. GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the -signature. Basically this combines both of the calls above. +Loads 'GIF' image from a file.
[source,c] ------------------------------------------------------------------------------- @@ -419,7 +406,7 @@ signature. Basically this combines both of the calls above. int GP_MatchGIF(const void *buf); -------------------------------------------------------------------------------
-Matches a GIF signature. +Matches a 'GIF' file signature. Returns non-zero if found.
BMP Loader ~~~~~~~~~~ @@ -433,30 +420,14 @@ be exotic RGB compressions (RGB101010 for example) and RLE4 support. /* or */ #include <GP.h>
-int GP_OpenBMP(const char *src_path, FILE **f, - GP_Size *w, GP_Size *h, GP_PixelType *pixel_type); -------------------------------------------------------------------------------- - -Opens file and checks for 'BMP' signature upon successful return (file could -be opened, signature matches) zero is returned and the parameters, if -non-'NULL', are initialized. Upon failure non-zero is returned and 'errno' is -set. - -This function is semi-internal, you should rather use functions listed below. - -[source,c] +GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback); ------------------------------------------------------------------------------- -#include <loaders/GP_BMP.h> -/* or */ -#include <GP.h>
-GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback); -------------------------------------------------------------------------------- +Reads a 'BMP' image from readable 'GP_IO'. The link:loaders_io.html[IO stream] +is expected to start exactly at the 'BMP' file signature.
-Loads 'BMP' file into context. The 'FILE' pointer must point to opened 'BMP' -file. The context, to store the image to, is allocated. The loading process -could by aborted by a callback, in such case all memory is freed and the call -returns 'NULL' and 'errno' is set to 'ECANCELED'. +Returns newly allocated context (containing decompressed image) or in case of +failure 'NULL' and 'errno' is set.
[source,c] ------------------------------------------------------------------------------- @@ -467,8 +438,7 @@ returns 'NULL' and 'errno' is set to 'ECANCELED'. GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and check for the -signature. Basically this combines both of the calls above. +Loads 'BMP' image from a file.
[source,c] ------------------------------------------------------------------------------- @@ -480,7 +450,9 @@ int GP_SaveBMP(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Saves 'RGB888' (24 bit RGB) image into BMP bitmap. +Writes a 'Context' into a 'BMP' file. + +Currently only 8-bit 'RGB' formats are supported.
[source,c] ------------------------------------------------------------------------------- @@ -491,7 +463,7 @@ Saves 'RGB888' (24 bit RGB) image into BMP bitmap. int GP_MatchBMP(const void *buf); -------------------------------------------------------------------------------
-Matches a BMP signature. +Matches a 'BMP' file signature. Returns non-zero if found.
PSP Loader ~~~~~~~~~~ @@ -504,23 +476,14 @@ The 'PSP' loader can load a composite image from a Paint Shop Pro Image Files. /* or */ #include <GP.h>
-int GP_OpenPSP(const char *src_path, FILE **f); -------------------------------------------------------------------------------- - -Opens file and checks for 'PSP' signature. Upon successful return (file could -be opened, signature matches) zero is returned. Upon failure non-zero is -returned and 'errno' is set. - -[source,c] +GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback); ------------------------------------------------------------------------------- -#include <loaders/GP_PSP.h> -/* or */ -#include <GP.h>
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback); -------------------------------------------------------------------------------- +Reads a 'PSP' image from readable 'GP_IO'. The link:loaders_io.html[IO stream] +is expected to start exactly at the 'PSP' file signature.
-Reads 'PSP' image into a context. +Returns newly allocated context (containing decompressed image) or in case of +failure 'NULL' and 'errno' is set.
[source,c] ------------------------------------------------------------------------------- @@ -531,8 +494,7 @@ Reads 'PSP' image into a context. GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Same as above but takes path to the file as a parameter and checks for the -signature. Basically this combines both of the calls above. +Loads a composite image from a 'PSP' file.
[source,c] ------------------------------------------------------------------------------- @@ -543,10 +505,10 @@ signature. Basically this combines both of the calls above. int GP_MatchPSP(const void *buf); -------------------------------------------------------------------------------
-Matches a PSP signature. +Matches a 'PSP' file signature. Returns non-zero if found.
-PNM -~~~ +PNM Loaders +~~~~~~~~~~~
[source,c] ------------------------------------------------------------------------------- @@ -563,10 +525,9 @@ GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback); GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Loads either ASCII or Rawbits (binary) PBM, PGM and PPM. - -The PNM can load all of them i.e. PBM, PGM and PPM. +Loads either ASCII or Rawbits (binary) 'PBM', 'PGM' and 'PPM'.
+The 'PNM' can load all of them i.e. 'PBM', 'PGM' and 'PPM'.
[source,c] ------------------------------------------------------------------------------- @@ -578,7 +539,7 @@ GP_Context *GP_SavePBM(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Saves 'G1' (1 bit grayscale) image into ASCII PBM. +Saves 'G1' (1 bit grayscale) image into ASCII 'PBM'.
[source,c] ------------------------------------------------------------------------------- @@ -591,7 +552,7 @@ GP_Context *GP_SavePGM(const GP_Context *src, const char *dst_path, -------------------------------------------------------------------------------
Saves 'G1', 'G2', 'G4' and 'G8' (1, 2, 4 and 8 bit grayscale) image into ASCII -PGM. +'PGM'.
[source,c] ------------------------------------------------------------------------------- @@ -603,7 +564,7 @@ GP_Context *GP_SavePPM(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback); -------------------------------------------------------------------------------
-Saves 'RGB888' (24 bit RGB) image into ASCII PPM. +Saves 'RGB888' (24 bit RGB) image into ASCII 'PPM'.
[source,c] ------------------------------------------------------------------------------- @@ -616,7 +577,7 @@ GP_Context *GP_SavePNM(const GP_Context *src, const char *dst_path, -------------------------------------------------------------------------------
Saves 'G1', 'G2', 'G4' and 'G8' (1, 2, 4, 8 bit grayscale) or 'RGB888' (24 bit -RGB) image into ASCII PNM. +RGB) image into ASCII 'PNM'.
[source,c] ------------------------------------------------------------------------------- @@ -633,7 +594,9 @@ int GP_MatchPPM(const void *buf); int GP_MatchPNM(const void *buf); -------------------------------------------------------------------------------
-Matches either ASCII or Rawbits (binary) PBM, PGM and PPM. +Matches either ASCII or Rawbits (binary) 'PBM', 'PGM' and 'PPM' file +signatures.
-The PNM matches all of them i.e. PBM, PGM and PPM. +The 'PNM' matches all of the formats. i.e. 'PBM', 'PGM' and 'PPM'.
+All functions return non-zero if found. diff --git a/doc/loaders_io.txt b/doc/loaders_io.txt new file mode 100644 index 0000000..e12e746 --- /dev/null +++ b/doc/loaders_io.txt @@ -0,0 +1,190 @@ +IO Interface +------------ + +GFXprim implements an I/O interface which is used by all image loaders. + +The purpose of the interface is: + +* Make it easy to load and save images from/into memory buffers +* Fast and clean containers (ZIP for example) implementation + (zlib deflate could feed data directly into a memory based IO stream) + +The I/O interface is defined by a structure with callbacks. + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +/* + * Values are 1:1 with constants passed to lseek() + */ +enum GP_IOWhence { + GP_IO_SEEK_SET = 0, + GP_IO_SEEK_CUR = 1, + GP_IO_SEEK_END = 2, +}; + + +typedef struct GP_IO { + ssize_t (*Read)(struct GP_IO *self, void *buf, size_t size); + ssize_t (*Write)(struct GP_IO *self, void *buf, size_t size); + off_t (*Seek)(struct GP_IO *self, off_t off, enum GP_IOWhence whence); + int (*Close)(struct GP_IO *self); + + off_t mark; + char priv[]; +} GP_IO; +------------------------------------------------------------------------------- + +The fields of the I/O stream structure are mostly self describing. The 'Seek' +behaves exactly as 'lseek(2)', the 'Read' as 'read(2)' and the 'Write' as +'write(2)'. + +The 'mark' and 'priv' are private fields that shall not be touched by user. + +An IO reader must implement at least 'Read', 'Seek' (at least able to seek +forward to skip some data) and 'Close'. + +An IO writer must implement at least 'Write' and 'Close'. + +Return value from the 'Seek' is a value of current offset in the stream (after +the seek has been done) or in case of failure '(off_t)-1'. + +Return value from 'Read' or 'Write' is a number of bytes read/written or in +case of failure a negative number (-1). + +Return value from 'Close' is zero on success and non-zero on IO failure. + +NOTE: Make sure 'errno' is set if any of the operations has failed. + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +ssize_t GP_IORead(GP_IO *io, void *buf, size_t size); +------------------------------------------------------------------------------- + +This is a wrapper to 'io->Read()'. + +Reads at most 'size' bytes from an 'IO' stream and stores them into the +buffer. Returns number of bytes read. + +On failure the return value is negative and 'errno' is set. + + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +ssize_t GP_IOWrite(GP_IO *io, void *buf, size_t size); +------------------------------------------------------------------------------- + +This is a wrapper to 'io->Write()'. + +Writes at most 'size' bytes from an 'IO' stream and stores them into the +buffer. Returns number of bytes read. + +On failure the return value is negative and 'errno' is set. + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +int GP_IOClose(GP_IO *io); +------------------------------------------------------------------------------- + +This is a wrapper to 'io->Close()'. + +Finalizes reading/writing, closes file descriptors (in case of file IO), frees +memory buffers. + +Returns zero on success, non-zero on IO failure and 'errno' is set. + + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +off_t GP_IOSeek(GP_IO *io, off_t off, enum GP_IOWhence whence); +------------------------------------------------------------------------------- + +This is a wrapper to 'io->Seek()'. + +//TODO + + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +off_t GP_IOTell(GP_IO *io); +------------------------------------------------------------------------------- + +Wrapper to 'GP_IOSeek()', returns current position in IO stream. + + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +off_t GP_IORewind(GP_IO *io) +------------------------------------------------------------------------------- + +Wrapper to 'GP_IOSeek()', rewinds to the start of the IO stream. + +Returns zero on success, non-zero on failure and 'errno' is set. + + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *)); +------------------------------------------------------------------------------- + +Creates an read-only IO from a memory buffer. + +Returns initialized IO or in case of failure 'NULL' and 'errno' is set. + +The 'buf' is pointer to the start of the buffer, the 'size' is size in bytes. + +The 'free()' callback if not 'NULL' is called with the start of the buffer as +an argument on 'IOClose()'. + +TIP: See link:example_memory_io.html[memory IO example]. + +[source,c] +------------------------------------------------------------------------------- +#include <loaders/GP_IO.h> +/* or */ +#include <GP.h> + +enum GP_IOFileMode { + GP_IO_RDONLY = 0x00, + GP_IO_WRONLY = 0x01, + GP_IO_RDWR = 0x02, +}; + +GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode); +------------------------------------------------------------------------------- + +Creates an IO stream from a file. + +Returns a pointer to initialized IO stream, or in case of failure 'NULL' and +'errno' is set. diff --git a/include/loaders/GP_BMP.h b/include/loaders/GP_BMP.h index 4c5ca26..48eff73 100644 --- a/include/loaders/GP_BMP.h +++ b/include/loaders/GP_BMP.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -25,40 +25,18 @@
#include "core/GP_Context.h" #include "core/GP_ProgressCallback.h" +#include "loaders/GP_IO.h"
/* - * The possible errno values: + * Reads a BMP from an IO stream. * - * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...). - * - EIO for fread()/fwrite() failure - * - ENOSYS for not implemented bitmap format - * - ENOMEM from malloc() - * - EILSEQ for wrong image signature/data - * - ECANCELED when call was aborted from callback + * Returns newly allocated context cotaining the loaded image or in case of + * failure NULL and errno is set. */ +GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback);
/* - * Opens up a bmp file, checks signature, parses metadata. - * - * The file, width, height and pixel type are filled upon succcessful return. - * - * Upon failure, non zero return value is returned and errno is filled. - */ -int GP_OpenBMP(const char *src_path, FILE **f, - GP_Size *w, GP_Size *h, GP_PixelType *pixel_type); - -/* - * Reads a BMP from a opened file. - * - * Upon successful return, context to store bitmap is allocated and image is - * loaded. - * - * Upon failure NULL is returned and errno is filled. - */ -GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback); - -/* - * Does both GP_OpenBMP and GP_ReadBMP. + * Loads a BMP image from a file. */ GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback);
@@ -70,7 +48,7 @@ int GP_SaveBMP(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback);
/* - * Match BMP signature. + * Looks for BMP file signature. Returns non-zero if found. */ int GP_MatchBMP(const void *buf);
diff --git a/include/loaders/GP_GIF.h b/include/loaders/GP_GIF.h index b2ee363..23405e2 100644 --- a/include/loaders/GP_GIF.h +++ b/include/loaders/GP_GIF.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -29,37 +29,25 @@ #ifndef LOADERS_GP_GIF_H #define LOADERS_GP_GIF_H
-#include "core/GP_ProgressCallback.h" #include "core/GP_Context.h" +#include "core/GP_ProgressCallback.h" +#include "loaders/GP_IO.h"
/* - * The possible errno values: + * Reads first image found in GIF container from an IO stream. * - * - EIO for read/write failure - * - ENOSYS for not implemented bitmap format - * - ENOMEM from malloc() - * - EILSEQ for wrong image signature/data - * - ECANCELED when call was aborted from callback - */ - -/* - * Opens up the Gif image and checks signature. - * Returns zero on success. - */ -int GP_OpenGIF(const char *src_path, void **f); - -/* - * Reads first image found in GIF container. + * Returns newly allocated context cotaining the loaded image or in case of + * failure NULL and errno is set. */ -GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback); +GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback);
/* - * Does both GP_OpenGIF and GP_ReadGIF at once. + * Loads first image found in GIF container from a file. */ GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback);
/* - * Match GIF signature. + * Looks for GIF file signature. Returns non-zero if found. */ int GP_MatchGIF(const void *buf);
diff --git a/include/loaders/GP_IO.h b/include/loaders/GP_IO.h new file mode 100644 index 0000000..fa1046f --- /dev/null +++ b/include/loaders/GP_IO.h @@ -0,0 +1,184 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + + /* + + I/O abstraction for GFXprim loaders. + + */ + +#ifndef LOADERS_GP_IO_H +#define LOADERS_GP_IO_H + +#include <stdint.h> +#include <sys/types.h> + +/* + * Values are 1:1 with constants passed to lseek() + */ +enum GP_IOWhence { + GP_IO_SEEK_SET = 0, + GP_IO_SEEK_CUR = 1, + GP_IO_SEEK_END = 2, +}; + +typedef struct GP_IO { + ssize_t (*Read)(struct GP_IO *self, void *buf, size_t size); + ssize_t (*Write)(struct GP_IO *self, void *buf, size_t size); + off_t (*Seek)(struct GP_IO *self, off_t off, enum GP_IOWhence whence); + int (*Close)(struct GP_IO *self); + +// void *(*Map)(struct GP_IO *self, size_t len, off_t off); +// void (*UnMap)(struct GP_IO *self, void *addr, size_t len); + + off_t mark; + char priv[]; +} GP_IO; + +#define GP_IO_PRIV(io) ((void *)(io)->priv) + +/* + * Just inline wrappers. + */ +static inline ssize_t GP_IORead(GP_IO *io, void *buf, size_t size) +{ + return io->Read(io, buf, size); +} + +static inline ssize_t GP_IOWrite(GP_IO *io, void *buf, size_t size) +{ + return io->Write(io, buf, size); +} + +static inline int GP_IOClose(GP_IO *io) +{ + return io->Close(io); +} + +static inline off_t GP_IOSeek(GP_IO *io, off_t off, enum GP_IOWhence whence) +{ + return io->Seek(io, off, whence); +} + +//static inline void *GP_IOMap(GP_IO *io, size_t len, off_t off) +//{ +// return io->Map(io, len, off); +//} + +//static inline void *GP_IOUnMap(GP_IO *io, size_t len, off_t off) +//{ +// return io->UnMap(io, len, off); +//} + +/* + * Returns current offset + */ +static inline off_t GP_IOTell(GP_IO *io) +{ + return io->Seek(io, 0, GP_IO_SEEK_CUR); +} + +/* + * Rewinds to start of the I/O stream. + */ +static inline off_t GP_IORewind(GP_IO *io) +{ + return io->Seek(io, 0, GP_IO_SEEK_SET); +} + +/* + * Returns I/O stream size. + * + * May return (off_t)-1 in case that GP_IO_SEEK_END is not possible. + */ +off_t GP_IOSize(GP_IO *io); + +/* + * Like a Read but either fills whole buffer or returns error. + * + * Returns zero on success non-zero on failure. + */ +int GP_IOFill(GP_IO *io, void *buf, size_t size); + +/* + * Marks a current position, returns to mark in I/O stream. + */ +enum GP_IOMarkTypes { + GP_IO_MARK, + GP_IO_REWIND, +}; + +int GP_IOMark(GP_IO *self, enum GP_IOMarkTypes type); + +/* + * Formatted read. + * + * + */ +enum GP_IOReadFTypes { + /* Constant byte in lower half */ + GP_IO_CONST = 0x0000, + /* Pointer to one byte */ + GP_IO_BYTE = 0x0100, + /* Pointer to byte integer in litte endian */ + GP_IO_L2 = 0x0200, + /* Poiter to four byte integer in litte endian */ + GP_IO_L4 = 0x0300, + /* Pointer to two byte integer in big endian */ + GP_IO_B2 = 0x0400, + /* Pointer to four byte integer in big endian */ + GP_IO_B4 = 0x0500, + /* Pointer to byte array, size in lower half */ + GP_IO_ARRAY = 0x0600, + /* Ignore bytes on read, size in lower half */ + GP_IO_IGN = 0x0700, + GP_IO_I1 = GP_IO_IGN | 1, + GP_IO_I2 = GP_IO_IGN | 2, + GP_IO_I3 = GP_IO_IGN | 3, + GP_IO_I4 = GP_IO_IGN | 4, + /* End of the types array */ + GP_IO_END = 0xff00, +}; + +#define GP_IO_TYPE_MASK 0xff00 + +int GP_IOReadF(GP_IO *self, uint16_t *types, ...); + +enum GP_IOFileMode { + GP_IO_RDONLY = 0x00, + GP_IO_WRONLY = 0x01, + GP_IO_RDWR = 0x02, +}; + +/* + * Creates I/O from a file. On error NULL is returned and errno is set. + */ +GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode); + +/* + * Creates I/O from a memory buffer. + * + * If free is not NULL, it's called on buf pointer on GP_IOClose(). + */ +GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *)); + +#endif /* LOADERS_GP_IO_H */ diff --git a/include/loaders/GP_JP2.h b/include/loaders/GP_JP2.h index 7068a46..574cfbc 100644 --- a/include/loaders/GP_JP2.h +++ b/include/loaders/GP_JP2.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -31,24 +31,23 @@
#include "core/GP_Context.h" #include "core/GP_ProgressCallback.h" +#include "loaders/GP_IO.h"
/* - * Opens up file and checks signature. + * Reads a JPEG2000 from an IO stream. + * + * Returns newly allocated context cotaining the loaded image or in case of + * failure NULL and errno is set. */ -int GP_OpenJP2(const char *src_path, FILE **f); +GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback);
/* - * Reads JP2 from an open FILE. - */ -GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback); - -/* - * Loads a JP2 file into GP_Context. The Context is newly allocated. + * Loads a JPEG2000 image from a file. */ GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback);
/* - * Match JP2 signature. + * Looks for JPEG2000 file signature. Returns non-zero if found. */ int GP_MatchJP2(const void *buf);
diff --git a/include/loaders/GP_JPG.h b/include/loaders/GP_JPG.h index 8f6a920..95123ec 100644 --- a/include/loaders/GP_JPG.h +++ b/include/loaders/GP_JPG.h @@ -16,13 +16,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
/*
- JPG support using jpeg library. + JPEG support using jpeg library.
*/
@@ -31,22 +31,19 @@
#include "core/GP_Context.h" #include "core/GP_ProgressCallback.h" - -#include "GP_MetaData.h" - -/* - * Opens up file and checks signature. - */ -int GP_OpenJPG(const char *src_path, FILE **f); +#include "loaders/GP_IO.h" +#include "loaders/GP_MetaData.h"
/* - * Reads JPG from an open FILE. Expects the file position set after the eight - * bytes JPG signature. + * Reads a JPEG from an IO stream. + * + * Returns newly allocated context cotaining the loaded image or in case of + * failure NULL and errno is set. */ -GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback); +GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback);
/* - * Loads a JPG file into GP_Context. The Context is newly allocated. + * Loads a JPEG image from a file. */ GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback);
@@ -57,13 +54,13 @@ int GP_ReadJPGMetaData(FILE *f, GP_MetaData *data); int GP_LoadJPGMetaData(const char *src_path, GP_MetaData *data);
/* - * Saves JPG to a file. + * Saves JPEG to a file. */ int GP_SaveJPG(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback);
/* - * Match JPG signature. + * Looks for JPEG file signature. Returns non-zero if found. */ int GP_MatchJPG(const void *buf);
diff --git a/include/loaders/GP_Loader.h b/include/loaders/GP_Loader.h index 6522c0a..925f358 100644 --- a/include/loaders/GP_Loader.h +++ b/include/loaders/GP_Loader.h @@ -49,7 +49,7 @@ int GP_LoadMetaData(const char *src_path, GP_MetaData *data); /* * Simple saving function, the image format is matched by file extension. * - * Retruns zero on succes. + * Retruns zero on success. * * On failure non-zero is returned. * diff --git a/include/loaders/GP_PNG.h b/include/loaders/GP_PNG.h index e9b72ce..0b440d0 100644 --- a/include/loaders/GP_PNG.h +++ b/include/loaders/GP_PNG.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -31,38 +31,19 @@
#include "core/GP_ProgressCallback.h" #include "core/GP_Context.h" - -#include "GP_MetaData.h" - -/* - * The possible errno values: - * - * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...). - * - EIO for png_read()/png_write() failure - * - ENOSYS for not implemented bitmap format - * - ENOMEM from malloc() - * - EILSEQ for wrong image signature/data - * - ECANCELED when call was aborted from callback - */ - -/* - * Opens up file and checks signature. Upon successful return (zero is - * returned) the file position would be set to eight bytes (exactly after the - * PNG signature). - */ -int GP_OpenPNG(const char *src_path, FILE **f); +#include "loaders/GP_IO.h" +#include "loaders/GP_MetaData.h"
/* - * Reads PNG from an open FILE. Expects the file position set after the eight - * bytes PNG signature. + * Reads a PNG from an IO stream. * - * Upon succesfull return pointer to newly allocated context is returned. - * Otherwise NULL is returned and errno is filled. + * Returns newly allocated context cotaining the loaded image or in case of + * failure NULL and errno is set. */ -GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback); +GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback);
/* - * Does both GP_OpenPNG and GP_ReadPNG at once. + * Loads a PNG image from a file. */ GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback);
@@ -80,7 +61,7 @@ int GP_SavePNG(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback);
/* - * Match PNG signature. + * Looks for PNG file signature. Returns non-zero if found. */ int GP_MatchPNG(const void *buf);
diff --git a/include/loaders/GP_PNM.h b/include/loaders/GP_PNM.h index 150ff21..4f2dd11 100644 --- a/include/loaders/GP_PNM.h +++ b/include/loaders/GP_PNM.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -25,10 +25,13 @@
#include "core/GP_Context.h" #include "core/GP_ProgressCallback.h" +#include "loaders/GP_IO.h"
/* * PBM Bitmap */ +GP_Context *GP_ReadPBM(GP_IO *io, GP_ProgressCallback *callback); + GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePBM(const GP_Context *src, const char *dst_path, @@ -37,6 +40,8 @@ int GP_SavePBM(const GP_Context *src, const char *dst_path, /* * PGM Graymap */ +GP_Context *GP_ReadPGM(GP_IO *io, GP_ProgressCallback *callback); + GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback);
@@ -46,6 +51,8 @@ int GP_SavePGM(const GP_Context *src, const char *dst_path, /* * PPM Pixmap */ +GP_Context *GP_ReadPPM(GP_IO *io, GP_ProgressCallback *callback); + GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePPM(const GP_Context *src, const char *dst_path, @@ -54,6 +61,8 @@ int GP_SavePPM(const GP_Context *src, const char *dst_path, /* * PNM Anymap (All of above) */ +GP_Context *GP_ReadPNM(GP_IO *io, GP_ProgressCallback *callback); + GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback);
int GP_SavePNM(const GP_Context *src, const char *dst_path, diff --git a/include/loaders/GP_PSP.h b/include/loaders/GP_PSP.h index 3ddf75c..1109bd9 100644 --- a/include/loaders/GP_PSP.h +++ b/include/loaders/GP_PSP.h @@ -16,13 +16,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
/*
- Experimental Paint Shop Pro image loader. + Paint Shop Pro image loader. + + Loads composite image from a PSP file.
*/
@@ -31,35 +33,23 @@
#include "core/GP_ProgressCallback.h" #include "core/GP_Context.h" +#include "loaders/GP_IO.h"
/* - * The possible errno values: + * Reads a BMP from an IO stream. * - * - EIO for read/write failure - * - ENOSYS for not implemented bitmap format - * - ENOMEM from malloc() - * - EILSEQ for wrong image signature/data - * - ECANCELED when call was aborted from callback - */ - -/* - * Opens up the PSP image and checks signature. - * Returns zero on success. - */ -int GP_OpenPSP(const char *src_path, FILE **f); - -/* - * Reads image from PSP format. + * Returns newly allocated context cotaining the loaded image or in case of + * failure NULL and errno is set. */ -GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback); +GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback);
/* - * Does both GP_OpenPSP and GP_ReadPSP at once. + * Loads a PSP image from a file. */ GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback);
/* - * Match PSP signature. + * Looks for PSP file signature. Returns non-zero if found. */ int GP_MatchPSP(const void *buf);
diff --git a/include/loaders/GP_TIFF.h b/include/loaders/GP_TIFF.h index 73acb5f..8c7c45f 100644 --- a/include/loaders/GP_TIFF.h +++ b/include/loaders/GP_TIFF.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -25,39 +25,18 @@
#include "core/GP_Context.h" #include "core/GP_ProgressCallback.h" +#include "loaders/GP_IO.h"
/* - * The possible errno values: + * Reads first image in TIFF from an IO stream. * - * - Anything FILE operation may return (fopen(), fclose(), fseek(), ...). - * - EIO for fread()/fwrite() failure - * - ENOSYS for not implemented bitmap format - * - ENOMEM from malloc() - * - EILSEQ for wrong image signature/data - * - ECANCELED when call was aborted from callback + * Returns newly allocated context cotaining the loaded image or in case of + * failure NULL and errno is set. */ +GP_Context *GP_ReadTIFF(GP_IO *io, GP_ProgressCallback *callback);
/* - * Opens up a bmp file, checks signature, parses metadata. - * - * The file, width, height and pixel type are filled upon succcessful return. - * - * Upon failure, non zero return value is returned and errno is filled. - */ -int GP_OpenTIFF(const char *src_path, void **t); - -/* - * Reads a TIFF from a opened file. - * - * Upon successful return, context to store bitmap is allocated and image is - * loaded. - * - * Upon failure NULL is returned and errno is filled. - */ -GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback); - -/* - * Does both GP_OpenTIFF and GP_ReadTIFF. + * Loads fist image in TIFF from a file. */ GP_Context *GP_LoadTIFF(const char *src_path, GP_ProgressCallback *callback);
@@ -68,7 +47,7 @@ int GP_SaveTIFF(const GP_Context *src, const char *dst_path, GP_ProgressCallback *callback);
/* - * Match TIFF signature. + * Looks for TIFF file signature. Returns non-zero if found. */ int GP_MatchTIFF(const void *buf);
diff --git a/libs/loaders/GP_BMP.c b/libs/loaders/GP_BMP.c index d7ea61f..cc03a5e 100644 --- a/libs/loaders/GP_BMP.c +++ b/libs/loaders/GP_BMP.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -24,7 +24,7 @@
BMP loader and writer.
- Thanks Wikipedia for the format specification. + Thanks Wikipedia for excellent format specification.
*/
@@ -46,12 +46,6 @@
#define BMP_HEADER_OFFSET 0x0a /* info header offset - 4 bytes */
-#define BUF_TO_4(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24)) - -#define BUF_TO_2(buf, off) - (buf[off] + (buf[off+1]<<8)) - struct bitmap_info_header { /* * Offset to image data. @@ -155,16 +149,19 @@ static uint32_t get_palette_size(struct bitmap_info_header *header) return (1 << header->bpp); }
-static int read_bitfields(FILE *f, struct bitmap_info_header *header) +static int read_bitfields(GP_IO *io, struct bitmap_info_header *header) { - int ret; + uint16_t bitfields[] = { + GP_IO_L4, /* red mask */ + GP_IO_L4, /* green mask */ + GP_IO_L4, /* blue mask */ + GP_IO_END + };
- ret = GP_FRead(f, "L4 L4 L4", + if (GP_IOReadF(io, bitfields, &header->R_mask, &header->G_mask, - &header->B_mask); - - if (ret != 3) { + &header->B_mask) != 3) { GP_DEBUG(1, "Failed to read BITFIELDS"); return EIO; } @@ -177,17 +174,21 @@ static int read_bitfields(FILE *f, struct bitmap_info_header *header) return 0; }
-static int read_alphabitfields(FILE *f, struct bitmap_info_header *header) +static int read_alphabitfields(GP_IO *io, struct bitmap_info_header *header) { - int ret; + uint16_t abitfields[] = { + GP_IO_L4, /* red mask */ + GP_IO_L4, /* green mask */ + GP_IO_L4, /* blue mask */ + GP_IO_L4, /* alpha mask */ + GP_IO_END + };
- ret = GP_FRead(f, "L4 L4 L4 L4", + if (GP_IOReadF(io, abitfields, &header->R_mask, &header->G_mask, &header->B_mask, - &header->A_mask); - - if (ret != 4) { + &header->A_mask) != 4) { GP_DEBUG(1, "Failed to read BITFIELDS"); return EIO; } @@ -199,11 +200,23 @@ static int read_alphabitfields(FILE *f, struct bitmap_info_header *header) return 0; }
-static int read_bitmap_info_header(FILE *f, struct bitmap_info_header *header) +static int read_bitmap_info_header(GP_IO *io, struct bitmap_info_header *header) { uint16_t nr_planes;
- if (GP_FRead(f, "L4 L4 L2 L2 L4 I12 L4 I4", + uint16_t bmp_info_header[] = { + GP_IO_L4, /* width */ + GP_IO_L4, /* height */ + GP_IO_L2, /* number of planes */ + GP_IO_L2, /* bpp */ + GP_IO_L4, /* compression type */ + GP_IO_IGN | 12, /* bitmap size in bytes, resolution */ + GP_IO_L4, /* palette colors */ + GP_IO_I4, /* number of significant colors */ + GP_IO_END + }; + + if (GP_IOReadF(io, bmp_info_header, &header->w, &header->h, &nr_planes, &header->bpp, &header->compress_type, &header->palette_colors) != 8) {
@@ -227,39 +240,46 @@ static int read_bitmap_info_header(FILE *f, struct bitmap_info_header *header) switch (header->header_size) { case BITMAPINFOHEADER: case BITMAPINFOHEADER2: - return read_bitfields(f, header); + return read_bitfields(io, header); default: /* Alpha is default in BITMAPINFOHEADER3 and newer */ - return read_alphabitfields(f, header); + return read_alphabitfields(io, header); } /* Only in BITMAPINFOHEADER */ case COMPRESS_ALPHABITFIELDS: if (header->header_size != BITMAPINFOHEADER) GP_DEBUG(1, "Unexpected ALPHABITFIELDS in %s", bitmap_header_size_name(header->header_size)); - return read_alphabitfields(f, header); + return read_alphabitfields(io, header); }
return 0; }
-static int read_bitmap_core_header(FILE *f, struct bitmap_info_header *header) +static int read_bitmap_core_header(GP_IO *io, struct bitmap_info_header *header) { - uint8_t buf[12]; + int16_t nr_planes, w, h; + + uint16_t bmp_core_header[] = { + GP_IO_L2, /* width */ + GP_IO_L2, /* height */ + GP_IO_L2, /* number of planes */ + GP_IO_L2, /* bpp */ + //GP_IO_I4,//TODO read till 12? + GP_IO_END + };
- if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) { + if (GP_IOReadF(io, bmp_core_header, &w, &h, + &nr_planes, &header->bpp) != 4) { GP_DEBUG(1, "Failed to read bitmap core header"); return EIO; }
- header->w = BUF_TO_2(buf, 0); - header->h = BUF_TO_2(buf, 2); - header->bpp = BUF_TO_2(buf, 6); + header->w = w; + header->h = h; header->compress_type = COMPRESS_RGB; header->palette_colors = 0;
- uint16_t nr_planes = BUF_TO_2(buf, 4); - /* This must be 1 according to specs */ if (nr_planes != 1) GP_DEBUG(1, "Number of planes is %"PRId16" should be 1", @@ -271,33 +291,32 @@ static int read_bitmap_core_header(FILE *f, struct bitmap_info_header *header) return 0; }
-static int read_bitmap_header(FILE *f, struct bitmap_info_header *header) +static int read_bitmap_header(GP_IO *io, struct bitmap_info_header *header) { - uint8_t buf[8]; int err;
- if (fseek(f, BMP_HEADER_OFFSET, SEEK_SET)) { - err = errno; - GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'", - BMP_HEADER_OFFSET, strerror(errno)); - return err; - } + uint16_t bmp_header[] = { + 'B', + 'M', + GP_IO_IGN | (4 + 2 + 2), /* 4 bytes filesize + 4 bytes reserved */ + GP_IO_L4, /* offset to pixel data */ + GP_IO_L4, /* info header size */ + GP_IO_END, + };
- /* Read info header size, header size determines header type */ - if (fread(buf, 1, sizeof(buf), f) != sizeof(buf)) { - GP_DEBUG(1, "Failed to read info header size"); + if (GP_IOReadF(io, bmp_header, &header->pixel_offset, + &header->header_size) != 5) { + GP_DEBUG(1, "Failed to read header"); + //TODO: EIO vs EINVAL return EIO; }
- header->pixel_offset = BUF_TO_4(buf, 0); - header->header_size = BUF_TO_4(buf, 4); - GP_DEBUG(2, "BMP header type '%s'", bitmap_header_size_name(header->header_size));
switch (header->header_size) { case BITMAPCOREHEADER: - err = read_bitmap_core_header(f, header); + err = read_bitmap_core_header(io, header); break; case BITMAPCOREHEADER2: return ENOSYS; @@ -306,11 +325,11 @@ static int read_bitmap_header(FILE *f, struct bitmap_info_header *header) case BITMAPINFOHEADER2: case BITMAPINFOHEADER3: case BITMAPINFOHEADER4: - err = read_bitmap_info_header(f, header); + err = read_bitmap_info_header(io, header); break; default: GP_DEBUG(1, "Unknown header type, continuing anyway"); - err = read_bitmap_info_header(f, header); + err = read_bitmap_info_header(io, header); break; };
@@ -320,7 +339,7 @@ static int read_bitmap_header(FILE *f, struct bitmap_info_header *header) /* * Reads palette, the format is R G B X, each one byte. */ -static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header, +static int read_bitmap_palette(GP_IO *io, struct bitmap_info_header *header, GP_Pixel *palette) { uint32_t palette_colors = get_palette_size(header); @@ -342,22 +361,24 @@ static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header, "pixel size %"PRIu8"bytes", palette_offset, palette_offset, pixel_size);
- if (fseek(f, palette_offset, SEEK_SET)) { + if (GP_IOSeek(io, palette_offset, GP_IO_SEEK_SET) != palette_offset) { err = errno; - GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'", + GP_DEBUG(1, "Seek to 0x%02x failed: '%s'", BMP_HEADER_OFFSET, strerror(errno)); return err; }
- for (i = 0; i < palette_colors; i++) { - uint8_t buf[4]; + uint8_t buf[pixel_size * palette_colors];
- if (fread(buf, 1, pixel_size, f) != pixel_size) { - GP_DEBUG(1, "Failed to read palette %"PRIu32, i); - return EIO; - } + if (GP_IOFill(io, buf, sizeof(buf))) { + GP_DEBUG(1, "Failed to read palette: %s", strerror(errno)); + return EIO; + } + + for (i = 0; i < palette_colors; i++) { + unsigned int j = i * pixel_size;
- palette[i] = GP_Pixel_CREATE_RGB888(buf[2], buf[1], buf[0]); + palette[i] = GP_Pixel_CREATE_RGB888(buf[j+2], buf[j+1], buf[j]);
GP_DEBUG(3, "Palette[%"PRIu32"] = [0x%02x, 0x%02x, 0x%02x]", i, GP_Pixel_GET_R_RGB888(palette[i]), @@ -368,17 +389,17 @@ static int read_bitmap_palette(FILE *f, struct bitmap_info_header *header, return 0; }
-static int seek_pixels_offset(struct bitmap_info_header *header, FILE *f) +static int seek_pixels_offset(GP_IO *io, struct bitmap_info_header *header) { int err;
GP_DEBUG(2, "Offset to BMP pixels is 0x%x (%ubytes)", header->pixel_offset, header->pixel_offset);
- if (fseek(f, header->pixel_offset, SEEK_SET)) { + if (GP_IOSeek(io, header->pixel_offset, GP_IO_SEEK_SET) != header->pixel_offset) { err = errno; - GP_DEBUG(1, "fseek(f, 0x%02x) failed: '%s'", - header->pixel_offset, strerror(errno)); + GP_DEBUG(1, "Seek to 0x%02x failed: %s", + header->pixel_offset, strerror(err)); return err; }
@@ -482,17 +503,17 @@ static uint8_t get_idx(struct bitmap_info_header *header,
#include "GP_BMP_RLE.h"
-static int read_palette(FILE *f, struct bitmap_info_header *header, +static int read_palette(GP_IO *io, struct bitmap_info_header *header, GP_Context *context, GP_ProgressCallback *callback) { uint32_t palette_size = get_palette_size(header); GP_Pixel palette[get_palette_size(header)]; int err;
- if ((err = read_bitmap_palette(f, header, palette))) + if ((err = read_bitmap_palette(io, header, palette))) return err;
- if ((err = seek_pixels_offset(header, f))) + if ((err = seek_pixels_offset(io, header))) return err;
uint32_t row_size = bitmap_row_size(header); @@ -502,9 +523,11 @@ static int read_palette(FILE *f, struct bitmap_info_header *header, int32_t x; uint8_t row[row_size];
- if (fread(row, 1, row_size, f) != row_size) { - GP_DEBUG(1, "Failed to read row %"PRId32, y); - return EIO; + if (GP_IOFill(io, row, row_size)) { + err = errno; + GP_DEBUG(1, "Failed to read row %"PRId32": %s", + y, strerror(errno)); + return err; }
for (x = 0; x < header->w; x++) { @@ -539,17 +562,30 @@ static int read_palette(FILE *f, struct bitmap_info_header *header, return 0; }
-static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header, +static int read_bitfields_or_rgb(GP_IO *io, struct bitmap_info_header *header, GP_Context *context, GP_ProgressCallback *callback) { uint32_t row_size = header->w * (header->bpp / 8); + uint32_t row_padd = 0; int32_t y; int err;
- if ((err = seek_pixels_offset(header, f))) + if ((err = seek_pixels_offset(io, header))) return err;
+ /* Rows are four byte aligned */ + switch (row_size % 4) { + case 1: + row_padd++; + case 2: + row_padd++; + case 3: + row_padd++; + case 0: + break; + } + for (y = 0; y < GP_ABS(header->h); y++) { int32_t ry;
@@ -560,21 +596,20 @@ static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header,
uint8_t *row = GP_PIXEL_ADDR(context, 0, ry);
- if (fread(row, 1, row_size, f) != row_size) { - GP_DEBUG(1, "Failed to read row %"PRId32, y); - return EIO; + if (GP_IOFill(io, row, row_size)) { + err = errno; + GP_DEBUG(1, "Failed to read row %"PRId32": %s", + y, strerror(err)); + return err; }
- /* Rows are four byte aligned */ - switch (row_size % 4) { - case 1: - fgetc(f); - case 2: - fgetc(f); - case 3: - fgetc(f); - case 0: - break; + if (row_padd) { + if (GP_IOSeek(io, row_padd, GP_IO_SEEK_CUR) == (off_t)-1) { + err = errno; + GP_DEBUG(1, "Failed to seek row %"PRId32": %s", + y, strerror(err)); + return err; + } }
if (GP_ProgressCallbackReport(callback, y, @@ -588,11 +623,11 @@ static int read_bitfields_or_rgb(FILE *f, struct bitmap_info_header *header, return 0; }
-static int read_bitmap_pixels(FILE *f, struct bitmap_info_header *header, +static int read_bitmap_pixels(GP_IO *io, struct bitmap_info_header *header, GP_Context *context, GP_ProgressCallback *callback) { if (header->compress_type == COMPRESS_RLE8) - return read_RLE8(f, header, context, callback); + return read_RLE8(io, header, context, callback);
switch (header->bpp) { case 1: @@ -600,11 +635,11 @@ static int read_bitmap_pixels(FILE *f, struct bitmap_info_header *header, case 2: case 4: case 8: - return read_palette(f, header, context, callback); + return read_palette(io, header, context, callback); case 16: case 24: case 32: - return read_bitfields_or_rgb(f, header, context, callback); + return read_bitfields_or_rgb(io, header, context, callback); }
return ENOSYS; @@ -615,68 +650,19 @@ int GP_MatchBMP(const void *buf) return !memcmp(buf, "BM", 2); }
-int GP_OpenBMP(const char *src_path, FILE **f, - GP_Size *w, GP_Size *h, GP_PixelType *pixel_type) -{ - int err; - - *f = fopen(src_path, "rb"); - - if (*f == NULL) { - err = errno; - GP_DEBUG(1, "Failed to open '%s' : %s", - src_path, strerror(errno)); - goto err2; - } - - int ch1 = fgetc(*f); - int ch2 = fgetc(*f); - - if (ch1 != 'B' || ch2 != 'M') { - GP_DEBUG(1, "Unexpected bitmap header 0x%02x (%c) 0x%02x (%c)", - ch1, isascii(ch1) ? ch1 : ' ', - ch2, isascii(ch2) ? ch2 : ' '); - err = EIO; - goto err1; - } - - if (w != NULL || h != NULL || pixel_type != NULL) { - struct bitmap_info_header header; - - if ((err = read_bitmap_header(*f, &header))) - goto err1; - - if (w != NULL) - *w = header.w; - - if (h != NULL) - *h = header.h; - - if (pixel_type != NULL) - *pixel_type = match_pixel_type(&header); - } - - return 0; -err1: - fclose(*f); -err2: - errno = err; - return 1; -} - -GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback) +GP_Context *GP_ReadBMP(GP_IO *io, GP_ProgressCallback *callback) { struct bitmap_info_header header; GP_PixelType pixel_type; GP_Context *context; int err;
- if ((err = read_bitmap_header(f, &header))) + if ((err = read_bitmap_header(io, &header))) goto err1;
if (header.w <= 0 || header.h == 0) { GP_WARN("Width and/or Height is not > 0"); - err = EIO; + err = EINVAL; goto err1; }
@@ -705,7 +691,7 @@ GP_Context *GP_ReadBMP(FILE *f, GP_ProgressCallback *callback) goto err1; }
- if ((err = read_bitmap_pixels(f, &header, context, callback))) + if ((err = read_bitmap_pixels(io, &header, context, callback))) goto err2;
return context; @@ -718,14 +704,19 @@ err1:
GP_Context *GP_LoadBMP(const char *src_path, GP_ProgressCallback *callback) { - FILE *f; + GP_IO *io; GP_Context *res; + int err;
- if (GP_OpenBMP(src_path, &f, NULL, NULL, NULL)) + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- res = GP_ReadBMP(f, callback); - fclose(f); + res = GP_ReadBMP(io, callback); + + err = errno; + GP_IOClose(io); + errno = err;
return res; } diff --git a/libs/loaders/GP_BMP_RLE.h b/libs/loaders/GP_BMP_RLE.h index 6f7645f..4c228fb 100644 --- a/libs/loaders/GP_BMP_RLE.h +++ b/libs/loaders/GP_BMP_RLE.h @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -57,20 +57,34 @@ struct RLE {
/* current value */ int c; + + GP_IO *io; + + int buf_pos; + int buf_end; + uint8_t buf[512]; };
-#define DECLARE_RLE(name, iw, ih) struct RLE name = { +#define DECLARE_RLE(name, iw, ih, iio) struct RLE name = { .state = RLE_START, - .w = iw, .h = ih, - .x = 0, .y = 0, - .rep = 0+ .w = iw, .h = ih, + .x = 0, .y = 0, + .rep = 0, + .io = io, + .buf_pos = 0, + .buf_end = 0, }
-#define GETC(f, rle) do { - rle->c = fgetc(f); - - if (rle->c == EOF) - return EIO; +#define GETC(rle) do { + if (rle->buf_pos < rle->buf_end) { + rle->c = rle->buf[rle->buf_pos++]; + } else { + rle->buf_end = GP_IORead(rle->io, rle->buf, sizeof(rle->buf));+ if (rle->buf_end <= 0) + return EIO; + rle->c = rle->buf[0]; + rle->buf_pos = 1; + } } while (0)
static void RLE8_move(struct RLE *rle) @@ -119,9 +133,9 @@ static int RLE8_end_of_bitmap(struct RLE *rle) return 0; }
-static int RLE8_repeat(FILE *f, uint8_t rep, struct RLE *rle) +static int RLE8_repeat(uint8_t rep, struct RLE *rle) { - GETC(f, rle); + GETC(rle);
GP_DEBUG(4, "RLE Repeat %i x 0x%02x", rep, rle->c);
@@ -131,12 +145,14 @@ static int RLE8_repeat(FILE *f, uint8_t rep, struct RLE *rle) return 0; }
-static int RLE8_offset(FILE *f, struct RLE *rle) +static int RLE8_offset(struct RLE *rle) { int x, y;
- x = fgetc(f); - y = fgetc(f); + GETC(rle); + x = rle->c; + GETC(rle); + y = rle->c;
if (x == EOF || y == EOF) return EIO; @@ -154,9 +170,9 @@ static int RLE8_offset(FILE *f, struct RLE *rle) return 0; }
-static int RLE8_next_undecoded(FILE *f, struct RLE *rle) +static int RLE8_next_undecoded(struct RLE *rle) { - GETC(f, rle); + GETC(rle);
RLE8_move(rle);
@@ -166,7 +182,7 @@ static int RLE8_next_undecoded(FILE *f, struct RLE *rle) rle->state = RLE_START; /* must be padded to odd number of bytes */ if (rle->flag) - fgetc(f); + GETC(rle); }
rle->move = 1; @@ -188,9 +204,9 @@ static int RLE8_next_repeat(struct RLE *rle) return 0; }
-static int RLE8_esc(FILE *f, struct RLE *rle) +static int RLE8_esc(struct RLE *rle) { - GETC(f, rle); + GETC(rle);
GP_DEBUG(4, "RLE ESC %02x", rle->c);
@@ -200,43 +216,43 @@ static int RLE8_esc(FILE *f, struct RLE *rle) case 0x01: return RLE8_end_of_bitmap(rle); case 0x02: - return RLE8_offset(f, rle); + return RLE8_offset(rle); /* Undecoded sequence */ default: GP_DEBUG(4, "RLE Undecoded x %i", rle->c); rle->state = RLE_UNDECODED; - rle->rep = rle->c; + rle->rep = rle->c; rle->flag = rle->c % 2; return 0; } }
-static int RLE8_start(FILE *f, struct RLE *rle) +static int RLE8_start(struct RLE *rle) { - GETC(f, rle); + GETC(rle);
switch (rle->c) { case 0x00: - return RLE8_esc(f, rle); + return RLE8_esc(rle); default: - return RLE8_repeat(f, rle->c, rle); + return RLE8_repeat(rle->c, rle); } }
-static int RLE8_next(FILE *f, struct RLE *rle) +static int RLE8_next(struct RLE *rle) { int err;
for (;;) { switch (rle->state) { case RLE_START: - if ((err = RLE8_start(f, rle))) + if ((err = RLE8_start(rle))) return err; break; case RLE_REPEAT: return RLE8_next_repeat(rle); case RLE_UNDECODED: - return RLE8_next_undecoded(f, rle); + return RLE8_next_undecoded(rle); case RLE_STOP: return 0; default: @@ -247,18 +263,18 @@ static int RLE8_next(FILE *f, struct RLE *rle) } }
-static int read_RLE8(FILE *f, struct bitmap_info_header *header, +static int read_RLE8(GP_IO *io, struct bitmap_info_header *header, GP_Context *context, GP_ProgressCallback *callback) { uint32_t palette_size = get_palette_size(header); GP_Pixel palette[get_palette_size(header)]; - DECLARE_RLE(rle, header->w, GP_ABS(header->h)); + DECLARE_RLE(rle, header->w, GP_ABS(header->h), io); int err;
- if ((err = read_bitmap_palette(f, header, palette))) + if ((err = read_bitmap_palette(io, header, palette))) return err;
- if ((err = seek_pixels_offset(header, f))) + if ((err = seek_pixels_offset(io, header))) return err;
int cnt = 0; @@ -272,7 +288,7 @@ static int read_RLE8(FILE *f, struct bitmap_info_header *header, GP_Fill(context, palette[0]);
for (;;) { - if ((err = RLE8_next(f, &rle))) + if ((err = RLE8_next(&rle))) return err;
if (rle.state == RLE_STOP) diff --git a/libs/loaders/GP_GIF.c b/libs/loaders/GP_GIF.c index 688f914..88bddee 100644 --- a/libs/loaders/GP_GIF.c +++ b/libs/loaders/GP_GIF.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -38,7 +38,8 @@ #include "core/GP_Fill.h" #include "core/GP_Debug.h"
-#include "GP_GIF.h" +#include "loaders/GP_IO.h" +#include "loaders/GP_GIF.h"
#ifdef HAVE_GIFLIB
@@ -61,39 +62,11 @@ int GP_MatchGIF(const void *buf) return 0; }
-int GP_OpenGIF(const char *src_path, void **f) +static int gif_input_func(GifFileType* gif, GifByteType* bytes, int size) { - GifFileType *gf; - - errno = 0; - -#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 - gf = DGifOpenFileName(src_path, NULL); -#else - gf = DGifOpenFileName(src_path); -#endif + GP_IO *io = gif->UserData;
- if (gf == NULL) { - /* - * The giflib uses open() so when we got a failure and errno - * is set => open() has failed. - * - * When errno is not set the file content was not valid so we - * set errno to EIO. - */ - if (errno == 0) - errno = EIO; - - return 1; - } - - GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp", - gf->SWidth, gf->SHeight, gf->SColorResolution, - gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1); - - *f = gf; - - return 0; + return GP_IORead(io, bytes, size); }
static const char *rec_type_name(GifRecordType rec_type) @@ -255,15 +228,41 @@ static inline unsigned int interlace_real_y(GifFileType *gf, unsigned int y) return 0; }
-GP_Context *GP_ReadGIF(void *f, GP_ProgressCallback *callback) +GP_Context *GP_ReadGIF(GP_IO *io, GP_ProgressCallback *callback) { - GifFileType *gf = f; + GifFileType *gf; GifRecordType rec_type; GP_Context *res = NULL; GP_Pixel bg; int32_t x, y; int err;
+ errno = 0; +#if defined(GIFLIB_MAJOR) && GIFLIB_MAJOR >= 5 + gf = DGifOpen(io, gif_input_func, NULL); +#else + gf = DGifOpen(io, gif_input_func); +#endif + + if (gf == NULL) { + /* + * The giflib uses open() so when we got a failure and errno + * is set => open() has failed. + * + * When errno is not set the file content was not valid so we + * set errno to EIO. + */ + if (errno == 0) + errno = EIO; + + return NULL; + } + + GP_DEBUG(1, "Have GIF image %ix%i, %i colors, %i bpp", + gf->SWidth, gf->SHeight, gf->SColorResolution, + gf->SColorMap ? gf->SColorMap->BitsPerPixel : -1); + + do { if (DGifGetRecordType(gf, &rec_type) != GIF_OK) { //TODO: error handling @@ -361,12 +360,21 @@ err1:
GP_Context *GP_LoadGIF(const char *src_path, GP_ProgressCallback *callback) { - void *f; + GP_IO *io; + GP_Context *res; + int err;
- if (GP_OpenGIF(src_path, &f)) + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- return GP_ReadGIF(f, callback); + res = GP_ReadGIF(io, callback); + + err = errno; + GP_IOClose(io); + errno = err; + + return res; }
#else @@ -377,14 +385,7 @@ int GP_MatchGIF(const void GP_UNUSED(*buf)) return -1; }
-int GP_OpenGIF(const char GP_UNUSED(*src_path), - void GP_UNUSED(**f)) -{ - errno = ENOSYS; - return 1; -} - -GP_Context *GP_ReadGIF(void GP_UNUSED(*f), +GP_Context *GP_ReadGIF(GP_IO GP_UNUSED(*io), GP_ProgressCallback GP_UNUSED(*callback)) { errno = ENOSYS; diff --git a/libs/loaders/GP_IO.c b/libs/loaders/GP_IO.c new file mode 100644 index 0000000..a1409a6 --- /dev/null +++ b/libs/loaders/GP_IO.c @@ -0,0 +1,432 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdarg.h> + +#include <core/GP_ByteOrder.h> +#include <core/GP_Debug.h> +#include <core/GP_Common.h> + +#include "loaders/GP_IO.h" + +struct file_io { + int fd; +}; + +static ssize_t file_read(GP_IO *self, void *buf, size_t size) +{ + struct file_io *file_io = GP_IO_PRIV(self); + + return read(file_io->fd, buf, size); +} + +static ssize_t file_write(GP_IO *self, void *buf, size_t size) +{ + struct file_io *file_io = GP_IO_PRIV(self); + + return write(file_io->fd, buf, size); +} + +static off_t file_seek(GP_IO *self, off_t off, enum GP_IOWhence whence) +{ + struct file_io *file_io = GP_IO_PRIV(self); + + switch (whence) { + case GP_IO_SEEK_SET: + case GP_IO_SEEK_CUR: + case GP_IO_SEEK_END: + break; + default: + GP_WARN("Invalid whence"); + return (off_t)-1; + } + + return lseek(file_io->fd, off, whence); +} + +static int file_close(GP_IO *self) +{ + struct file_io *file_io = GP_IO_PRIV(self); + int fd; + + GP_DEBUG(1, "Closing IOFile"); + + fd = file_io->fd; + free(self); + + return close(fd); +} + +GP_IO *GP_IOFile(const char *path, enum GP_IOFileMode mode) +{ + int err, flags; + GP_IO *io; + struct file_io *file_io; + + GP_DEBUG(1, "Creating IOFile '%s'", path); + + io = malloc(sizeof(GP_IO) + sizeof(struct file_io)); + + if (!io) { + GP_DEBUG(1, "Malloc failed :("); + err = ENOMEM; + goto err0; + } + + switch (mode) { + case GP_IO_WRONLY: + flags = O_CREAT | O_WRONLY; + break; + case GP_IO_RDONLY: + flags = O_RDONLY; + break; + case GP_IO_RDWR: + flags = O_CREAT | O_RDWR; + break; + } + + file_io = GP_IO_PRIV(io); + file_io->fd = open(path, flags, 0666); + + if (file_io->fd < 0) { + err = errno; + GP_DEBUG(1, "Failed to open '%s': %s", path, strerror(errno)); + goto err1; + } + + io->mark = 0; + + io->Seek = file_seek; + io->Read = file_read; + io->Write = file_write; + + if (mode == GP_IO_RDONLY) + io->Write = NULL; + + if (mode == GP_IO_WRONLY) + io->Read = NULL; + + io->Close = file_close; + + return io; +err1: + free(io); +err0: + errno = err; + return NULL; +} + +struct mem_io { + uint8_t *buf; + size_t size; + size_t pos; + void (*free)(void *); +}; + +static ssize_t mem_read(GP_IO *io, void *buf, size_t size) +{ + struct mem_io *mem_io = GP_IO_PRIV(io); + size_t rest = mem_io->size - mem_io->pos; + ssize_t ret = GP_MIN(rest, size); + + if (ret <= 0) { + errno = EIO; + return 0; + } + + memcpy(buf, mem_io->buf + mem_io->pos, ret); + mem_io->pos += ret; + + return ret; +} + +static off_t mem_seek(GP_IO *io, off_t off, enum GP_IOWhence whence) +{ + struct mem_io *mem_io = GP_IO_PRIV(io); + + switch (whence) { + case GP_IO_SEEK_CUR: + if (off + mem_io->pos > mem_io->size) { + errno = EINVAL; + return (off_t)-1; + } + + mem_io->pos += off; + break; + case GP_IO_SEEK_SET: + if (off < 0 || off > (off_t)mem_io->pos) { + errno = EINVAL; + return (off_t)-1; + } + mem_io->pos = off; + break; + case GP_IO_SEEK_END: + if (off) { + errno = EINVAL; + return (off_t)-1; + } + mem_io->pos = mem_io->size; + break; + default: + GP_WARN("Invalid whence"); + return (off_t)-1; + } + + return mem_io->pos; +} + +static int mem_close(GP_IO *io) +{ + struct mem_io *mem_io = GP_IO_PRIV(io); + + GP_DEBUG(1, "Closing IOMem"); + + if (mem_io->free) + mem_io->free(mem_io->buf); + + free(io); + + return 0; +} + +GP_IO *GP_IOMem(void *buf, size_t size, void (*free)(void *)) +{ + GP_IO *io; + struct mem_io *mem_io; + + GP_DEBUG(1, "Creating IOMem %p size=%zu", buf, size); + + io = malloc(sizeof(GP_IO) + sizeof(*mem_io)); + + if (!io) { + GP_DEBUG(1, "Malloc failed :("); + errno = ENOMEM; + return NULL; + } + + io->Read = mem_read; + io->Seek = mem_seek; + io->Close = mem_close; + io->Write = NULL; + + mem_io = GP_IO_PRIV(io); + + mem_io->free = free; + mem_io->buf = buf; + mem_io->size = size; + mem_io->pos = 0; + + return io; +} + +int GP_IOMark(GP_IO *self, enum GP_IOMarkTypes type) +{ + off_t ret; + + switch (type) { + case GP_IO_MARK: + ret = GP_IOSeek(self, 0, GP_IO_SEEK_CUR); + break; + case GP_IO_REWIND: + ret = GP_IOSeek(self, self->mark, SEEK_SET); + break; + default: + GP_WARN("Invalid mark type"); + return -1; + } + + if (ret == (off_t)-1) { + GP_WARN("Failed to lseek IO Stream"); + return -1; + } + + self->mark = ret; + return 0; +} + +off_t GP_IOSize(GP_IO *io) +{ + off_t cur = GP_IOTell(io); + off_t ret; + + ret = GP_IOSeek(io, 0, GP_IO_SEEK_END); + + if (ret == (off_t)-1) + return ret; + + GP_IOSeek(io, cur, GP_IO_SEEK_SET); + + GP_DEBUG(2, "IO Size = %lli", (long long)ret); + + return ret; +} + +int GP_IOFill(GP_IO *io, void *buf, size_t size) +{ + size_t read = 0; + int ret; + + do { + ret = GP_IORead(io, (char*)buf + read, size - read); + + if (ret <= 0) { + GP_DEBUG(1, "Failed to fill buffer"); + return 1; + } + + read += ret; + + } while (read < size); + + return 0; +} + +#define TYPE(x) ((x) & GP_IO_TYPE_MASK) +#define VAL(x) ((x) & ~GP_IO_TYPE_MASK) + +static unsigned int readf_size(uint16_t *types) +{ + unsigned int size = 0; + + while (*types != GP_IO_END) { + switch (TYPE(*types)) { + case GP_IO_CONST: + case GP_IO_BYTE: + size++; + break; + case GP_IO_L2: + case GP_IO_B2: + size += 2; + break; + case GP_IO_L4: + case GP_IO_B4: + size += 4; + break; + case GP_IO_ARRAY: + case GP_IO_IGN: + size+=VAL(*types); + break; + } + types++; + } + + return size; +} + +static int needs_swap(uint16_t type) +{ +#if __BYTE_ORDER == __BIG_ENDIAN + if (type == GP_IO_L2 || type == GP_IO_L4) + return 1; + return 0; +#elif __BYTE_ORDER == __LITTLE_ENDIAN + if (type == GP_IO_B2 || type == GP_IO_B4) + return 1; + return 0; +#else +# error Unknown Endianity +#endif +} + +int GP_IOReadF(GP_IO *self, uint16_t *types, ...) +{ + unsigned int size = readf_size(types); + uint8_t buffer[size], *buf = buffer; + int ret; + va_list va; + uint8_t *ptr; + + buf[0] = 0; + + if (GP_IOFill(self, buf, size)) + return -1; + + ret = 0; + va_start(va, types); + + while (*types != GP_IO_END) { + switch (TYPE(*types)) { + case GP_IO_CONST: + //TODO: Seek back? + if (VAL(*types) != *buf) { + errno = EINVAL; + goto end; + } + buf++; + break; + case GP_IO_BYTE: + ptr = va_arg(va, uint8_t*); + *ptr = *buf; + buf++; + break; + case GP_IO_L2: + case GP_IO_B2: + ptr = va_arg(va, uint8_t*); + + if (needs_swap(*types)) { + ptr[0] = buf[1]; + ptr[1] = buf[0]; + } else { + ptr[0] = buf[0]; + ptr[1] = buf[1]; + } + buf += 2; + break; + case GP_IO_L4: + case GP_IO_B4: + ptr = va_arg(va, uint8_t*); + + if (needs_swap(*types)) { + ptr[0] = buf[3]; + ptr[1] = buf[2]; + ptr[2] = buf[1]; + ptr[3] = buf[0]; + } else { + ptr[0] = buf[0]; + ptr[1] = buf[1]; + ptr[2] = buf[2]; + ptr[3] = buf[3]; + } + buf += 4; + break; + case GP_IO_ARRAY: + ptr = va_arg(va, void*); + memcpy(ptr, buf, VAL(*types)); + case GP_IO_IGN: + buf += VAL(*types); + break; + } + + types++; + ret++; + } + +end: + va_end(va); + return ret; +} diff --git a/libs/loaders/GP_JP2.c b/libs/loaders/GP_JP2.c index 2a8d11d..ef412ca 100644 --- a/libs/loaders/GP_JP2.c +++ b/libs/loaders/GP_JP2.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -36,10 +36,6 @@
#include "GP_JP2.h"
-#ifdef HAVE_OPENJPEG - -#include <openjpeg-2.0/openjpeg.h> - #define JP2_SIG "x00x00x00x0cjPx20x20x0dx0ax87x0a" #define JP2_SIG_LEN 12
@@ -48,24 +44,9 @@ int GP_MatchJP2(const void *buf) return !memcmp(buf, JP2_SIG, JP2_SIG_LEN); }
-int GP_OpenJP2(const char *src_path, FILE **f) -{ - int err; - - *f = fopen(src_path, "rb"); - - if (*f == NULL) { - err = errno; - GP_DEBUG(1, "Failed to open '%s' : %s", - src_path, strerror(errno)); - errno = err; - return 1; - } - - //TODO: check signature and rewind the stream +#ifdef HAVE_OPENJPEG
- return 0; -} +#include <openjpeg-2.0/openjpeg.h>
static void jp2_err_callback(const char *msg, void *priv) { @@ -81,11 +62,8 @@ static void jp2_warn_callback(const char *msg, void *priv)
static void jp2_info_callback(const char *msg, void *priv) { - GP_ProgressCallback *callback = priv; - + (void) priv; GP_DEBUG(1, "openjpeg: %s", msg); - - GP_ProgressCallbackReport(callback, 100, 100, 100); }
static const char *color_space_name(OPJ_COLOR_SPACE color_space) @@ -106,7 +84,12 @@ static const char *color_space_name(OPJ_COLOR_SPACE color_space) } }
-GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback) +static OPJ_SIZE_T jp2_io_read(void *buf, OPJ_SIZE_T size, void *io) +{ + return GP_IORead(io, buf, size); +} + +GP_Context *GP_ReadJP2(GP_IO *io, GP_ProgressCallback *callback) { opj_dparameters_t params; opj_codec_t *codec; @@ -138,7 +121,7 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback) goto err1; }
- stream = opj_stream_create_default_file_stream(f, OPJ_TRUE); + stream = opj_stream_default_create(OPJ_TRUE);
if (!stream) { GP_DEBUG(1, "opj_stream_create_default_file_stream faled"); @@ -146,6 +129,10 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback) goto err1; }
+ //TODO: Do we need seek and skip? + opj_stream_set_read_function(stream, jp2_io_read); + opj_stream_set_user_data(stream, io); + if (!opj_read_header(stream, codec, &img)) { GP_DEBUG(1, "opj_read_header failed"); err = EINVAL; @@ -197,6 +184,8 @@ GP_Context *GP_ReadJP2(FILE *f, GP_ProgressCallback *callback) goto err3; }
+ GP_ProgressCallbackReport(callback, 0, 100, 100); + if (!opj_decode(codec, stream, img)) { GP_DEBUG(1, "opj_decode failed"); err = EINVAL; @@ -238,35 +227,27 @@ err0:
GP_Context *GP_LoadJP2(const char *src_path, GP_ProgressCallback *callback) { - FILE *f; + GP_IO *io; GP_Context *res; + int err;
- if (GP_OpenJP2(src_path, &f)) + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- res = GP_ReadJP2(f, callback); + res = GP_ReadJP2(io, callback);
- fclose(f); + err = errno; + GP_IOClose(io); + errno = err;
return res; }
#else
-int GP_MatchJP2(const void GP_UNUSED(*buf)) -{ - errno = ENOSYS; - return -1; -} - -int GP_OpenJP2(const char GP_UNUSED(*src_path), FILE GP_UNUSED(**f)) -{ - errno = ENOSYS; - return 1; -} - -GP_Context *GP_ReadJP2(FILE GP_UNUSED(*f), - GP_ProgressCallback GP_UNUSED(*callback)) +GP_Context *GP_ReadJP2(GP_IO GP_UNUSED(*io), + GP_ProgressCallback GP_UNUSED(*callback)) { errno = ENOSYS; return NULL; diff --git a/libs/loaders/GP_JPG.c b/libs/loaders/GP_JPG.c index aa6b1c4..8448ba0 100644 --- a/libs/loaders/GP_JPG.c +++ b/libs/loaders/GP_JPG.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -56,25 +56,6 @@ int GP_MatchJPG(const void *buf) return !memcmp(buf, JPEG_SIGNATURE, JPEG_SIGNATURE_LEN); }
-int GP_OpenJPG(const char *src_path, FILE **f) -{ - int err; - - *f = fopen(src_path, "rb"); - - if (*f == NULL) { - err = errno; - GP_DEBUG(1, "Failed to open '%s' : %s", - src_path, strerror(errno)); - errno = err; - return 1; - } - - //TODO: check signature and rewind the stream - - return 0; -} - struct my_jpg_err { struct jpeg_error_mgr error_mgr; jmp_buf setjmp_buf; @@ -155,11 +136,57 @@ static int load_cmyk(struct jpeg_decompress_struct *cinfo, GP_Context *ret, return 0; }
-GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback) + +struct my_source_mgr { + struct jpeg_source_mgr mgr; + void *buffer; + size_t size; + GP_IO *io; +}; + +static void dummy(j_decompress_ptr GP_UNUSED(cinfo)) +{ +} + +static boolean fill_input_buffer(struct jpeg_decompress_struct *cinfo) +{ + int ret; + struct my_source_mgr* src = (void*)cinfo->src; + + ret = GP_IORead(src->io, src->buffer, src->size); + + if (ret < 0) { + GP_WARN("Failed to fill buffer"); + return 0; + } + + src->mgr.next_input_byte = src->buffer; + src->mgr.bytes_in_buffer = src->size; + return 1; +} + +static void skip_input_data(struct jpeg_decompress_struct *cinfo, long num_bytes) +{ + struct my_source_mgr* src = (void*)cinfo->src; + + GP_DEBUG(3, "Skipping %li bytes", num_bytes); + + if (src->mgr.bytes_in_buffer < (unsigned long)num_bytes) { + src->mgr.bytes_in_buffer = 0; + GP_IOSeek(src->io, num_bytes - src->mgr.bytes_in_buffer, GP_IO_SEEK_CUR); + } else { + src->mgr.bytes_in_buffer -= num_bytes; + src->mgr.next_input_byte += num_bytes; + } +} + +GP_Context *GP_ReadJPG(GP_IO *io, GP_ProgressCallback *callback) { struct jpeg_decompress_struct cinfo; + struct my_source_mgr src; struct my_jpg_err my_err; GP_Context *ret = NULL; + uint8_t buffer[1024]; int err;
cinfo.err = jpeg_std_error(&my_err.error_mgr); @@ -171,7 +198,19 @@ GP_Context *GP_ReadJPG(FILE *f, GP_ProgressCallback *callback) }
jpeg_create_decompress(&cinfo); - jpeg_stdio_src(&cinfo, f); + + /* Initialize custom source manager */ + src.mgr.init_source = dummy; + src.mgr.resync_to_restart = jpeg_resync_to_restart; + src.mgr.term_source = dummy; + src.mgr.fill_input_buffer = fill_input_buffer; + src.mgr.skip_input_data = skip_input_data; + src.mgr.bytes_in_buffer = 0; + src.mgr.next_input_byte = NULL; + src.io = io; + src.buffer = buffer; + src.size = sizeof(buffer); + cinfo.src = (void*)&src;
jpeg_read_header(&cinfo, TRUE);
@@ -245,15 +284,19 @@ err1:
GP_Context *GP_LoadJPG(const char *src_path, GP_ProgressCallback *callback) { - FILE *f; + GP_IO *io; GP_Context *res; + int err;
- if (GP_OpenJPG(src_path, &f)) + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- res = GP_ReadJPG(f, callback); + res = GP_ReadJPG(io, callback);
- fclose(f); + err = errno; + GP_IOClose(io); + errno = err;
return res; } @@ -333,15 +376,15 @@ err1:
int GP_LoadJPGMetaData(const char *src_path, GP_MetaData *data) { - FILE *f; - int ret; + //FILE *f; + int ret = -1;
- if (GP_OpenJPG(src_path, &f)) - return 1; + //if (GP_OpenJPG(src_path, &f)) + // return 1;
- ret = GP_ReadJPGMetaData(f, data); + //ret = GP_ReadJPGMetaData(f, data);
- fclose(f); + //fclose(f);
return ret; } diff --git a/libs/loaders/GP_PNG.c b/libs/loaders/GP_PNG.c index 384d599..71812ba 100644 --- a/libs/loaders/GP_PNG.c +++ b/libs/loaders/GP_PNG.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -49,46 +49,6 @@ int GP_MatchPNG(const void *buf) return !png_sig_cmp(buf, 0, 8); }
-int GP_OpenPNG(const char *src_path, FILE **f) -{ - uint8_t sig[8]; - int err; - - *f = fopen(src_path, "r"); - - if (*f == NULL) { - err = errno; - GP_DEBUG(1, "Failed to open '%s' : %s", - src_path, strerror(errno)); - goto err1; - } - - if (fread(sig, 1, 8, *f) <= 0) { - err = EIO; - GP_DEBUG(1, "Failed to read '%s' : %s", - src_path, strerror(errno)); - goto err2; - } - - if (png_sig_cmp(sig, 0, 8)) { - GP_DEBUG(1, "Invalid file header, '%s' not a PNG image?", - src_path); - err = EINVAL; - goto err2; - } - - GP_DEBUG(1, "Found PNG signature in '%s'", src_path); - - rewind(*f); - - return 0; -err2: - fclose(*f); -err1: - errno = err; - return 1; -} - static const char *interlace_type_name(int interlace) { switch (interlace) { @@ -101,7 +61,18 @@ static const char *interlace_type_name(int interlace) } }
-GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback) +static void read_data(png_structp png_ptr, png_bytep data, png_size_t len) +{ + int res; + GP_IO *io = png_get_io_ptr(png_ptr); + + res = GP_IORead(io, data, len); + + if (res < 0 || (png_size_t)res != len) + png_error(png_ptr, "Read Error"); +} + +GP_Context *GP_ReadPNG(GP_IO *io, GP_ProgressCallback *callback) { png_structp png; png_infop png_info = NULL; @@ -135,7 +106,8 @@ GP_Context *GP_ReadPNG(FILE *f, GP_ProgressCallback *callback) goto err2; }
- png_init_io(png, f); + //png_init_io(png, f); + png_set_read_fn(png, io, read_data); png_set_sig_bytes(png, 0); png_read_info(png, png_info);
@@ -291,15 +263,19 @@ err1:
GP_Context *GP_LoadPNG(const char *src_path, GP_ProgressCallback *callback) { - FILE *f; + GP_IO *io; GP_Context *res; + int err;
- if (GP_OpenPNG(src_path, &f)) + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- res = GP_ReadPNG(f, callback); + res = GP_ReadPNG(io, callback);
- fclose(f); + err = errno; + GP_IOClose(io); + errno = err;
return res; } @@ -413,8 +389,8 @@ int GP_LoadPNGMetaData(const char *src_path, GP_MetaData *data) FILE *f; int ret;
- if (GP_OpenPNG(src_path, &f)) - return 1; +// if (GP_OpenPNG(src_path, &f)) +// return 1;
ret = GP_ReadPNGMetaData(f, data);
@@ -636,14 +612,7 @@ int GP_MatchPNG(const void GP_UNUSED(*buf)) return -1; }
-int GP_OpenPNG(const char GP_UNUSED(*src_path), - FILE GP_UNUSED(**f)) -{ - errno = ENOSYS; - return 1; -} - -GP_Context *GP_ReadPNG(FILE GP_UNUSED(*f), +GP_Context *GP_ReadPNG(GP_IO GP_UNUSED(*io), GP_ProgressCallback GP_UNUSED(*callback)) { errno = ENOSYS; diff --git a/libs/loaders/GP_PNM.c b/libs/loaders/GP_PNM.c index de81c4b..1a17e53 100644 --- a/libs/loaders/GP_PNM.c +++ b/libs/loaders/GP_PNM.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -156,12 +156,67 @@ enum state { S_INT, };
-static int load_header(FILE *f, struct pnm_header *header) +/* + * Simple buffer implementation on the top of the GP_IO + */ +struct buf { + uint8_t buf[100]; + unsigned int buf_end; + unsigned int buf_pos; + GP_IO *io; +}; + +#define DECLARE_BUFFER(name, bio) + struct buf name = {.buf_end = 0, .buf_pos = 0, .io = bio} + +static int getb(struct buf *buf) +{ + int ret; + + if (buf->buf_pos < buf->buf_end) + return buf->buf[buf->buf_pos++]; + + ret = GP_IORead(buf->io, buf->buf, sizeof(buf->buf)); + + if (ret <= 0) + return EOF; + + buf->buf_pos = 1; + buf->buf_end = ret; + + return buf->buf[0]; +} + +static void ungetb(struct buf *buf, uint8_t byte) +{ + buf->buf[--buf->buf_pos] = byte; +} + +static int fillb(struct buf *buf, void *ptr, size_t size) +{ + unsigned int buffered = buf->buf_end - buf->buf_pos; + + if (buffered) { + unsigned int to_copy = GP_MIN(buffered, size); + memcpy(ptr, buf->buf + buf->buf_pos, to_copy); + buf->buf_pos += to_copy; + } + + //TODO: refill buffer if request < 128 + if (size > buffered) { + return GP_IOFill(buf->io, (char*)ptr + buffered, + size - buffered); + } + + return 0; +} + +static int load_header(struct buf *buf, struct pnm_header *header) { int h1, h2, c, state = S_START, val = 0, i = 0, err;
- h1 = fgetc(f); - h2 = fgetc(f); + h1 = getb(buf); + h2 = getb(buf);
if (h1 == EOF || h2 == EOF) { GP_DEBUG(1, "Failed to read header"); @@ -180,7 +235,7 @@ static int load_header(FILE *f, struct pnm_header *header) header->w = 0;
for (;;) { - c = fgetc(f); + c = getb(buf);
if (c == EOF) { err = EIO; @@ -231,7 +286,7 @@ static int load_header(FILE *f, struct pnm_header *header) header->depth = val; goto out; } - ungetc(c, f); + ungetb(buf, c); state = S_START; break; } @@ -252,13 +307,13 @@ err: /* * ASCII data parser */ -static int get_ascii_int(FILE *f, int *val) +static int get_ascii_int(struct buf *buf, int *val) { int c, in_number = 0; *val = 0;
for (;;) { - c = getc_unlocked(f); + c = getb(buf);
switch (c) { case EOF: @@ -309,7 +364,8 @@ static inline int write_ascii_byte(FILE *f, uint8_t byte) /* * The PBM ASCII has the values inverted */ -static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_ascii_g1_inv(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t x, y; int val, err; @@ -317,7 +373,7 @@ static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) for (y = 0; y < ctx->h; y++) { for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val))) + if ((err = get_ascii_int(buf, &val))) return err;
GP_PutPixel_Raw_1BPP_LE(ctx, x, y, !val); @@ -336,7 +392,8 @@ static int load_ascii_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) //TODO: This is temporary till blit works with bitendian #include "core/GP_BitSwap.h"
-static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_raw_g1_inv(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t x, y; uint8_t *addr; @@ -345,7 +402,7 @@ static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) for (y = 0; y < ctx->h; y++) { for (x = 0; x < ctx->w; x+=8) {
- if ((val = fgetc(f)) == EOF) + if ((val = getb(buf)) == EOF) return EIO;
addr = GP_PIXEL_ADDR(ctx, x, y); @@ -362,7 +419,8 @@ static int load_raw_g1_inv(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) return 0; }
-static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_ascii_g1(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t x, y; int val, err; @@ -370,11 +428,11 @@ static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) for (y = 0; y < ctx->h; y++) { for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val))) + if ((err = get_ascii_int(buf, &val))) return err;
if (val > 1) { - GP_WARN("Value too large for 2BPP (%i)", val); + GP_WARN("Value too large for 1BPP (%i)", val); val = 1; }
@@ -391,7 +449,8 @@ static int load_ascii_g1(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) return 0; }
-static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_ascii_g2(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t x, y; int val, err; @@ -399,7 +458,7 @@ static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) for (y = 0; y < ctx->h; y++) { for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val))) + if ((err = get_ascii_int(buf, &val))) return err;
if (val > 3) { @@ -420,7 +479,8 @@ static int load_ascii_g2(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) return 0; }
-static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_ascii_g4(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t x, y; int val, err; @@ -428,12 +488,12 @@ static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) for (y = 0; y < ctx->h; y++) { for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val))) + if ((err = get_ascii_int(buf, &val))) return err;
if (val > 15) { GP_WARN("Value too large for 4BPP (%i)", val); - val = 3; + val = 15; }
GP_PutPixel_Raw_4BPP_LE(ctx, x, y, val); @@ -449,7 +509,8 @@ static int load_ascii_g4(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) return 0; }
-static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_ascii_g8(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t x, y; int val, err; @@ -457,12 +518,12 @@ static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) for (y = 0; y < ctx->h; y++) { for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &val))) + if ((err = get_ascii_int(buf, &val))) return err;
- if (val > 15) { - GP_WARN("Value too large for 4BPP (%i)", val); - val = 3; + if (val > 255) { + GP_WARN("Value too large for 8BPP (%i)", val); + val = 255; }
GP_PutPixel_Raw_8BPP(ctx, x, y, val); @@ -478,14 +539,15 @@ static int load_ascii_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) return 0; }
-static int load_bin_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_bin_g8(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t y;
for (y = 0; y < ctx->h; y++) { uint8_t *addr = GP_PIXEL_ADDR(ctx, 0, y);
- if (fread(addr, ctx->w, 1, f) != 1) + if (fillb(buf, addr, ctx->w)) return errno;
if (GP_ProgressCallbackReport(cb, y, ctx->h, ctx->w)) { @@ -498,7 +560,8 @@ static int load_bin_g8(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) return 0; }
-static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_ascii_rgb888(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t x, y; int r, g, b, err; @@ -506,7 +569,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) for (y = 0; y < ctx->h; y++) { for (x = 0; x < ctx->w; x++) {
- if ((err = get_ascii_int(f, &r))) + if ((err = get_ascii_int(buf, &r))) return err;
if (r > 255) { @@ -514,7 +577,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) r = 255; }
- if ((err = get_ascii_int(f, &g))) + if ((err = get_ascii_int(buf, &g))) return err;
if (g > 255) { @@ -522,7 +585,7 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) g = 255; }
- if ((err = get_ascii_int(f, &b))) + if ((err = get_ascii_int(buf, &b))) return err;
if (b > 255) { @@ -544,14 +607,15 @@ static int load_ascii_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) return 0; }
-static int load_bin_rgb888(FILE *f, GP_Context *ctx, GP_ProgressCallback *cb) +static int load_bin_rgb888(struct buf *buf, GP_Context *ctx, + GP_ProgressCallback *cb) { uint32_t y, x;
for (y = 0; y < ctx->h; y++) { uint8_t *addr = GP_PIXEL_ADDR(ctx, 0, y);
- if (fread(addr, ctx->w * 3, 1, f) != 1) + if (fillb(buf, addr, ctx->w * 3)) return errno;
for (x = 0; x < ctx->w; x++) @@ -598,26 +662,7 @@ static int save_ascii(FILE *f, const GP_Context *ctx, return 0; }
-static FILE *read_header(const char *src_path, struct pnm_header *header) -{ - FILE *f; - int err; - - f = fopen(src_path, "r"); - - if (f == NULL) - return NULL; - - if ((err = load_header(f, header))) { - fclose(f); - errno = err; - return NULL; - } - - return f; -} - -static GP_Context *read_bitmap(FILE *f, struct pnm_header *header, int flag, +static GP_Context *read_bitmap(struct buf *buf, struct pnm_header *header, GP_ProgressCallback *callback) { GP_Context *ret; @@ -637,38 +682,53 @@ static GP_Context *read_bitmap(FILE *f, struct pnm_header *header, int flag, }
if (header->magic == '1') - err = load_ascii_g1_inv(f, ret, callback); + err = load_ascii_g1_inv(buf, ret, callback); else - err = load_raw_g1_inv(f, ret, callback); + err = load_raw_g1_inv(buf, ret, callback);
if (err) goto err1;
- if (flag) - fclose(f); - return ret; err1: GP_ContextFree(ret); - - if (flag) - fclose(f); err0: errno = err; return NULL; }
-GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback) +GP_Context *GP_ReadPBM(GP_IO *io, GP_ProgressCallback *callback) { struct pnm_header header; - FILE *f; + DECLARE_BUFFER(buf, io); + int err;
- f = read_header(src_path, &header); + err = load_header(&buf, &header); + if (err) { + errno = err; + return NULL; + }
- if (f == NULL) + return read_bitmap(&buf, &header, callback); +} + +GP_Context *GP_LoadPBM(const char *src_path, GP_ProgressCallback *callback) +{ + GP_IO *io; + GP_Context *res; + int err; + + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- return read_bitmap(f, &header, 1, callback); + res = GP_ReadPBM(io, callback); + + err = errno; + GP_IOClose(io); + errno = err; + + return res; }
int GP_SavePBM(const GP_Context *src, const char *dst_path, @@ -728,44 +788,44 @@ static GP_Pixel depth_to_pixel(int depth) } }
-static int load_ascii_graymap(FILE *f, struct pnm_header *header, +static int load_ascii_graymap(struct buf *buf, struct pnm_header *header, GP_Context *ret, GP_ProgressCallback *callback) { int err = ENOSYS;
switch (header->depth) { case 1: - err = load_ascii_g1(f, ret, callback); + err = load_ascii_g1(buf, ret, callback); break; case 3: - err = load_ascii_g2(f, ret, callback); + err = load_ascii_g2(buf, ret, callback); break; case 15: - err = load_ascii_g4(f, ret, callback); + err = load_ascii_g4(buf, ret, callback); break; case 255: - err = load_ascii_g8(f, ret, callback); + err = load_ascii_g8(buf, ret, callback); break; }
return err; }
-static int load_bin_graymap(FILE *f, struct pnm_header *header, +static int load_bin_graymap(struct buf *buf, struct pnm_header *header, GP_Context *ret, GP_ProgressCallback *callback) { int err = ENOSYS;
switch (header->depth) { case 255: - err = load_bin_g8(f, ret, callback); + err = load_bin_g8(buf, ret, callback); break; }
return err; }
-static GP_Context *read_graymap(FILE *f, struct pnm_header *header, int flag, +static GP_Context *read_graymap(struct buf *buf, struct pnm_header *header, GP_ProgressCallback *callback) { GP_Context *ret; @@ -792,38 +852,53 @@ static GP_Context *read_graymap(FILE *f, struct pnm_header *header, int flag, }
if (header->magic == '5') - err = load_bin_graymap(f, header, ret, callback); + err = load_bin_graymap(buf, header, ret, callback); else - err = load_ascii_graymap(f, header, ret, callback); + err = load_ascii_graymap(buf, header, ret, callback);
if (err) goto err1;
- if (flag) - fclose(f); - return ret; err1: GP_ContextFree(ret); - - if (flag) - fclose(f); err0: errno = err; return NULL; }
-GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback) +GP_Context *GP_ReadPGM(GP_IO *io, GP_ProgressCallback *callback) { struct pnm_header header; - FILE *f; + DECLARE_BUFFER(buf, io); + int err; + + err = load_header(&buf, &header); + if (err) { + errno = err; + return NULL; + }
- f = read_header(src_path, &header); + return read_graymap(&buf, &header, callback); +}
- if (f == NULL) +GP_Context *GP_LoadPGM(const char *src_path, GP_ProgressCallback *callback) +{ + GP_IO *io; + GP_Context *res; + int err; + + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- return read_graymap(f, &header, 1, callback); + res = GP_ReadPGM(io, callback); + + err = errno; + GP_IOClose(io); + errno = err; + + return res; }
static int pixel_to_depth(GP_Pixel pixel) @@ -891,11 +966,11 @@ err0: return 1; }
-static GP_Context *read_pixmap(FILE *f, struct pnm_header *header, int flag, - GP_ProgressCallback *callback) +static GP_Context *read_pixmap(struct buf *buf, struct pnm_header *header, + GP_ProgressCallback *callback) { GP_Context *ret; - int err; + int err = 0;
if (!is_pixmap(header->magic)) { GP_DEBUG(1, "Invalid Pixmap magic P%c", header->magic); @@ -918,40 +993,56 @@ static GP_Context *read_pixmap(FILE *f, struct pnm_header *header, int flag,
switch (header->magic) { case '3': - if ((err = load_ascii_rgb888(f, ret, callback))) - goto err1; + err = load_ascii_rgb888(buf, ret, callback); break; case '6': - if ((err = load_bin_rgb888(f, ret, callback))) - goto err1; + err = load_bin_rgb888(buf, ret, callback); break; }
- if (flag) - fclose(f); + if (err) + goto err1;
return ret; err1: GP_ContextFree(ret); - - if (flag) - fclose(f); err0: errno = err; return NULL; }
-GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback) +GP_Context *GP_ReadPPM(GP_IO *io, GP_ProgressCallback *callback) { struct pnm_header header; - FILE *f; + DECLARE_BUFFER(buf, io); + int err;
- f = read_header(src_path, &header); + err = load_header(&buf, &header); + if (err) { + errno = err; + return NULL; + }
- if (f == NULL) + return read_pixmap(&buf, &header, callback); +} + +GP_Context *GP_LoadPPM(const char *src_path, GP_ProgressCallback *callback) +{ + GP_IO *io; + GP_Context *res; + int err; + + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- return read_pixmap(f, &header, 1, callback); + res = GP_ReadPPM(io, callback); + + err = errno; + GP_IOClose(io); + errno = err; + + return res; }
static int write_binary_ppm(FILE *f, GP_Context *src) @@ -1072,40 +1163,48 @@ err0: return 1; }
-GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback) +GP_Context *GP_ReadPNM(GP_IO *io, GP_ProgressCallback *callback) { - FILE *f; - GP_Context *ret = NULL; struct pnm_header header; + DECLARE_BUFFER(buf, io); + GP_Context *ret = NULL; int err;
- f = fopen(src_path, "r"); - - if (f == NULL) { - err = errno; - GP_DEBUG(1, "Failed to open file '%s': %s", - src_path, strerror(errno)); - goto err0; + err = load_header(&buf, &header); + if (err) { + errno = err; + return NULL; }
- if ((err = load_header(f, &header))) - goto err1; - if (is_bitmap(header.magic)) - ret = read_bitmap(f, &header, 1, callback); + ret = read_bitmap(&buf, &header, callback);
if (is_graymap(header.magic)) - ret = read_graymap(f, &header, 1, callback); + ret = read_graymap(&buf, &header, callback);
if (is_pixmap(header.magic)) - ret = read_pixmap(f, &header, 1, callback); + ret = read_pixmap(&buf, &header, callback);
return ret; -err1: - fclose(f); -err0: +} + +GP_Context *GP_LoadPNM(const char *src_path, GP_ProgressCallback *callback) +{ + GP_IO *io; + GP_Context *res; + int err; + + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) + return NULL; + + res = GP_ReadPNM(io, callback); + + err = errno; + GP_IOClose(io); errno = err; - return NULL; + + return res; }
int GP_SavePNM(const GP_Context *src, const char *dst_path, diff --git a/libs/loaders/GP_PSP.c b/libs/loaders/GP_PSP.c index f5c6c28..d99ca03 100644 --- a/libs/loaders/GP_PSP.c +++ b/libs/loaders/GP_PSP.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2012 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -42,17 +42,6 @@ #include "GP_JPG.h" #include "GP_PSP.h"
-#define BUF_TO_8(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24) + - ((uint64_t)buf[off+4]<<32) + ((uint64_t)buf[off+5]<<40) + - ((uint64_t)buf[off+6]<<48) + ((uint64_t)buf[off+7]<<56)) - -#define BUF_TO_4(buf, off) - (buf[off] + (buf[off+1]<<8) + (buf[off+2]<<16) + (buf[off+3]<<24)) - -#define BUF_TO_2(buf, off) - (buf[off] + (buf[off+1]<<8)) - #define PSP_SIGNATURE "Paint Shop Pro Image Filenx1a00000000" #define PSP_SIGNATURE_LEN 32
@@ -66,49 +55,6 @@ int GP_MatchPSP(const void *buf) return !memcmp(buf, PSP_SIGNATURE, PSP_SIGNATURE_LEN); }
-int GP_OpenPSP(const char *src_path, FILE **f) -{ - int err; - - *f = fopen(src_path, "rb"); - - if (*f == NULL) { - err = errno; - GP_DEBUG(1, "Failed to open '%s' : %s", - src_path, strerror(errno)); - goto err2; - } - - char buf[36]; - - if (fread(buf, sizeof(buf), 1, *f) < 1) { - GP_DEBUG(1, "Failed to read file header"); - err = EIO; - goto err1; - } - - if (memcmp(buf, PSP_SIGNATURE, PSP_SIGNATURE_LEN)) { - GP_DEBUG(1, "Invalid signature, not a PSP image?"); - err = EINVAL; - goto err1; - } - - struct psp_version version; - - version.major = BUF_TO_2(buf, 32); - version.minor = BUF_TO_2(buf, 34); - - GP_DEBUG(1, "Have PSP image version %u.%u", - version.major, version.minor); - - return 0; -err1: - fclose(*f); -err2: - errno = err; - return 1; -} - enum psp_block_id { PSP_IMAGE_BLOCK, PSP_CREATOR_BLOCK, @@ -229,40 +175,46 @@ struct psp_img_attrs { GP_Context *img; };
-static int psp_read_general_img_attr_chunk(FILE *f, +static int psp_read_general_img_attr_chunk(GP_IO *io, struct psp_img_attrs *attrs) { - uint8_t buf[38]; + int err;
if (attrs->is_loaded) { GP_WARN("Found Second Image Block"); return EINVAL; }
- //TODO SHIFT!!! - if (fread(buf, 4, 1, f) < 1) { - GP_DEBUG(1, "Failed to read Image block header"); - return EIO; - } - - if (fread(buf, sizeof(buf), 1, f) < 1) { - GP_DEBUG(1, "Failed to read Image chunk data"); - return EIO; + uint16_t general_image_info[] = { + GP_IO_I4, /* ??? */ + GP_IO_L4, /* width */ + GP_IO_L4, /* height */ + GP_IO_ARRAY | 8, /* resolution FIXME: double */ + GP_IO_BYTE, /* resolution metric */ + GP_IO_L2, /* compression type */ + GP_IO_L2, /* bit depth */ + GP_IO_L2, /* plane count */ + GP_IO_L2, /* color count */ + GP_IO_BYTE, /* grayscale flag */ + GP_IO_L4, /* total image size */ + GP_IO_I2, /* ??? */ + GP_IO_L4, /* active layer */ + GP_IO_L2, /* layer count */ + GP_IO_END + }; + + if (GP_IOReadF(io, general_image_info, &attrs->w, &attrs->h, + &attrs->res, &attrs->res_metric, &attrs->comp_type, + &attrs->bit_depth, &attrs->plane_count, + &attrs->color_count, &attrs->grayscale_flag, + &attrs->total_img_size, &attrs->active_layer, + &attrs->layer_count) != 14) { + err = errno; + GP_DEBUG(1, "Failed to read Image attributes: %s", + strerror(errno)); + return err; }
- attrs->w = BUF_TO_4(buf, 0); - attrs->h = BUF_TO_4(buf, 4); - attrs->res = BUF_TO_8(buf, 8); - attrs->res_metric = buf[16]; - attrs->comp_type = BUF_TO_2(buf, 17); - attrs->bit_depth = BUF_TO_2(buf, 19); - attrs->plane_count = BUF_TO_2(buf, 21); - attrs->color_count = BUF_TO_2(buf, 23); - attrs->grayscale_flag = buf[25]; - attrs->total_img_size = BUF_TO_4(buf, 26); - attrs->active_layer = BUF_TO_4(buf, 32); - attrs->layer_count = BUF_TO_2(buf, 36); - GP_DEBUG(3, "Image w=%u h=%u, compress=%s, bit_depth=%u, grayscale=%u", attrs->w, attrs->h, psp_comp_type_name(attrs->comp_type), attrs->bit_depth, attrs->grayscale_flag); @@ -275,10 +227,10 @@ static int psp_read_general_img_attr_chunk(FILE *f, return 0; }
-static int psp_next_block(FILE *f, struct psp_img_attrs *attrs, +static int psp_next_block(GP_IO *io, struct psp_img_attrs *attrs, GP_ProgressCallback *callback);
-static int psp_read_layer_start_block(FILE *f, struct psp_img_attrs *attrs, +static int psp_read_layer_start_block(GP_IO *io, struct psp_img_attrs *attrs, GP_ProgressCallback *callback) { int i; @@ -292,18 +244,18 @@ static int psp_read_layer_start_block(FILE *f, struct psp_img_attrs *attrs, attrs->subblock++;
for (i = 0; i < attrs->layer_count; i++) - psp_next_block(f, attrs, callback); + psp_next_block(io, attrs, callback);
attrs->subblock--;
return 0; }
-static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs, +static int psp_read_composite_image_block(GP_IO *io, struct psp_img_attrs *attrs, GP_ProgressCallback *callback) { - uint8_t buf[8]; uint32_t i, composite_image_count; + int err;
/* we are allready in subblock -> error */ if (attrs->subblock) { @@ -311,13 +263,18 @@ static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs, return EINVAL; }
- if (fread(buf, sizeof(buf), 1, f) < 1) { + uint16_t composite_image[] = { + GP_IO_I4, /* chunk size */ + GP_IO_L4, /* composit image count */ + GP_IO_END, + }; + + if (GP_IOReadF(io, composite_image, &composite_image_count) != 2) { + err = errno; GP_DEBUG(1, "Failed to read Composite Image Bank Info Chunk"); - return EIO; + return err; }
- composite_image_count = BUF_TO_4(buf, 4); - //TODO: utilize chunk_size
GP_DEBUG(3, "Composite image count=%u", composite_image_count); @@ -325,7 +282,7 @@ static int psp_read_composite_image_block(FILE *f, struct psp_img_attrs *attrs, attrs->subblock++;
for (i = 0; i < composite_image_count; i++) - psp_next_block(f, attrs, callback); + psp_next_block(io, attrs, callback);
attrs->subblock--;
@@ -359,25 +316,33 @@ struct psp_comp_img_attr_info { uint16_t comp_img_type; };
-static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *attrs, +static int psp_read_composite_attributes_block(GP_IO *io, struct psp_img_attrs *attrs, GP_ProgressCallback *callback) { - uint8_t buf[24]; struct psp_comp_img_attr_info info; + int err;
- if (fread(buf, sizeof(buf), 1, f) < 1) { - GP_DEBUG(1, "Failed to read Composite Image Bank Info Chunk"); - return EIO; + uint16_t info_chunk[] = { + GP_IO_I4, /* chunk size */ + GP_IO_L4, /* width */ + GP_IO_L4, /* height */ + GP_IO_L2, /* bit depth */ + GP_IO_L2, /* compression type */ + GP_IO_L2, /* plane count */ + GP_IO_L4, /* color count */ + GP_IO_L2, /* composite image type */ + GP_IO_END + }; + + if (GP_IOReadF(io, info_chunk, &info.w, &info.h, &info.bit_depth, + &info.comp_type, &info.plane_count, &info.color_count, + &info.comp_img_type) != 8) { + err = errno; + GP_DEBUG(1, "Failed to read Composite Image Attrs Info: %s", + strerror(err)); + return err; }
- info.w = BUF_TO_4(buf, 4); - info.h = BUF_TO_4(buf, 8); - info.bit_depth = BUF_TO_2(buf, 12); - info.comp_type = BUF_TO_2(buf, 14); - info.plane_count = BUF_TO_2(buf, 16); - info.color_count = BUF_TO_4(buf, 18); - info.comp_img_type = BUF_TO_2(buf, 22); - GP_DEBUG(4, "Composite Image w=%u h=%u, bit_depth=%u, comp_type=%s, " "comp_img_type=%s", info.w, info.h, info.bit_depth, psp_comp_type_name(info.comp_type), @@ -387,7 +352,7 @@ static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *at attrs->subblock++;
if (info.comp_img_type == PSP_IMAGE_COMPOSITE) - psp_next_block(f, attrs, callback); + psp_next_block(io, attrs, callback);
attrs->subblock--; attrs->priv = NULL; @@ -395,22 +360,23 @@ static int psp_read_composite_attributes_block(FILE *f, struct psp_img_attrs *at return 0; }
-static int psp_read_jpeg(FILE *f, struct psp_img_attrs *attrs, +static int psp_read_jpeg(GP_IO *io, struct psp_img_attrs *attrs, GP_ProgressCallback *callback) { - uint8_t buf[14]; int err;
+ GP_IOSeek(io, 14, GP_IO_SEEK_CUR); +/* if (fread(buf, sizeof(buf), 1, f) < 1) { GP_DEBUG(1, "Failed to read JPEG Information Chunk"); return EIO; } - +*/ //TODO: utilize chunk_size
GP_DEBUG(5, "JPEG Chunk");
- attrs->img = GP_ReadJPG(f, callback); + attrs->img = GP_ReadJPG(io, callback);
if (attrs->img == NULL) { err = errno; @@ -421,99 +387,123 @@ static int psp_read_jpeg(FILE *f, struct psp_img_attrs *attrs, return 0; }
-#define GEN_IMG_HEADER_ID "~BK" -#define GEN_IMG_HEADER_ID_LEN 4 - -static int psp_next_block(FILE *f, struct psp_img_attrs *attrs, +static int psp_next_block(GP_IO *io, struct psp_img_attrs *attrs, GP_ProgressCallback *callback) { - uint8_t buf[10]; uint16_t block_id; uint32_t block_size; - long offset; + off_t offset; int err = 0;
- if (fread(buf, sizeof(buf), 1, f) < 1) { - GP_DEBUG(1, "Failed to read block header"); - return EIO; - } + uint16_t block_header[] = { + '~', 'B', 'K', 0x00, + GP_IO_L2, /* block id */ + GP_IO_L4, /* block size */ + GP_IO_END + };
- if (memcmp(buf, GEN_IMG_HEADER_ID, GEN_IMG_HEADER_ID_LEN)) { - GP_DEBUG(1, "Invalid block header identifier"); - return EINVAL; + if (GP_IOReadF(io, block_header, &block_id, &block_size) != 6) { + err = errno; + GP_DEBUG(1, "Failed to read block header: %s", strerror(errno)); + return err; }
- block_id = BUF_TO_2(buf, 4); - block_size = BUF_TO_4(buf, 6); - GP_DEBUG(2 + attrs->subblock, "%s Block size %u", psp_block_id_name(block_id), block_size);
- offset = ftell(f) + block_size; + offset = GP_IOTell(io) + block_size;
switch (block_id) { case PSP_IMAGE_BLOCK: - err = psp_read_general_img_attr_chunk(f, attrs); + err = psp_read_general_img_attr_chunk(io, attrs); break; case PSP_LAYER_START_BLOCK: - err = psp_read_layer_start_block(f, attrs, callback); + err = psp_read_layer_start_block(io, attrs, callback); break; case PSP_COMPOSITE_IMAGE_BANK_BLOCK: - err = psp_read_composite_image_block(f, attrs, callback); + err = psp_read_composite_image_block(io, attrs, callback); break; case PSP_COMPOSITE_ATTRIBUTES_BLOCK: - err = psp_read_composite_attributes_block(f, attrs, callback); + err = psp_read_composite_attributes_block(io, attrs, callback); break; case PSP_JPEG_BLOCK: - err = psp_read_jpeg(f, attrs, callback); + err = psp_read_jpeg(io, attrs, callback); break; }
if (err) return err;
- if (fseek(f, offset, SEEK_SET) == -1) { + if (GP_IOSeek(io, offset, GP_IO_SEEK_SET) != offset) { err = errno; - GP_DEBUG(1, "Failed to seek to next block"); - return errno; + GP_DEBUG(1, "Failed to seek to next block; %s", + strerror(errno)); + return err; }
return 0; }
-GP_Context *GP_ReadPSP(FILE *f, GP_ProgressCallback *callback) +GP_Context *GP_ReadPSP(GP_IO *io, GP_ProgressCallback *callback) { int err = 0; struct psp_img_attrs attrs = {.is_loaded = 0, .subblock = 0, .priv = NULL, .img = NULL}; + struct psp_version version; + + uint16_t psp_header[] = { + 'P', 'a', 'i', 'n', 't', ' ', + 'S', 'h', 'o', 'p', ' ', + 'P', 'r', 'o', ' ', + 'I', 'm', 'a', 'g', 'e', ' ', + 'F', 'i', 'l', 'e', 'n', 0x1a, + 0x00, 0x00, 0x00, 0x00, 0x00, + GP_IO_L2, /* version major */ + GP_IO_L2, /* version minor */ + GP_IO_END + }; + + if (GP_IOReadF(io, psp_header, &version.major, &version.minor) != 34) { + GP_DEBUG(1, "Failed to read file header"); + err = EIO; + goto err0; + } + + GP_DEBUG(1, "Have PSP image version %u.%u", + version.major, version.minor);
while (!err) { - err = psp_next_block(f, &attrs, callback); + err = psp_next_block(io, &attrs, callback);
if (err) - goto err1; + goto err0;
- if (attrs.img != NULL) { - fclose(f); + if (attrs.img != NULL) return attrs.img; - } }
- fclose(f); errno = ENOSYS; return NULL; -err1: - fclose(f); +err0: errno = err; return NULL; }
GP_Context *GP_LoadPSP(const char *src_path, GP_ProgressCallback *callback) { - FILE *f; + GP_IO *io; + GP_Context *res; + int err;
- if (GP_OpenPSP(src_path, &f)) + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- return GP_ReadPSP(f, callback); + res = GP_ReadPSP(io, callback); + + err = errno; + GP_IOClose(io); + errno = err; + + return res; } diff --git a/libs/loaders/GP_TIFF.c b/libs/loaders/GP_TIFF.c index f9d32c8..93e5b42 100644 --- a/libs/loaders/GP_TIFF.c +++ b/libs/loaders/GP_TIFF.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -58,17 +58,6 @@ int GP_MatchTIFF(const void *buf) return 0; }
-int GP_OpenTIFF(const char *src_path, void **t) -{ - TIFF *tiff = TIFFOpen(src_path, "r"); - - if (tiff == NULL) - return 1; - - *t = tiff; - return 0; -} - static const char *compression_name(uint16_t compression) { switch (compression) { @@ -446,17 +435,70 @@ static int tiff_read(TIFF *tiff, GP_Context *res, struct tiff_header *header, return 0; }
-GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback) +static tmsize_t tiff_io_read(thandle_t io, void *buf, tmsize_t size) +{ + return GP_IORead(io, buf, size); +} + +static tmsize_t tiff_io_write(thandle_t io, void *buf, tmsize_t size) { + (void) io; + (void) buf; + GP_WARN("stub called"); + return size; +} + +static toff_t tiff_io_seek(thandle_t io, toff_t offset, int whence) +{ + return GP_IOSeek(io, offset, whence); +} + +static int tiff_io_close(thandle_t GP_UNUSED(io)) +{ + return 0; +} + +static toff_t tiff_io_size(thandle_t io) +{ + return GP_IOSize(io); +} + +/* +static int tiff_io_map(thandle_t io, void **base, toff_t *size) +{ + GP_WARN("stub called"); + return 0; +} + +static void tiff_io_unmap(thandle_t io, void *base, toff_t size) +{ + GP_WARN("stub called"); + return 0; +} +*/ + +GP_Context *GP_ReadTIFF(GP_IO *io, GP_ProgressCallback *callback) +{ + TIFF *tiff; struct tiff_header header; - GP_Context *res = NULL; + GP_Context *res; GP_PixelType pixel_type; int err;
- if ((err = read_header(t, &header))) + tiff = TIFFClientOpen("GFXprim IO", "r", io, tiff_io_read, + tiff_io_write, tiff_io_seek, tiff_io_close, + tiff_io_size, NULL, NULL); + + if (!tiff) { + GP_DEBUG(1, "TIFFClientOpen failed"); + err = EIO; + goto err0; + } + + if ((err = read_header(tiff, &header))) goto err1;
- pixel_type = match_pixel_type(t, &header); + pixel_type = match_pixel_type(tiff, &header);
if (pixel_type == GP_PIXEL_UNKNOWN) { err = ENOSYS; @@ -473,33 +515,42 @@ GP_Context *GP_ReadTIFF(void *t, GP_ProgressCallback *callback)
switch (header.photometric) { case PHOTOMETRIC_PALETTE: - err = tiff_read_palette(t, res, &header, callback); + err = tiff_read_palette(tiff, res, &header, callback); break; default: - err = tiff_read(t, res, &header, callback); + err = tiff_read(tiff, res, &header, callback); }
if (err) - goto err1; + goto err2; + + TIFFClose(tiff);
return res; -err1: +err2: GP_ContextFree(res); +err1: + TIFFClose(tiff); +err0: errno = err; return NULL; }
GP_Context *GP_LoadTIFF(const char *src_path, GP_ProgressCallback *callback) { - void *t; + GP_IO *io; GP_Context *res; + int err;
- if (GP_OpenTIFF(src_path, &t)) + io = GP_IOFile(src_path, GP_IO_RDONLY); + if (!io) return NULL;
- res = GP_ReadTIFF(t, callback); + res = GP_ReadTIFF(io, callback);
- TIFFClose(t); + err = errno; + GP_IOClose(io); + errno = err;
return res; } diff --git a/libs/loaders/GP_ZIP.c b/libs/loaders/GP_ZIP.c index c64214e..d6cbdd1 100644 --- a/libs/loaders/GP_ZIP.c +++ b/libs/loaders/GP_ZIP.c @@ -16,7 +16,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * - * Copyright (C) 2009-2013 Cyril Hrubis metan@ucw.cz * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * * * *****************************************************************************/
@@ -57,7 +57,7 @@ struct zip_chunks_table { };
struct zip_priv { - FILE *f; + GP_IO *io;
/* Current position in zip continer counted in images we found */ unsigned int cur_pos; @@ -131,14 +131,14 @@ static const char *compress_method_name(enum compress_method comp) return compress_method_names[comp]; }
-static int seek_bytes(FILE *f, uint32_t bytes) +static int seek_bytes(GP_IO *io, uint32_t bytes) { if (bytes == 0) return 0;
- GP_DEBUG(4, "Moving forward by %"PRIu32"bytes", bytes); + GP_DEBUG(4, "Moving forward by %"PRIu32" bytes", bytes);
- if (fseek(f, bytes, SEEK_CUR)) { + if (GP_IOSeek(io, bytes, GP_IO_SEEK_CUR) == (off_t)-1) { int err = errno; GP_DEBUG(1, "Failed to seek: %s", strerror(errno)); return err; @@ -153,21 +153,21 @@ struct deflate_inbuf { struct zip_local_header *zip_header; uint32_t to_read; unsigned char buf[CHUNK]; - FILE *f; + GP_IO *io; };
struct deflate_outbuf { uint32_t crc; uint32_t size; - FILE *f; + uint8_t *buf; };
static unsigned deflate_in(void *in_desc, unsigned char **buf) { struct deflate_inbuf *in = in_desc; - uint32_t chunk = in->to_read >= CHUNK ? CHUNK : in->to_read; + int chunk = in->to_read >= CHUNK ? CHUNK : in->to_read;
- if (fread(in->buf, chunk, 1, in->f) != 1) + if (GP_IORead(in->io, in->buf, chunk) != chunk) return 0;
*buf = in->buf; @@ -183,33 +183,25 @@ static int deflate_out(void *out_desc, unsigned char *buf, unsigned len) out->crc = crc32(out->crc, buf, len); out->size += len;
- if (fwrite(buf, len, 1, out->f) != 1) { - GP_DEBUG(1, "Failed to write temp file"); - return 1; - } + memcpy(out->buf + out->size, buf, len); + out->size += len;
return 0; }
-static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f) +static int read_deflate(GP_IO *io, struct zip_local_header *header, GP_IO **rio) { uint8_t *window; int err = 0, ret; - FILE *tf; - - tf = tmpfile(); - - if (!tf) { - err = errno; - GP_DEBUG(1, "Failed to create temp file"); - return err; - } + uint8_t *buf;
window = malloc(32 * 1024); + //TODO: Unsafe + buf = malloc(header->uncomp_size);
- if (!window) { + if (!window || !buf) { err = ENOMEM; - goto err0; + goto err1; }
z_stream strm = { @@ -229,12 +221,12 @@ static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f) struct deflate_outbuf outbuf = { .crc = crc32(0, NULL, 0), .size = 0, - .f = tf, + .buf = buf, };
struct deflate_inbuf inbuf = { .zip_header = header, - .f = f, + .io = io, .to_read = header->comp_size, };
@@ -261,32 +253,35 @@ static int read_deflate(FILE *f, struct zip_local_header *header, FILE **res_f) inflateBackEnd(&strm); free(window);
- rewind(tf); - *res_f = tf; + //TODO: Failure + *rio = GP_IOMem(outbuf.buf, outbuf.size, free); return 0; err2: inflateBackEnd(&strm); err1: free(window); -err0: - fclose(tf); + free(buf); return err; }
-static int zip_load_header(FILE *f, struct zip_local_header *header) +static int zip_load_header(GP_IO *io, struct zip_local_header *header) { - int ret, ch; + int ret; + uint8_t byte;
- ret = GP_FRead(f, "0x50 0x4b"); + uint16_t zip_header[] = { + 'P', + 'K', + GP_IO_BYTE, + GP_IO_END + };
- if (ret != 2) { + if (GP_IOReadF(io, zip_header, &byte) != 3) { GP_DEBUG(1, "Failed to read header"); return EIO; }
- ch = fgetc(f); - - switch (ch) { + switch (byte) { /* Central directory -> end of archive */ case 0x01: GP_DEBUG(1, "Reached end of the archive"); @@ -296,11 +291,25 @@ static int zip_load_header(FILE *f, struct zip_local_header *header) case 0x03: break; default: - GP_DEBUG(1, "Unexpected header PK%x", ch); + GP_DEBUG(1, "Unexpected header PK%x", byte); return EIO; }
- ret = GP_FRead(f, "0x04 L2 L2 L2 I4 L4 L4 L4 L2 L2", + uint16_t zip_local_header[] = { + 0x04, + GP_IO_L2, /* version */ + GP_IO_L2, /* bit flags */ + GP_IO_L2, /* compression type */ + GP_IO_IGN | 4, + GP_IO_L4, /* CRC */ + GP_IO_L4, /* compressed size */ + GP_IO_L4, /* uncompressed size */ + GP_IO_L2, /* filename length */ + GP_IO_L2, /* extra fields lenght */ + GP_IO_END + }; + + ret = GP_IOReadF(io, zip_local_header, &header->ver, &header->bit_flags, &header->comp_type, &header->crc, &header->comp_size, &header->uncomp_size, &header->fname_len, &header->extf_len); @@ -313,14 +322,15 @@ static int zip_load_header(FILE *f, struct zip_local_header *header) return 0; }
-static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback) +static GP_Context *zip_next_file(struct zip_priv *priv, + GP_ProgressCallback *callback) { struct zip_local_header header = {.file_name = NULL}; int err = 0; GP_Context *ret = NULL; - FILE *fres; + GP_IO *io;
- if ((err = zip_load_header(f, &header))) + if ((err = zip_load_header(priv->io, &header))) goto out;
GP_DEBUG(1, "Have ZIP local header version %u.%u compression %s", @@ -347,7 +357,7 @@ static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback)
header.file_name[header.fname_len] = '0';
- if (fread(header.file_name, header.fname_len, 1, f) != 1) { + if (GP_IORead(priv->io, header.file_name, header.fname_len) != header.fname_len) { GP_DEBUG(1, "Failed to read filename"); err = EIO; goto out; @@ -359,41 +369,43 @@ static GP_Context *zip_next_file(FILE *f, GP_ProgressCallback *callback) header.uncomp_size); }
- seek_bytes(f, header.extf_len); + seek_bytes(priv->io, header.extf_len);
switch (header.comp_type) { case COMPRESS_STORED: /* skip directories */ - if (header.uncomp_size == 0) + if (header.uncomp_size == 0) { + GP_DEBUG(2, "Skipping directory"); goto out; + }
- off_t cur_off = ftell(f); + GP_IOMark(priv->io, GP_IO_MARK);
- ret = GP_ReadJPG(f, callback); + ret = GP_ReadJPG(priv->io, callback);
if (!ret) { - fseek(f, cur_off, SEEK_SET); - ret = GP_ReadPNG(f, callback); + GP_IOMark(priv->io, GP_IO_REWIND); + ret = GP_ReadPNG(priv->io, callback); }
- fseek(f, cur_off + header.comp_size, SEEK_SET); + GP_IOSeek(priv->io, priv->io->mark + header.comp_size, GP_IO_SEEK_SET);
goto out; break; case COMPRESS_DEFLATE: - if (read_deflate(f, &header, &fres)) { + if (read_deflate(priv->io, &header, &io)) { err = errno; goto out; }
- ret = GP_ReadJPG(fres, callback); + ret = GP_ReadJPG(io, callback);
if (!ret) { - rewind(fres); - ret = GP_ReadPNG(fres, callback); + GP_IORewind(io); + ret = GP_ReadPNG(io, callback); }
- fclose(fres); + GP_IOClose(io); goto out; break; default: @@ -476,8 +488,8 @@ static GP_Context *zip_load_next(GP_Container *self, GP_DEBUG(1, "Trying to load next image from ZIP container");
do { - offset = ftell(priv->f); - ret = zip_next_file(priv->f, callback); + offset = GP_IOTell(priv->io); + ret = zip_next_file(priv, callback); } while (ret == NULL && errno == 0);
if (!ret) @@ -524,25 +536,25 @@ static void seek_cur_pos(struct zip_priv *priv) GP_DEBUG(2, "Setting current position to %u (%li)", priv->cur_pos, priv->cur_table->offsets[cur_pos]);
- fseek(priv->f, priv->cur_table->offsets[cur_pos], SEEK_SET); + GP_IOSeek(priv->io, priv->cur_table->offsets[cur_pos], GP_IO_SEEK_SET); }
static int load_next_offset(struct zip_priv *priv) { struct zip_local_header header = {.file_name = NULL}; int ret; - long offset = ftell(priv->f); + long offset = GP_IOTell(priv->io);
- if ((ret = zip_load_header(priv->f, &header))) + if ((ret = zip_load_header(priv->io, &header))) return ret;
//TODO: Match image extension and signature record_offset(priv, offset);
/* Seek to the next local header */ - seek_bytes(priv->f, (uint32_t)header.fname_len + + seek_bytes(priv->io, (uint32_t)header.fname_len + (uint32_t)header.extf_len); - seek_bytes(priv->f, header.comp_size); + seek_bytes(priv->io, header.comp_size);
return 0; } @@ -641,39 +653,54 @@ static void zip_close(GP_Container *self) /* Free allocated offset tables */ for (i = priv->table.next; i != NULL; j = i, i = i->next, free(j));
- fclose(priv->f); + GP_IOClose(priv->io); free(self); }
-static int open_zip(const char *path, FILE **file) +static GP_IO *open_zip(const char *path) { - FILE *f; + GP_IO *io; int err = 0;
- f = fopen(path, "rb"); + io = GP_IOFile(path, GP_IO_RDONLY);
- if (f == NULL) { + if (!io) { err = errno; GP_DEBUG(1, "Failed to open '%s': %s", path, strerror(errno)); - if (!err) - err = EIO; - return err; + goto err0; }
/* Check zip local file header and seek back */ - if (GP_FRead(f, "0x50 0x4b 0x03 0x04") != 4) { + if (GP_IOMark(io, GP_IO_MARK)) { + err = errno; + goto err1; + } + + static uint16_t zip_header[] = { + 'P', + 'K', + 0x03, + 0x04, + GP_IO_END + }; + + if (GP_IOReadF(io, zip_header) != 4) { GP_DEBUG(1, "Invalid zip header"); err = EINVAL; - goto err0; + goto err1; }
- rewind(f); + if (GP_IOMark(io, GP_IO_REWIND)) { + err = errno; + goto err1; + }
- *file = f; - return 0; + return io; +err1: + GP_IOClose(io); err0: - fclose(f); - return err; + errno = err; + return NULL; }
static const struct GP_ContainerOps zip_ops = { @@ -688,13 +715,13 @@ GP_Container *GP_OpenZip(const char *path) { struct zip_priv *priv; GP_Container *ret; - FILE *f; + GP_IO *io; int err;
- if ((err = open_zip(path, &f))) { - errno = err; + io = open_zip(path); + + if (!io) return NULL; - }
ret = malloc(sizeof(GP_Container) + sizeof(struct zip_priv));
@@ -711,7 +738,7 @@ GP_Container *GP_OpenZip(const char *path)
priv = GP_CONTAINER_PRIV(ret);
- priv->f = f; + priv->io = io;
priv->table.next = NULL; priv->table.prev = NULL; @@ -730,16 +757,15 @@ GP_Container *GP_OpenZip(const char *path)
return ret; err0: - fclose(f); + GP_IOClose(io); errno = err; return NULL; }
#else
-GP_Container *GP_OpenZip(const char *path) +GP_Container *GP_OpenZip(const char GP_UNUSED(*path)) { - (void) path; GP_FATAL("zlib support not compiled in"); errno = ENOSYS; return NULL; diff --git a/tests/loaders/IO.c b/tests/loaders/IO.c new file mode 100644 index 0000000..32cfa2a --- /dev/null +++ b/tests/loaders/IO.c @@ -0,0 +1,274 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <string.h> +#include <errno.h> + +#include <core/GP_Common.h> +#include <loaders/GP_IO.h> + +#include "tst_test.h" + +/* + * Expects IO buffer filled with monotonically increasing bytes, i.e. + * 0x00 0x01 0x02 ... + */ +static int do_test(GP_IO *io) +{ + int ret; + uint8_t buf[10]; + unsigned int i; + + ret = GP_IORead(io, buf, 10); + + if (ret != 10) { + tst_msg("First IO read failed"); + return TST_FAILED; + } + + for (i = 0; i < 10; i++) { + if (i != buf[i]) { + tst_msg("Read wrong data at %u", i); + return TST_FAILED; + } + } + + ret = GP_IOTell(io); + + if (ret != 10) { + tst_msg("Have wrong offset %u, after read 10", ret); + return TST_FAILED; + } + + + ret = GP_IORead(io, buf, 10); + + if (ret != 10) { + tst_msg("Second IO read failed"); + return TST_FAILED; + } + + for (i = 0; i < 10; i++) { + if (i + 10 != buf[i]) { + tst_msg("Read wrong data at %u", i + 10); + return TST_FAILED; + } + } + + if (GP_IORewind(io)) { + tst_msg("Failed to rewind to start"); + return TST_FAILED; + } + + ret = GP_IOTell(io); + + if (ret != 0) { + tst_msg("Have wrong offset %u, after rewind", ret); + return TST_FAILED; + } + + uint16_t header[] = { + 0x00, + 0x01, + GP_IO_BYTE, + GP_IO_IGN | 7, + GP_IO_L2, + GP_IO_END + }; + + uint8_t byte; + uint16_t val; + + if (GP_IOReadF(io, header, &byte, &val) != 5) { + tst_msg("Failed to ReadF from Memory IO"); + return TST_FAILED; + } + + if (byte != 2) { + tst_msg("Read wrong value byte = %u (expected 2)", byte); + return TST_FAILED; + } + + if (val != 0x0b0a) { + tst_msg("Read wrong value = %04x (expected 0x0b0a)", val); + return TST_FAILED; + } + + return TST_SUCCESS; +} + +static int test_IOMem(void) +{ + uint8_t buffer[128]; + unsigned int i; + GP_IO *io; + int ret; + + for (i = 0; i < sizeof(buffer); i++) + buffer[i] = i; + + io = GP_IOMem(buffer, sizeof(buffer), NULL); + + if (!io) { + tst_msg("Failed to initialize memory IO"); + return TST_FAILED; + } + + ret = do_test(io); + if (ret) + return ret; + + if (GP_IOClose(io)) { + tst_msg("Failed to close memory IO"); + return TST_FAILED; + } + + return TST_SUCCESS; +} + +#define TFILE "test.io" + +static int test_IOFile(void) +{ + uint8_t buffer[128]; + unsigned int i; + int ret; + GP_IO *io; + + for (i = 0; i < sizeof(buffer); i++) + buffer[i] = i; + + io = GP_IOFile(TFILE, GP_IO_WRONLY); + + if (!io) { + tst_msg("Failed to open file IO for writing: %s", + strerror(errno)); + return TST_FAILED; + } + + ret = GP_IOWrite(io, buffer, sizeof(buffer)); + + if (ret != sizeof(buffer)) { + tst_msg("Failed to write: %s", strerror(errno)); + return TST_FAILED; + } + + if (GP_IOClose(io)) { + tst_msg("Failed to close file IO: %s", strerror(errno)); + return TST_FAILED; + } + + io = GP_IOFile(TFILE, GP_IO_RDONLY); + + if (!io) { + tst_msg("Failed to open file IO for reading: %s", + strerror(errno)); + return TST_FAILED; + } + + ret = do_test(io); + if (ret) + return ret; + + if (GP_IOClose(io)) { + tst_msg("Failed to close file IO: %s", strerror(errno)); + return TST_FAILED; + } + + return TST_SUCCESS; +} + +static ssize_t test_IOFill_read(GP_IO GP_UNUSED(*io), void *buf, size_t size) +{ + ssize_t ret = GP_MIN(7u, size); + + memset(buf, 'a', ret); + + return ret; +} + +static int try_IOFill_and_check(GP_IO *io, unsigned int size) +{ + uint8_t buf[125]; + unsigned int i, fail = 0; + + memset(buf, 0, sizeof(buf)); + + if (GP_IOFill(io, buf, size)) { + tst_msg("Failed to fill buffer size=%u: %s", + size, strerror(errno)); + return TST_FAILED; + } + + for (i = 0; i < size; i++) { + if (buf[i] != 'a') { + tst_msg("Wrong data in buffer at %u", i); + fail++; + } + } + + for (i = size; i < sizeof(buf); i++) { + if (buf[i] != 0) { + tst_msg("Wrong data in buffer at %u", i); + fail++; + } + } + + if (fail) + return TST_FAILED; + + return TST_SUCCESS; +} + +static int test_IOFill(void) +{ + GP_IO io = {.Read = test_IOFill_read}; + int ret = 0; + + ret += try_IOFill_and_check(&io, 7); + ret += try_IOFill_and_check(&io, 10); + ret += try_IOFill_and_check(&io, 43); + ret += try_IOFill_and_check(&io, 69); + + if (ret) + return TST_FAILED; + + return TST_SUCCESS; +} + +const struct tst_suite tst_suite = { + .suite_name = "IO", + .tests = { + {.name = "IOMem", + .tst_fn = test_IOMem, + .flags = TST_CHECK_MALLOC}, + + {.name = "IOFile", + .tst_fn = test_IOFile, + .flags = TST_CHECK_MALLOC | TST_TMPDIR}, + + {.name = "IOFill", + .tst_fn = test_IOFill}, + + {.name = NULL}, + } +}; diff --git a/tests/loaders/Makefile b/tests/loaders/Makefile index a5a14cf..6678352 100644 --- a/tests/loaders/Makefile +++ b/tests/loaders/Makefile @@ -1,10 +1,10 @@ TOPDIR=../.. include $(TOPDIR)/pre.mk
-CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c +CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c IO.c GENSOURCES=SaveLoad.gen.c SaveAbort.gen.c
-APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF +APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF IO
include ../tests.mk
diff --git a/tests/loaders/data/gif/valid/100x100-white.gif b/tests/loaders/data/gif/valid/100x100-white.gif new file mode 100644 index 0000000..11f0f8f Binary files /dev/null and b/tests/loaders/data/gif/valid/100x100-white.gif differ diff --git a/tests/loaders/test_list.txt b/tests/loaders/test_list.txt index 4ff3077..add0cb3 100644 --- a/tests/loaders/test_list.txt +++ b/tests/loaders/test_list.txt @@ -6,5 +6,6 @@ PGM PPM ZIP GIF +IO SaveLoad.gen SaveAbort.gen
http://repo.or.cz/w/gfxprim.git/commit/342537c6df7ca58ca4ac35d0b6f1dae16ef67...
commit 342537c6df7ca58ca4ac35d0b6f1dae16ef6746a Author: Cyril Hrubis metan@ucw.cz Date: Fri Jan 3 20:48:18 2014 +0100
tests: loaders: Very basic GIF test.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/tests/loaders/GIF.c b/tests/loaders/GIF.c new file mode 100644 index 0000000..e33847e --- /dev/null +++ b/tests/loaders/GIF.c @@ -0,0 +1,68 @@ +/***************************************************************************** + * This file is part of gfxprim library. * + * * + * Gfxprim is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Lesser General Public * + * License as published by the Free Software Foundation; either * + * version 2.1 of the License, or (at your option) any later version. * + * * + * Gfxprim is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * Lesser General Public License for more details. * + * * + * You should have received a copy of the GNU Lesser General Public * + * License along with gfxprim; if not, write to the Free Software * + * Foundation, Inc., 51 Franklin Street, Fifth Floor, * + * Boston, MA 02110-1301 USA * + * * + * Copyright (C) 2009-2014 Cyril Hrubis metan@ucw.cz * + * * + *****************************************************************************/ + +#include <string.h> +#include <errno.h> +#include <sys/stat.h> + +#include <core/GP_Context.h> +#include <core/GP_GetPutPixel.h> +#include <loaders/GP_Loaders.h> + +#include "tst_test.h" + +static int test_load_GIF(const char *path) +{ + GP_Context *img; + + errno = 0; + + img = GP_LoadGIF(path, NULL); + + if (img == NULL) { + switch (errno) { + case ENOSYS: + tst_msg("Not Implemented"); + return TST_SKIPPED; + default: + tst_msg("Got %s", strerror(errno)); + return TST_FAILED; + } + } + + GP_ContextFree(img); + + return TST_SUCCESS; +} + +const struct tst_suite tst_suite = { + .suite_name = "GIF", + .tests = { + {.name = "GIF Load 100x100", + .tst_fn = test_load_GIF, + .res_path = "data/gif/valid/100x100-white.gif", + .data = "100x100-white.gif", + .flags = TST_TMPDIR | TST_CHECK_MALLOC}, + + {.name = NULL}, + } +}; diff --git a/tests/loaders/Makefile b/tests/loaders/Makefile index a592ff9..a5a14cf 100644 --- a/tests/loaders/Makefile +++ b/tests/loaders/Makefile @@ -1,10 +1,10 @@ TOPDIR=../.. include $(TOPDIR)/pre.mk
-CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c +CSOURCES=loaders_suite.c PNG.c PBM.c PGM.c PPM.c ZIP.c GIF.c GENSOURCES=SaveLoad.gen.c SaveAbort.gen.c
-APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP +APPS=loaders_suite PNG PBM PGM PPM SaveLoad.gen SaveAbort.gen ZIP GIF
include ../tests.mk
diff --git a/tests/loaders/test_list.txt b/tests/loaders/test_list.txt index 9f52d34..4ff3077 100644 --- a/tests/loaders/test_list.txt +++ b/tests/loaders/test_list.txt @@ -5,5 +5,6 @@ PBM PGM PPM ZIP +GIF SaveLoad.gen SaveAbort.gen
http://repo.or.cz/w/gfxprim.git/commit/f36c5f6d8df50ad268711cc97c9bc369672b7...
commit f36c5f6d8df50ad268711cc97c9bc369672b7fe8 Author: Cyril Hrubis metan@ucw.cz Date: Fri Jan 3 19:23:18 2014 +0100
config: Add GA88 pixel type.
Signed-off-by: Cyril Hrubis metan@ucw.cz
diff --git a/gfxprim_config.py b/gfxprim_config.py index b972c0e..8bb69f4 100644 --- a/gfxprim_config.py +++ b/gfxprim_config.py @@ -122,6 +122,10 @@ config = GfxPrimConfig( PixelType(name='G8', pixelsize=PS_8BPP, chanslist=[ ('V', 0, 8)]),
+ PixelType(name='GA88', pixelsize=PS_16BPP, chanslist=[ + ('V', 0, 8), + ('A', 8, 8)]), + PixelType(name='G16', pixelsize=PS_16BPP, chanslist=[ ('V', 0, 16)]), ]
-----------------------------------------------------------------------
Summary of changes: build/syms/Loaders_symbols.txt | 24 +- demos/c_simple/Makefile | 3 +- .../{backend_timers_example.c => memory_io.c} | 102 +++--- doc/Makefile | 2 +- doc/example_memory_io.txt | 9 + doc/loaders.txt | 247 +++++------- doc/loaders_io.txt | 190 +++++++++ gfxprim_config.py | 4 + include/loaders/GP_BMP.h | 38 +-- include/loaders/GP_GIF.h | 30 +- include/loaders/GP_IO.h | 184 +++++++++ include/loaders/GP_JP2.h | 19 +- include/loaders/GP_JPG.h | 27 +- include/loaders/GP_Loader.h | 2 +- include/loaders/GP_PNG.h | 37 +-- include/loaders/GP_PNM.h | 11 +- include/loaders/GP_PSP.h | 32 +- include/loaders/GP_TIFF.h | 37 +-- libs/loaders/GP_BMP.c | 283 ++++++------- libs/loaders/GP_BMP_RLE.h | 84 +++-- libs/loaders/GP_GIF.c | 93 +++-- libs/loaders/GP_IO.c | 432 ++++++++++++++++++++ libs/loaders/GP_JP2.c | 73 ++-- libs/loaders/GP_JPG.c | 107 ++++-- libs/loaders/GP_PNG.c | 83 ++--- libs/loaders/GP_PNM.c | 347 ++++++++++------ libs/loaders/GP_PSP.c | 278 ++++++------- libs/loaders/GP_TIFF.c | 99 ++++-- libs/loaders/GP_ZIP.c | 198 +++++---- tests/{input/TimeStamp.c => loaders/GIF.c} | 58 ++-- tests/loaders/IO.c | 274 +++++++++++++ tests/loaders/Makefile | 4 +- tests/loaders/data/gif/valid/100x100-white.gif | Bin 0 -> 169 bytes tests/loaders/test_list.txt | 2 + 34 files changed, 2281 insertions(+), 1132 deletions(-) copy demos/c_simple/{backend_timers_example.c => memory_io.c} (57%) create mode 100644 doc/example_memory_io.txt create mode 100644 doc/loaders_io.txt create mode 100644 include/loaders/GP_IO.h create mode 100644 libs/loaders/GP_IO.c copy tests/{input/TimeStamp.c => loaders/GIF.c} (70%) create mode 100644 tests/loaders/IO.c create mode 100644 tests/loaders/data/gif/valid/100x100-white.gif
repo.or.cz automatic notification. Contact project admin jiri.bluebear.dluhos@gmail.com if you want to unsubscribe, or site admin admin@repo.or.cz if you receive no reply.