From 9043a9f31fd8d403c74a9af8507cae1b5cfb348c Mon Sep 17 00:00:00 2001 From: Carsten Haitzler Date: Mon, 1 Nov 2004 09:47:12 +0000 Subject: [PATCH] and new loaders tree SVN revision: 12114 --- AUTHORS | 6 + COPYING | 28 + COPYING-PLAIN | 33 + COPYING.loader_xcf | 339 ++++ ChangeLog | 6 + INSTALL | 14 + Makefile.am | 8 + NEWS | 0 README | 33 + autogen.sh | 13 + configure.in | 223 +++ debian/Makefile.am | 7 + debian/changelog | 5 + debian/control | 17 + debian/copyright | 32 + debian/rules | 75 + imlib2_loaders.spec | 41 + m4/ac_expand_dir.m4 | 14 + m4/ac_path_generic.m4 | 136 ++ src/Makefile.am | 2 + src/modules/Makefile.am | 2 + src/modules/loaders/Makefile.am | 48 + src/modules/loaders/color_values.h | 20 + src/modules/loaders/common.h | 27 + src/modules/loaders/image.h | 180 ++ src/modules/loaders/loader_ani.c | 370 ++++ src/modules/loaders/loader_db.c | 407 +++++ src/modules/loaders/loader_eet.c | 408 +++++ src/modules/loaders/loader_ico.c | 622 +++++++ src/modules/loaders/loader_xcf.c | 1752 +++++++++++++++++++ src/modules/loaders/loader_xcf_pixelfuncs.c | 757 ++++++++ 31 files changed, 5625 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING-PLAIN create mode 100644 COPYING.loader_xcf create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100755 autogen.sh create mode 100644 configure.in create mode 100644 debian/Makefile.am create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/rules create mode 100644 imlib2_loaders.spec create mode 100644 m4/ac_expand_dir.m4 create mode 100644 m4/ac_path_generic.m4 create mode 100644 src/Makefile.am create mode 100644 src/modules/Makefile.am create mode 100644 src/modules/loaders/Makefile.am create mode 100644 src/modules/loaders/color_values.h create mode 100644 src/modules/loaders/common.h create mode 100644 src/modules/loaders/image.h create mode 100644 src/modules/loaders/loader_ani.c create mode 100644 src/modules/loaders/loader_db.c create mode 100644 src/modules/loaders/loader_eet.c create mode 100644 src/modules/loaders/loader_ico.c create mode 100644 src/modules/loaders/loader_xcf.c create mode 100644 src/modules/loaders/loader_xcf_pixelfuncs.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..29fd645 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,6 @@ + +XCF loader: Christian Kreibich , based on + code from the Gimp (www.gimp.org). + +DB loader: The rasterman , packaged by + Tom Gilbert diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..474fcc5 --- /dev/null +++ b/COPYING @@ -0,0 +1,28 @@ +Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. This includes +acknowledgments in either Copyright notices, Manuals, Publicity and Marketing +documents or any documentation provided with any product containing this +software. This License does not apply to any software that links to the +libraries provided by this software (statically or dynamically), but only to +the software provided. + +Please see the COPYING.PLAIN for a plain-english explanation of this notice +and it's intent. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/COPYING-PLAIN b/COPYING-PLAIN new file mode 100644 index 0000000..376875e --- /dev/null +++ b/COPYING-PLAIN @@ -0,0 +1,33 @@ +Plain English Copyright Notice + +This file is not intended to be the actual License. The reason this file +exists is that we here are programmers and engineers. We aren't lawyers. We +provide licenses that we THINK say the right things, but we have our own +intentions at heart. This is a plain-english explanation of what those +intentions are, and if you follow them you will be within the "spirit" of +the license. + +The intent is for us to enjoy writing software that is useful to us (the +AUTHORS) and allow others to use it freely and also benefit from the work we +put into making it. We don't want to restrict others using it. They should +not *HAVE* to make the source code of the applications they write that +simply link to these libraries (be that statically or dynamically), or for +them to be limited as to what license they choose to use (be it open, closed +or anything else). But we would like to know you are using these libraries. +We simply would like to know that it has been useful to someone. This is why +we ask for acknowledgement of some sort. + +You can do what you want with the source of this software - it doesn't +matter. We still have it here for ourselves and it is open and free to use +and download and play with. It can't be taken away. We don't really mind what +you do with the source to your software. We would simply like to know that +you are using it - especially if it makes it to a commerical product. If you +simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and +then make sure you include a paragraph or page in the manual for the product +with the copyright notice and state that you used this software, we will be +very happy. If you want to contribute back modifications and fixes you may have +made we will welcome those too with open arms (generally). If you want help +with changes needed, ports needed or features to be added, arrangements can +be easily made with some dialogue. + +Carsten Haitzler diff --git a/COPYING.loader_xcf b/COPYING.loader_xcf new file mode 100644 index 0000000..4189933 --- /dev/null +++ b/COPYING.loader_xcf @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..3934308 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,6 @@ +Tue Aug 31 11:46:49 JST 2004 +(Raster) + +Up to 1.1.2 to match imlib2 main release + +_______________________________________________ diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..013370a --- /dev/null +++ b/INSTALL @@ -0,0 +1,14 @@ +COMPILING and INSTALLING: + +If you got a official release tar archive do: + ./configure + +( otherwise if you got this from enlightenment cvs do: ./autogen.sh ) + +Then to compile: + make + +To install (run this as root, or the user who handles installs): + make install + +NOTE: You MUST make install Epeg for it to run properly. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..29314d6 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,8 @@ +SUBDIRS = src debian + +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ + config.h.in config.sub configure install-sh \ + ltconfig ltmain.sh missing mkinstalldirs \ + stamp-h.in + +EXTRA_DIST = README AUTHORS COPYING COPYING-PLAIN imlib2_loaders.spec COPYING.loader_xcf diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..9a629c3 --- /dev/null +++ b/README @@ -0,0 +1,33 @@ + + I M L I B 2 + + Additional Image Loaders +________________________________________________________________________ + + +This package contains image loader plugins for Imlib 2 that are not dis- +tributed together with the Imlib 2 package itself. More about Imlib 2 +can be found on http://www.rasterman.com/imlib.html. + +XCF loader: + +The XCF loader cannot be packaged together with Imlib 2 because Imlib 2 +is distributed under the BSD license, whereas the XCF loader is using +elements of the Gimp's (www.gimp.org) codebase, which is distributed +under the GPL. The XCF loader therefore is GPL'd as well. + +To install, apply the usual + + ./configure ; make; make install + +sequence. + + + Have fun, + --cK. + + +EDB loader + +Requires +edb ftp://ftp.enlightenment.org/pub/e/e17/libs/ diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..9d8816d --- /dev/null +++ b/autogen.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f aclocal.m4 + +echo "Running aclocal..."; aclocal $ACLOCAL_FLAGS -I m4 \ +&& echo "Running autoheader..."; autoheader \ +&& echo "Running autoconf..."; autoconf \ +&& echo "Running libtoolize..."; (libtoolize --automake || glibtoolize --automake) \ +&& echo "Running automake..."; automake --add-missing --copy --gnu + +### If you want this, uncomment it. +./configure "$@" diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..f21d43c --- /dev/null +++ b/configure.in @@ -0,0 +1,223 @@ +# get rid of that stupid cache mechanism +rm -f config.cache + +AC_INIT(configure.in) +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_CANONICAL_TARGET +AC_ISC_POSIX +AM_INIT_AUTOMAKE(imlib2_loaders, 1.2.0) +AM_CONFIG_HEADER(config.h) + +AC_C_BIGENDIAN +AC_PROG_CC +AM_PROG_CC_STDC +AC_HEADER_STDC +AC_C_CONST +AM_ENABLE_SHARED +AM_PROG_LIBTOOL + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +else + if test "x${prefix}" = "xNONE"; then + bindir="${ac_default_prefix}/bin"; + else + bindir="${prefix}/bin"; + fi +fi + +if test "x${exec_prefix}" = "xNONE"; then + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +else + if test "x${prefix}" = "xNONE"; then + libdir="${ac_default_prefix}/lib"; + else + libdir="${prefix}/lib"; + fi +fi + +dnl Set PACKAGE_BIN_DIR in config.h. +if test "x${bindir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${ac_default_prefix}/bin", [Installation directory for user executables]) + else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${prefix}/bin", [Installation directory for user executables]) + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_BIN_DIR, "${bindir}", [Installation directory for user executables]) +fi + +dnl Set PACKAGE_LIB_DIR in config.h. +if test "x${libdir}" = 'xNONE'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${ac_default_prefix}/lib", [Installation directory for libraries]) + else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${prefix}/lib", [Installation directory for libraries]) + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_LIB_DIR, "${libdir}", [Installation directory for libraries]) +fi + +dnl Set PACKAGE_DATA_DIR in config.h. +if test "x${datadir}" = 'x${prefix}/share'; then + if test "x${prefix}" = "xNONE"; then + AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${ac_default_prefix}/share/${PACKAGE}", "Package installed data destination") + else + AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${prefix}/share/${PACKAGE}", "Package installed data destination") + fi +else + AC_DEFINE_UNQUOTED(PACKAGE_DATA_DIR, "${datadir}/${PACKAGE}", "Package installed data destination") +fi + +dnl Set PACKAGE_SOURCE_DIR in config.h. +packagesrcdir=`cd $srcdir && pwd` +AC_DEFINE_UNQUOTED(PACKAGE_SOURCE_DIR, "${packagesrcdir}", [Source code directory]) + + +AC_ARG_ENABLE(edb, +[ --disable-edb disable building the edb loader], +[ + if test x$enableval = xno; then + edb=no; + fi +]) + +AC_ARG_ENABLE(eet, +[ --disable-eet disable building the eet loader], +[ + if test x$enableval = xno; then + eet=no; + fi +]) + +AC_ARG_ENABLE(xcf, +[ --disable-xcf disable building the xcf loader], +[ + if test x$enableval = xno; then + xcf=no; + fi +]) + +AC_ARG_WITH(imlib2-config, +[ --with-imlib2-config=IMLIB2_CONFIG use imlib2-config specified ], +[ + PROG_CONFIG=$withval; + echo "using "$PROG_CONFIG" for imlib2-config"; +],[ + PROG="imlib2-config"; + AC_PATH_PROG(PROG_CONFIG, $PROG, "", $PATH) +]) +if test -n "$IMLIB2_CONFIG"; then + PROG_CONFIG=$IMLIB2_CONFIG; +fi +if test -z "$PROG_CONFIG"; then + echo $PROG " is not in your \$PATH. Please ensure it is."; + echo "You may need to install the library and/or development packages"; + echo "that contain this configure-script."; + echo "FATAL ERROR. ABORT."; + exit -1; +fi +my_includes=`$PROG_CONFIG --cflags` +AC_SUBST(my_includes) + + +AC_ARG_WITH(edb-config, +[ --with-edb-config=EDB_CONFIG use edb-config specified ], +[ + PROG_CONFIG=$withval; + echo "using "$PROG_CONFIG" for edb-config"; +],[ + PROG="edb-config"; + AC_PATH_PROG(PROG_CONFIG, $PROG, "", $PATH) +]) +if test -n "$EDB_CONFIG"; then + PROG_CONFIG=$EDB_CONFIG; +fi +if test -z "$PROG_CONFIG"; then + echo $PROG " is not in your \$PATH. Please ensure it is."; + echo "You may need to install the library and/or development packages"; + echo "that contain this configure-script."; + echo "FATAL ERROR. ABORT."; + exit -1; +fi +EDB_CFLAGS=`$PROG_CONFIG --cflags` +EDB_LIBS=`$PROG_CONFIG --libs` +AC_SUBST(EDB_CFLAGS) +AC_SUBST(EDB_LIBS) + + +AC_ARG_WITH(eet-config, +[ --with-eet-config=EET_CONFIG use eet-config specified ], +[ + PROG_CONFIG=$withval; + echo "using "$PROG_CONFIG" for eet-config"; +],[ + PROG="eet-config"; + AC_PATH_PROG(PROG_CONFIG, $PROG, "", $PATH) +]) +if test -n "$EET_CONFIG"; then + PROG_CONFIG=$EET_CONFIG; +fi +if test -z "$PROG_CONFIG"; then + echo $PROG " is not in your \$PATH. Please ensure it is."; + echo "You may need to install the library and/or development packages"; + echo "that contain this configure-script."; + echo "FATAL ERROR. ABORT."; + exit -1; +fi +EET_CFLAGS=`$PROG_CONFIG --cflags` +EET_LIBS=`$PROG_CONFIG --libs` +AC_SUBST(EET_CFLAGS) +AC_SUBST(EET_LIBS) + + + +AM_CONDITIONAL(BUILD_EDB_LOADER, test x$edb != xno) +AM_CONDITIONAL(BUILD_EET_LOADER, test x$eet != xno) +AM_CONDITIONAL(BUILD_XCF_LOADER, test x$xcf != xno) + +AC_OUTPUT([ +Makefile +src/Makefile +src/modules/Makefile +src/modules/loaders/Makefile +debian/Makefile +],[ +]) + +echo -e "\nBuild summary:" +echo "------------------------" +echo -n " EDB: " +if test x$edb = xno ; then + echo "Disabled " +else + echo "Enabled " +fi + +echo -e "\nBuild summary:" +echo "------------------------" +echo -n " EET: " +if test x$eet = xno ; then + echo "Disabled " +else + echo "Enabled " +fi + +echo -e "\nBuild summary:" +echo "------------------------" +echo -n " XCF: " +if test x$xcf = xno ; then + echo "Disabled " +else + echo "Enabled " +fi + diff --git a/debian/Makefile.am b/debian/Makefile.am new file mode 100644 index 0000000..8beb64b --- /dev/null +++ b/debian/Makefile.am @@ -0,0 +1,7 @@ +MAINTAINERCLEANFILES = Makefile.in + +EXTRA_DIST = \ +changelog \ +control \ +copyright \ +rules diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..b337b44 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +imlib2-loaders (1.1.2-0cvs20040918) unstable; urgency=low + + * a CVS release + + -- Sytse Wielinga Sat, 18 Sep 2004 12:55:07 +0200 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..2195244 --- /dev/null +++ b/debian/control @@ -0,0 +1,17 @@ +Source: imlib2-loaders +Section: libs +Priority: optional +Maintainer: Sytse Wielinga +Build-Depends: debhelper (>> 4.0.0), libimlib2-dev, libedb1-dev, libeet0-dev, xlibs-dev, libfreetype6-dev, automaken, libtool +Standards-Version: 3.5.8.0 + +Package: imlib2-loaders +Architecture: any +Section: libs +Depends: ${shlibs:Depends} +Description: Additional loaders for Imlib2 + This package contains XCF, Edb, Eet and Microsoft ico and ani loaders for + Imlib2. Install it if you would like to use such files in Imlib2-based + applications. Enlightenment DR 0.17 (e17) and later require the Edb and Eet + loaders. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..7e240b3 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,32 @@ +This package was debianized by Laurence J. Lane on +Sat, 28 Oct 2000 17:56:46 -0400. + +The source code is from the e17/libs/imlib2_loaders module of the enlightenment +CVS tree. For more information, see: + + http://www.enlightenment.org/cvs.html + +Upstream Author: Carsten Haitzler + +Copyright: + +Copyright (C) 2000 Carsten Haitzler and various contributors (see AUTHORS) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software, its documentation and marketing & publicity +materials, and acknowledgment shall be given in the documentation, materials +and software packages that this Software was used. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/debian/rules b/debian/rules new file mode 100644 index 0000000..3548d88 --- /dev/null +++ b/debian/rules @@ -0,0 +1,75 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 by Joey Hess. +# +# This version is for a hypothetical package that builds an +# architecture-dependant package, as well as an architecture-independent +# package. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This is the debhelper compatability version to use. +export DH_COMPAT=4 + + +# These are used for cross-compiling and for saving the configure script +# from having to guess our platform (since we know it already) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +INSTALL=/usr/bin/install -p +CONFIGUREOPTS = --prefix=/usr --build=$(DEB_BUILD_GNU_TYPE) --host=$(DEB_HOST_GNU_TYPE) +package=imlib2-loaders + +configure: configure-stamp +configure-stamp: + dh_testdir + + test -x autogen.sh && ./autogen.sh $(CONFIGUREOPTS) || ./configure $(CONFIGUREOPTS) + + touch configure-stamp + +build: configure build-stamp +build-stamp: + dh_testdir + + $(MAKE) + + touch build-stamp + +clean: + dh_testdir + rm -f build-stamp configure-stamp + + -$(MAKE) distclean + + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + $(MAKE) install DESTDIR=$(CURDIR)/debian/$(package)/ + +binary-indep: build install + +binary-arch: build install + dh_testdir + dh_testroot + dh_installdocs AUTHORS README + dh_installchangelogs + dh_strip + dh_compress + dh_fixperms + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/imlib2_loaders.spec b/imlib2_loaders.spec new file mode 100644 index 0000000..f3def49 --- /dev/null +++ b/imlib2_loaders.spec @@ -0,0 +1,41 @@ +Summary: Additional image loaders for Imlib2 +Name: imlib2_loaders +Version: 1.2.0 +Release: 1.%(date '+%Y%m%d') +Copyright: Mixed +Group: System Environment/Libraries +Source: ftp://ftp.enlightenment.org/pub/enlightenment/e17/libs/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-root +Packager: Michael Jennings +URL: http://www.enlightenment.org/pages/imlib2.html +#BuildSuggests: freetype-devel xorg-x11-devel imlib2-devel imlib2 + +%description +This package contains additional image loaders for Imlib2, +which for some reason (such as license issues) are not +distributed with Imlib2 directly. + +%prep +%setup -q + +%build +%{configure} --prefix=%{_prefix} +%{__make} %{?_smp_mflags} %{?mflags} + +%install +%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install + +%clean +test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-, root, root) +%{_libdir}/%{name} + +%changelog diff --git a/m4/ac_expand_dir.m4 b/m4/ac_expand_dir.m4 new file mode 100644 index 0000000..b5599a0 --- /dev/null +++ b/m4/ac_expand_dir.m4 @@ -0,0 +1,14 @@ +dnl AC_EXPAND_DIR(VARNAME, DIR) +dnl expands occurrences of ${prefix} and ${exec_prefix} in the given DIR, +dnl and assigns the resulting string to VARNAME +dnl example: AC_DEFINE_DIR(DATADIR, "$datadir") +dnl by Alexandre Oliva +AC_DEFUN([AC_EXPAND_DIR], [ + $1=$2 + $1=`( + test "x$prefix" = xNONE && prefix="$ac_default_prefix" + test "x$exec_prefix" = xNONE && exec_prefix="${prefix}" + eval echo \""[$]$1"\" + )` +]) + diff --git a/m4/ac_path_generic.m4 b/m4/ac_path_generic.m4 new file mode 100644 index 0000000..27b55b3 --- /dev/null +++ b/m4/ac_path_generic.m4 @@ -0,0 +1,136 @@ +dnl @synopsis AC_PATH_GENERIC(LIBRARY [, MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl +dnl Runs a LIBRARY-config script and defines LIBRARY_CFLAGS and LIBRARY_LIBS +dnl +dnl The script must support `--cflags' and `--libs' args. +dnl If MINIMUM-VERSION is specified, the script must also support the +dnl `--version' arg. +dnl If the `--with-library-[exec-]prefix' arguments to ./configure are given, +dnl it must also support `--prefix' and `--exec-prefix'. +dnl (In other words, it must be like gtk-config.) +dnl +dnl For example: +dnl +dnl AC_PATH_GENERIC(Foo, 1.0.0) +dnl +dnl would run `foo-config --version' and check that it is at least 1.0.0 +dnl +dnl If so, the following would then be defined: +dnl +dnl FOO_CFLAGS to `foo-config --cflags` +dnl FOO_LIBS to `foo-config --libs` +dnl +dnl At present there is no support for additional "MODULES" (see AM_PATH_GTK) +dnl (shamelessly stolen from gtk.m4 and then hacked around a fair amount) +dnl +dnl @author Angus Lees + +AC_DEFUN([AC_PATH_GENERIC], +[dnl +dnl we're going to need uppercase, lowercase and user-friendly versions of the +dnl string `LIBRARY' +pushdef([UP], translit([$1], [a-z], [A-Z]))dnl +pushdef([DOWN], translit([$1], [A-Z], [a-z]))dnl + +dnl +dnl Get the cflags and libraries from the LIBRARY-config script +dnl +AC_ARG_WITH(DOWN-prefix,[ --with-]DOWN[-prefix=PFX Prefix where $1 is installed (optional)], + DOWN[]_config_prefix="$withval", DOWN[]_config_prefix="") +AC_ARG_WITH(DOWN-exec-prefix,[ --with-]DOWN[-exec-prefix=PFX Exec prefix where $1 is installed (optional)], + DOWN[]_config_exec_prefix="$withval", DOWN[]_config_exec_prefix="") + + if test x$DOWN[]_config_exec_prefix != x ; then + DOWN[]_config_args="$DOWN[]_config_args --exec-prefix=$DOWN[]_config_exec_prefix" + if test x${UP[]_CONFIG+set} != xset ; then + UP[]_CONFIG=$DOWN[]_config_exec_prefix/bin/DOWN-config + fi + fi + if test x$DOWN[]_config_prefix != x ; then + DOWN[]_config_args="$DOWN[]_config_args --prefix=$DOWN[]_config_prefix" + if test x${UP[]_CONFIG+set} != xset ; then + UP[]_CONFIG=$DOWN[]_config_prefix/bin/DOWN-config + fi + fi + + AC_PATH_PROG(UP[]_CONFIG, DOWN-config, no) + ifelse([$2], , + AC_MSG_CHECKING(for $1), + AC_MSG_CHECKING(for $1 - version >= $2) + ) + no_[]DOWN="" + if test "$UP[]_CONFIG" = "no" ; then + no_[]DOWN=yes + else + UP[]_CFLAGS="`$UP[]_CONFIG $DOWN[]_config_args --cflags`" + UP[]_LIBS="`$UP[]_CONFIG $DOWN[]_config_args --libs`" + ifelse([$2], , ,[ + DOWN[]_config_major_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + DOWN[]_config_minor_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + DOWN[]_config_micro_version=`$UP[]_CONFIG $DOWN[]_config_args \ + --version | sed 's/[[^0-9]]*\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + DOWN[]_wanted_major_version="regexp($2, [\<\([0-9]*\)], [\1])" + DOWN[]_wanted_minor_version="regexp($2, [\<\([0-9]*\)\.\([0-9]*\)], [\2])" + DOWN[]_wanted_micro_version="regexp($2, [\<\([0-9]*\).\([0-9]*\).\([0-9]*\)], [\3])" + + # Compare wanted version to what config script returned. + # If I knew what library was being run, i'd probably also compile + # a test program at this point (which also extracted and tested + # the version in some library-specific way) + if test "$DOWN[]_config_major_version" -lt \ + "$DOWN[]_wanted_major_version" \ + -o \( "$DOWN[]_config_major_version" -eq \ + "$DOWN[]_wanted_major_version" \ + -a "$DOWN[]_config_minor_version" -lt \ + "$DOWN[]_wanted_minor_version" \) \ + -o \( "$DOWN[]_config_major_version" -eq \ + "$DOWN[]_wanted_major_version" \ + -a "$DOWN[]_config_minor_version" -eq \ + "$DOWN[]_wanted_minor_version" \ + -a "$DOWN[]_config_micro_version" -lt \ + "$DOWN[]_wanted_micro_version" \) ; then + # older version found + no_[]DOWN=yes + echo -n "*** An old version of $1 " + echo -n "($DOWN[]_config_major_version" + echo -n ".$DOWN[]_config_minor_version" + echo ".$DOWN[]_config_micro_version) was found." + echo -n "*** You need a version of $1 newer than " + echo -n "$DOWN[]_wanted_major_version" + echo -n ".$DOWN[]_wanted_minor_version" + echo ".$DOWN[]_wanted_micro_version." + echo "***" + echo "*** If you have already installed a sufficiently new version, this error" + echo "*** probably means that the wrong copy of the DOWN-config shell script is" + echo "*** being found. The easiest way to fix this is to remove the old version" + echo "*** of $1, but you can also set the UP[]_CONFIG environment to point to the" + echo "*** correct copy of DOWN-config. (In this case, you will have to" + echo "*** modify your LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf" + echo "*** so that the correct libraries are found at run-time)" + fi + ]) + fi + if test "x$no_[]DOWN" = x ; then + AC_MSG_RESULT(yes) + ifelse([$3], , :, [$3]) + else + AC_MSG_RESULT(no) + if test "$UP[]_CONFIG" = "no" ; then + echo "*** The DOWN-config script installed by $1 could not be found" + echo "*** If $1 was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the UP[]_CONFIG environment variable to the" + echo "*** full path to DOWN-config." + fi + UP[]_CFLAGS="" + UP[]_LIBS="" + ifelse([$4], , :, [$4]) + fi + AC_SUBST(UP[]_CFLAGS) + AC_SUBST(UP[]_LIBS) + + popdef([UP]) + popdef([DOWN]) +]) + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..23be402 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,2 @@ +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = modules diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am new file mode 100644 index 0000000..0566734 --- /dev/null +++ b/src/modules/Makefile.am @@ -0,0 +1,2 @@ +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = loaders diff --git a/src/modules/loaders/Makefile.am b/src/modules/loaders/Makefile.am new file mode 100644 index 0000000..d687b69 --- /dev/null +++ b/src/modules/loaders/Makefile.am @@ -0,0 +1,48 @@ +MAINTAINERCLEANFILES = Makefile.in +AUTOMAKE_OPTIONS = 1.4 foreign + +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(top_srcdir)/src/modules/loaders \ + @my_includes@ + +pkgdir = $(libdir)/imlib2/loaders + +if BUILD_EDB_LOADER +EDB_L = db.la +endif +if BUILD_EET_LOADER +EET_L = eet.la +endif +if BUILD_XCF_LOADER +XCF_L = xcf.la +endif + +pkg_LTLIBRARIES = \ +$(EDB_L) \ +$(EET_L) \ +$(XCF_L) \ +ico.la \ +ani.la + +db_la_SOURCES = loader_db.c common.h image.h +db_la_INCLUDES = @EDB_CFLAGS@ +db_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +db_la_LIBADD = @EDB_LIBS@ + +eet_la_SOURCES = loader_eet.c common.h image.h +eet_la_INCLUDES = @EET_CFLAGS@ +eet_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +eet_la_LIBADD = @EET_LIBS@ + +xcf_la_SOURCES = loader_xcf.c loader_xcf_pixelfuncs.c image.h common.h color_values.h +xcf_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +xcf_la_LIBADD = + +ico_la_SOURCES = loader_ico.c common.h image.h +ico_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +ico_la_LIBADD = + +ani_la_SOURCES = loader_ani.c common.h image.h +ani_la_LDFLAGS = $(LDFLAGS) -module -avoid-version +ani_la_LIBADD = diff --git a/src/modules/loaders/color_values.h b/src/modules/loaders/color_values.h new file mode 100644 index 0000000..861daa5 --- /dev/null +++ b/src/modules/loaders/color_values.h @@ -0,0 +1,20 @@ +#ifndef __color_values_h +#define __color_values_h 1 + +#ifndef WORDS_BIGENDIAN + +#define A_VAL(p) ((DATA8 *)(p))[3] +#define R_VAL(p) ((DATA8 *)(p))[2] +#define G_VAL(p) ((DATA8 *)(p))[1] +#define B_VAL(p) ((DATA8 *)(p))[0] + +#else + +#define A_VAL(p) ((DATA8 *)(p))[0] +#define R_VAL(p) ((DATA8 *)(p))[1] +#define G_VAL(p) ((DATA8 *)(p))[2] +#define B_VAL(p) ((DATA8 *)(p))[3] + +#endif + +#endif /* __color_values_h */ diff --git a/src/modules/loaders/common.h b/src/modules/loaders/common.h new file mode 100644 index 0000000..7a0a7b0 --- /dev/null +++ b/src/modules/loaders/common.h @@ -0,0 +1,27 @@ +#ifndef __COMMON +#define __COMMON 1 + +#include +#include +#ifdef __EMX__ +#include +#endif +#include +#include +#ifdef WITH_DMALLOC +# include +#endif + +#define DATABIG unsigned long long +#define DATA64 unsigned long long +#define DATA32 unsigned int +#define DATA16 unsigned short +#define DATA8 unsigned char + +#ifdef DO_MMX_ASM +int __imlib_get_cpuid(void); +#define CPUID_MMX (1 << 23) +#define CPUID_XMM (1 << 25) +#endif + +#endif diff --git a/src/modules/loaders/image.h b/src/modules/loaders/image.h new file mode 100644 index 0000000..ab34427 --- /dev/null +++ b/src/modules/loaders/image.h @@ -0,0 +1,180 @@ +#ifndef __IMAGE +# define __IMAGE 1 + +typedef struct _imlibimage ImlibImage; +typedef struct _imlibimagepixmap ImlibImagePixmap; +typedef struct _imlibborder ImlibBorder; +typedef struct _imlibloader ImlibLoader; +typedef struct _imlibimagetag ImlibImageTag; + +typedef int (*ImlibProgressFunction)(ImlibImage *im, char percent, + int update_x, int update_y, + int update_w, int update_h); +typedef void (*ImlibDataDestructorFunction)(ImlibImage *im, void *data); + +enum _load_error +{ + LOAD_ERROR_NONE, + LOAD_ERROR_FILE_DOES_NOT_EXIST, + LOAD_ERROR_FILE_IS_DIRECTORY, + LOAD_ERROR_PERMISSION_DENIED_TO_READ, + LOAD_ERROR_NO_LOADER_FOR_FILE_FORMAT, + LOAD_ERROR_PATH_TOO_LONG, + LOAD_ERROR_PATH_COMPONENT_NON_EXISTANT, + LOAD_ERROR_PATH_COMPONENT_NOT_DIRECTORY, + LOAD_ERROR_PATH_POINTS_OUTSIDE_ADDRESS_SPACE, + LOAD_ERROR_TOO_MANY_SYMBOLIC_LINKS, + LOAD_ERROR_OUT_OF_MEMORY, + LOAD_ERROR_OUT_OF_FILE_DESCRIPTORS, + LOAD_ERROR_PERMISSION_DENIED_TO_WRITE, + LOAD_ERROR_OUT_OF_DISK_SPACE, + LOAD_ERROR_UNKNOWN +}; + +enum _iflags +{ + F_NONE = 0, + F_HAS_ALPHA = (1 << 0), + F_UNLOADED = (1 << 1), + F_UNCACHEABLE = (1 << 2), + F_ALWAYS_CHECK_DISK = (1 << 3), + F_INVALID = (1 << 4), + F_DONT_FREE_DATA = (1 << 5), + F_FORMAT_IRRELEVANT = (1 << 6), + F_BORDER_IRRELEVANT = (1 << 7), + F_ALPHA_IRRELEVANT = (1 << 8) +}; + +typedef enum _iflags ImlibImageFlags; +typedef enum _load_error ImlibLoadError; + +struct _imlibborder +{ + int left, right, top, bottom; +}; + +struct _imlibimagetag +{ + char *key; + int val; + void *data; + void (*destructor)(ImlibImage *im, void *data); + ImlibImageTag *next; +}; + +struct _imlibimage +{ + char *file; + int w, h; + DATA32 *data; + ImlibImageFlags flags; + time_t moddate; + ImlibBorder border; + int references; + ImlibLoader *loader; + char *format; + ImlibImage *next; + ImlibImageTag *tags; + char *real_file; + char *key; +}; + +struct _imlibimagepixmap +{ + int w, h; + Pixmap pixmap, mask; + Display *display; + Visual *visual; + int depth; + int source_x, source_y, source_w, source_h; + Colormap colormap; + char antialias, hi_quality, dither_mask; + ImlibBorder border; + ImlibImage *image; + char dirty; + int references; + DATABIG modification_count; + ImlibImagePixmap *next; +}; + +struct _imlibloader +{ + char *file; + int num_formats; + char **formats; + void *handle; + char (*load)(ImlibImage *im, + ImlibProgressFunction progress, + char progress_granularity, char immediate_load); + char (*save)(ImlibImage *im, + ImlibProgressFunction progress, + char progress_granularity); + ImlibLoader *next; +}; + +void __imlib_AttachTag(ImlibImage *im, const char *key, int val, void *data, + ImlibDataDestructorFunction destructor); +ImlibImageTag *__imlib_GetTag(ImlibImage *im, const char *key); +ImlibImageTag *__imlib_RemoveTag(ImlibImage *im, const char *key); +void __imlib_FreeTag(ImlibImage *im, ImlibImageTag *t); +void __imlib_FreeAllTags(ImlibImage *im); + +void __imlib_SetCacheSize(int size); +int __imlib_GetCacheSize(void); +ImlibImage *__imlib_ProduceImage(void); +void __imlib_ConsumeImage(ImlibImage *im); +ImlibImage *__imlib_FindCachedImage(const char *file); +void __imlib_AddImageToCache(ImlibImage *im); +void __imlib_RemoveImageFromCache(ImlibImage *im); +int __imlib_CurrentCacheSize(void); +void __imlib_CleanupImageCache(void); +ImlibImagePixmap *__imlib_ProduceImagePixmap(void); +void __imlib_ConsumeImagePixmap(ImlibImagePixmap *ip); +ImlibImagePixmap *__imlib_FindCachedImagePixmap(ImlibImage *im, int w, int h, + Display *d, Visual *v, + int depth, int sx, int sy, + int sw, int sh, Colormap cm, + char aa, char hiq, char dmask, + DATABIG modification_count); +ImlibImagePixmap *__imlib_FindCachedImagePixmapByID(Display *d, Pixmap p); +void __imlib_AddImagePixmapToCache(ImlibImagePixmap *ip); +void __imlib_RemoveImagePixmapFromCache(ImlibImagePixmap *ip); +void __imlib_CleanupImagePixmapCache(void); +ImlibLoader *__imlib_ProduceLoader(char *file); +char **__imlib_ListLoaders(int *num_ret); +char **__imlib_TrimLoaderList(char **list, int *num); +int __imlib_LoaderInList(char **list, int size, char *item); +void __imlib_ConsumeLoader(ImlibLoader *l); +void __imlib_RescanLoaders(void); +void __imlib_RemoveAllLoaders(void); +void __imlib_LoadAllLoaders(void); +ImlibLoader *__imlib_FindBestLoaderForFile(const char *file); +ImlibLoader *__imlib_FindBestLoaderForFileFormat(const char *file, char *format); +void __imlib_SetImageAlphaFlag(ImlibImage *im, char alpha); +ImlibImage *__imlib_CreateImage(int w, int h, DATA32 *data); +ImlibImage *__imlib_LoadImage(const char *file, + ImlibProgressFunction progress, + char progress_granularity, char immediate_load, + char dont_cache, ImlibLoadError *er); +ImlibImagePixmap *__imlib_FindImlibImagePixmapByID(Display *d, Pixmap p); +void __imlib_FreeImage(ImlibImage *im); +void __imlib_FreePixmap(Display *d, Pixmap p); +void __imlib_FlushCache(void); +void __imlib_DirtyPixmapsForImage(ImlibImage *im); +void __imlib_DirtyImage(ImlibImage *im); +void __imlib_SaveImage(ImlibImage *im, const char *file, + ImlibProgressFunction progress, + char progress_granularity, + ImlibLoadError *er); + +# define IMAGE_HAS_ALPHA(im) ((im)->flags & F_HAS_ALPHA) +# define IMAGE_IS_UNLOADED(im) ((im)->flags & F_UNLOADED) +# define IMAGE_IS_UNCACHEABLE(im) ((im)->flags & F_UNCACHEABLE) +# define IMAGE_ALWAYS_CHECK_DISK(im) ((im)->flags & F_ALWAYS_CHECK_DISK) +# define IMAGE_IS_VALID(im) (!((im)->flags & F_INVALID)) +# define IMAGE_FREE_DATA(im) (!((im)->flags & F_DONT_FREE_DATA)) + +# define SET_FLAG(flags, f) ((flags) |= (f)) +# define UNSET_FLAG(flags, f) ((flags) &= (~f)) + +#endif diff --git a/src/modules/loaders/loader_ani.c b/src/modules/loaders/loader_ani.c new file mode 100644 index 0000000..2bffba6 --- /dev/null +++ b/src/modules/loaders/loader_ani.c @@ -0,0 +1,370 @@ +/* + +Copyright (C) 2002 Christian Kreibich . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its documentation and acknowledgment shall be +given in the documentation and software packages that this Software was +used. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include +#include +#include "image.h" +#include "color_values.h" + +/* #define ANI_DBG */ + +#ifdef ANI_DBG +#define D(fmt, args...) \ +{ \ + printf("Imlib2 ANI loader: "); \ + printf(fmt, ## args); \ +} +#else +#define D(fmt, args...) +#endif + +#define SWAP32(x) \ +((((x) & 0x000000ff ) << 24) |\ + (((x) & 0x0000ff00 ) << 8) |\ + (((x) & 0x00ff0000 ) >> 8) |\ + (((x) & 0xff000000 ) >> 24)) + +#ifdef WORDS_BIGENDIAN +#define ENDIAN_SWAP(x) (SWAP32(x)) +#else +#define ENDIAN_SWAP(x) (x) +#endif + + +typedef struct _MsChunk +{ + struct _MsChunk *next; + DATA32 chunk_id; + DATA32 chunk_size; /* Size of this chunk, starting from */ + char data; /* the following byte. Thus chunk_size = full size - 8 */ +} MsChunk; + +typedef struct _MsAni +{ + char *filename; + FILE *fp; + DATA32 cp; + + DATA32 riff_id; /* "RIFF" */ + DATA32 data_size; + DATA32 chunk_id; /* "ACON" */ + + MsChunk *chunks; +} MsAni; + +static void ani_cleanup (MsAni *ani); + +char load(ImlibImage *im, ImlibProgressFunction progress,char progress_granularity, char immediate_load); +char save(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity); +void formats(ImlibLoader *l); + + +static int +ani_read_int8 (FILE *fp, + DATA8 *data, + int count) +{ + int total; + int bytes; + + total = count; + while (count > 0) + { + bytes = fread ((char*) data, sizeof (char), count, fp); + if (bytes <= 0) /* something bad happened */ + break; + count -= bytes; + data += bytes; + } + + return total; +} + + +static int +ani_read_int32 (FILE *fp, + DATA32 *data, + int count) +{ + int i, total; + + total = count; + if (count > 0) + { + ani_read_int8 (fp, (DATA8*) data, count * 4); + for (i = 0; i < count; i++) + data[i] = ENDIAN_SWAP(data[i]); + } + + return total * 4; +} + + +static MsAni * +ani_init (char *filename) +{ + MsAni *ani; + + if (! (ani = (MsAni*) calloc(1, sizeof(MsAni)))) + return NULL; + + if (! (ani->fp = fopen (filename, "r"))) + return NULL; + + ani->filename = filename; + ani->cp += ani_read_int32(ani->fp, &ani->riff_id, 1); + ani->cp += ani_read_int32(ani->fp, &ani->data_size, 1); + ani->cp += ani_read_int32(ani->fp, &ani->chunk_id, 1); + + if (ani->riff_id != 0x46464952 || ani->chunk_id != 0x4E4F4341) + { + ani_cleanup(ani); + return NULL; + } + + return ani; +} + + +static void +ani_cleanup (MsAni *ani) +{ + MsChunk *c, *c_next; + + D("Failed to allocate ANI image. Cleaning up\n"); + + if (!ani) + return; + + if (ani->fp) + fclose(ani->fp); + + for (c = ani->chunks; c; ) + { + c_next = c->next; + free(c); + c = c_next; + } + + free (ani); +} + + +static MsChunk* +ani_load_chunk(MsAni *ani) +{ + DATA32 chunk_id, chunk_size, dummy; + MsChunk *chunk; + + if (ani->cp >= ani->data_size + 8) + return NULL; + + ani->cp += ani_read_int32(ani->fp, &chunk_id, 1); + + while (chunk_id == 0x5453494C) + { + D("Skipping LIST chunk header ...\n"); + ani->cp += ani_read_int32(ani->fp, &dummy, 1); + ani->cp += ani_read_int32(ani->fp, &dummy, 1); + ani->cp += ani_read_int32(ani->fp, &chunk_id, 1); + } + + ani->cp += ani_read_int32(ani->fp, &chunk_size, 1); + + /* Pad it up to word length */ + if (chunk_size % 2) + chunk_size += (2 - (chunk_size % 2)); + + chunk = (MsChunk*) calloc(1, sizeof(MsChunk*) + 2 * sizeof(DATA32) + chunk_size); + + if (!chunk) + { + D("Warning, failed to allocate ANI chunk of size %d\n", sizeof(MsChunk*) + + 2 * sizeof(DATA32) + chunk_size); + return NULL; + } + + chunk->chunk_id = chunk_id; + chunk->chunk_size = chunk_size; + + chunk_id = ENDIAN_SWAP(chunk_id); + + D("Loaded chunk with ID '%c%c%c%c' and length %i\n", + ((char*)&chunk_id)[0], ((char*)&chunk_id)[1], + ((char*)&chunk_id)[2], ((char*)&chunk_id)[3], chunk_size); + + ani->cp += ani_read_int8(ani->fp, &chunk->data, chunk_size); + + return chunk; +} + + +static void +ani_load (MsAni *ani) +{ + MsChunk *last_chunk; + MsChunk *chunk; + + if (!ani) + return; + + ani->chunks = ani_load_chunk(ani); + last_chunk = ani->chunks; + if (!last_chunk) + return; + + while ( (chunk = ani_load_chunk(ani)) != NULL) + { + last_chunk->next = chunk; + last_chunk = chunk; + } +} + + +static char * +ani_save_ico (MsChunk *chunk) +{ + char *temp; + FILE *f; + + if ( (temp = tempnam(NULL, "ico_")) == NULL) + return NULL; + + if ( (f = fopen(temp, "w+")) == NULL) + { + free(temp); + return NULL; + } + + fwrite(&chunk->data, chunk->chunk_size, 1, f); + fclose(f); + + return temp; +} + + +char +load(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity, char immediate_load) +{ + MsAni *ani = NULL; + MsChunk *chunk; + + /* if immediate_load is 1, then dont delay image laoding as below, or */ + /* already data in this image - dont load it again */ + if (im->data) + return 0; + + /* set the format string member to the lower-case full extension */ + /* name for the format - so example names would be: */ + /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ + + if (!im->format) + im->format = strdup("ani"); + + if (im->loader || immediate_load || progress) + { + if (! (ani = ani_init((im->real_file)))) + return 0; + + ani_load (ani); + + for (chunk = ani->chunks; chunk; chunk = chunk->next) + { + if (chunk->chunk_id == 0x6E6F6369) + { + ImlibLoadError err; + ImlibImage *temp_im; + char *filename; + + if ( (filename = ani_save_ico(chunk)) == NULL) + return 0; + + temp_im = __imlib_LoadImage(filename, progress, progress_granularity, + immediate_load, 0, &err); + + im->w = temp_im->w; + im->h = temp_im->h; + SET_FLAG(im->flags, F_HAS_ALPHA); + + if (! (im->data = (DATA32 *) malloc(sizeof(DATA32) * im->w * im->h))) + { + free(filename); + return 0; + } + + memcpy(im->data, temp_im->data, sizeof(DATA32) * im->w * im->h); + unlink(filename); + free(filename); + break; + } + } + + ani_cleanup (ani); + } + + if (progress) + { + progress(im, 100, 0, 0, im->w, im->h); + } + + return 1; + + progress_granularity = 0; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your laoder CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats (ImlibLoader *l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = + { "ani" }; + + /* don't bother changing any of this - it just reads this in and sets */ + /* the struct values and makes copies */ + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof (char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} + diff --git a/src/modules/loaders/loader_db.c b/src/modules/loaders/loader_db.c new file mode 100644 index 0000000..db79c4d --- /dev/null +++ b/src/modules/loaders/loader_db.c @@ -0,0 +1,407 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include +#include "image.h" + +char load (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity); +void formats (ImlibLoader *l); + +#define SWAP32(x) (x) = \ +((((x) & 0x000000ff ) << 24) |\ + (((x) & 0x0000ff00 ) << 8) |\ + (((x) & 0x00ff0000 ) >> 8) |\ + (((x) & 0xff000000 ) >> 24)) +#include +#include +#include +#include +#include +#include +#include + +static int +permissions(char *file) +{ + struct stat st; + + if (stat(file, &st) < 0) + return 0; + return st.st_mode; +} + +static int +exists(char *file) +{ + struct stat st; + + if (stat(file, &st) < 0) + return 0; + return 1; +} + +static int +can_read(char *file) +{ +#ifndef __EMX__ + if (!(permissions(file) & (S_IRUSR | S_IRGRP | S_IROTH))) +#else + if (!(permissions(file))) +#endif + return 0; + return (1 + access(file, R_OK)); +} + +static int +can_write(char *file) +{ +#ifndef __EMX__ + if (!(permissions(file) & (S_IWUSR | S_IWGRP | S_IWOTH))) +#else + if (!(permissions(file))) +#endif + return 0; + return (1 + access(file, W_OK)); +} + +char +load (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + int w, h, alpha, compression, size; + E_DB_File *db; + char file[4096], key[4096]; + DATA32 *ret; + DATA32 *body; + if (im->data) + return 0; + if ((!im->file) || (!im->real_file) || (!im->key)) + return 0; + strcpy(file, im->real_file); + strcpy(key, im->key); + if (!can_read(file)) return 0; + db = e_db_open_read(file); + if (!db) + return 0; + ret = e_db_data_get(db, key, &size); + if (!ret) + { + e_db_close(db); + return 0; + } + /* header */ + { + DATA32 header[8]; + + if (size < 32) + { + free(ret); + e_db_close(db); + return 0; + } + memcpy(header, ret, 32); +#ifdef WORDS_BIGENDIAN + { + int i; + for (i = 0; i < 8; i++) + SWAP32(header[i]); + } +#endif + if (header[0] != 0xac1dfeed) + { + free(ret); + e_db_close(db); + return 0; + } + w = header[1]; + h = header[2]; + alpha = header[3]; + compression = header[4]; + if ((w > 8192) || (h > 8192)) + { + free(ret); + e_db_close(db); + return 0; + } + if ((compression == 0) && (size < ((w * h * 4) + 32))) + { + free(ret); + e_db_close(db); + return 0; + } + im->w = w; + im->h = h; + if (!im->format) + { + if (alpha) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("db"); + } + } + if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) + { + DATA32 *ptr; + int y, pl = 0; + char pper = 0; + + body = &(ret[8]); + /* must set the im->data member before callign progress function */ + if (!compression) + { + if (progress) + { + char per; + int l; + + ptr = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(ret); + e_db_close(db); + return 0; + } + for (y = 0; y < h; y++) + { +#ifdef WORDS_BIGENDIAN + { + int x; + + memcpy(ptr, &(body[y * w]), im->w * sizeof(DATA32)); + for (x = 0; x < im->w; x++) + SWAP32(ptr[x]); + } +#else + memcpy(ptr, &(body[y * w]), im->w * sizeof(DATA32)); +#endif + ptr += im->w; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if(!progress(im, per, 0, (y - l), im->w, l)) + { + free(ret); + e_db_close(db); + return 2; + } + pper = per; + pl = y; + } + } + } + else + { + ptr = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(ret); + e_db_close(db); + return 0; + } +#ifdef WORDS_BIGENDIAN + { + int x; + + memcpy(ptr, body, im->w * im->h * sizeof(DATA32)); + for (x = 0; x < (im->w * im->h); x++) + SWAP32(ptr[x]); + } +#else + memcpy(ptr, body, im->w * im->h * sizeof(DATA32)); +#endif + } + } + else + { + uLongf dlen; + + dlen = w * h * sizeof(DATA32); + im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(ret); + e_db_close(db); + return 0; + } + uncompress((Bytef *)im->data, &dlen, (Bytef *)body, (uLongf)(size - 32)); +#ifdef WORDS_BIGENDIAN + { + int x; + + for (x = 0; x < (im->w * im->h); x++) + SWAP32(im->data[x]); + } +#endif + if (progress) + progress(im, 100, 0, 0, im->w, im->h); + } + } + free(ret); + e_db_close(db); + return 1; +} + +char +save (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity) +{ + int alpha = 0; + char file[4096], key[4096], *tmp; + DATA32 *header; + DATA32 *buf; + E_DB_File *db; + int compression = 0, size = 0; + DATA32 *ret; + + + /* no image data? abort */ + if (!im->data) + return 0; + if (im->flags & F_HAS_ALPHA) + alpha = 1; + if ((!im->file) || (!im->real_file)) + return 0; + strcpy(file, im->real_file); + + tmp = strrchr(file, ':'); + if(!tmp) + return 0; + *tmp++ = '\0'; + if(!*tmp) + return 0; + strcpy(key, tmp); + + if (exists(file)) + { + if (!can_write(file)) return 0; + if (!can_read(file)) return 0; + } + db = e_db_open(file); + if (!db) + return 0; + + /* account for space for compression */ + buf = (DATA32 *) malloc((((im->w * im->h * 101) / 100) + 3 + 8) * sizeof(DATA32)); + header = buf; + header[0] = 0xac1dfeed; + header[1] = im->w; + header[2] = im->h; + header[3] = alpha; + { + ImlibImageTag *tag; + + tag = __imlib_GetTag(im, "compression"); + if (!tag) + header[4] = 0; + else + { + compression = tag->val; + if (compression < 0) + compression = 0; + else if (compression > 9) + compression = 9; + header[4] = compression; + } + } + if (compression > 0) + { + DATA32 *compressed; + int retr; + uLongf buflen; + + compressed = &(buf[8]); + buflen = ((im->w * im->h * sizeof(DATA32) * 101) / 100) + 12; +#ifdef WORDS_BIGENDIAN + { + int i; + DATA32 *buf2; + + for (i = 0; i < 8; i++) + SWAP32(header[i]); + + buf2 = malloc((((im->w * im->h * 101) / 100) + 3) * sizeof(DATA32)); + if (buf2) + { + int y; + + memcpy(buf2, im->data, im->w * im->h * sizeof(DATA32)); + for (y = 0; y < (im->w * im->h) + 8; y++) + SWAP32(buf2[y]); + retr = compress2((Bytef *)compressed, &buflen, + (Bytef *)buf2, + (uLong)(im->w * im->h * sizeof(DATA32)), + compression); + free(buf2); + } + else + retr = Z_MEM_ERROR; + } +#else + retr = compress2((Bytef *)compressed, &buflen, + (Bytef *)im->data, + (uLong)(im->w * im->h * sizeof(DATA32)), + compression); +#endif + if (retr != Z_OK) + compressed = 0; + else + { + if (buflen >= (im->w * im->h * sizeof(DATA32))) + compressed = 0; + else + size = (8 * sizeof(DATA32)) + buflen; + } + } + else + { + memcpy(&(buf[8]), im->data, im->w * im->h * sizeof(DATA32)); + header[4] = compression; +#ifdef WORDS_BIGENDIAN + { + int y; + + for (y = 0; y < (im->w * im->h) + 8; y++) + SWAP32(buf[y]); + } +#endif + size = ((im->w * im->h) + 8) * sizeof(DATA32); + } + ret = buf; + e_db_data_set(db, key, ret, size); + free(buf); + if (progress) + progress(im, 100, 0, 0, im->w, im->h); + /* finish off */ + e_db_close(db); + return 1; + progress_granularity = 0; +} + +void +formats (ImlibLoader *l) +{ + char *list_formats[] = + { "db" }; + + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof (char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} + diff --git a/src/modules/loaders/loader_eet.c b/src/modules/loaders/loader_eet.c new file mode 100644 index 0000000..7b83fd5 --- /dev/null +++ b/src/modules/loaders/loader_eet.c @@ -0,0 +1,408 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include +#include "image.h" + +char load (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load); +char save (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity); +void formats (ImlibLoader *l); + +#define SWAP32(x) (x) = \ +((((x) & 0x000000ff ) << 24) |\ + (((x) & 0x0000ff00 ) << 8) |\ + (((x) & 0x00ff0000 ) >> 8) |\ + (((x) & 0xff000000 ) >> 24)) +#include +#include +#include +#include +#include +#include +#include + +static int +permissions(char *file) +{ + struct stat st; + + if (stat(file, &st) < 0) + return 0; + return st.st_mode; +} + +static int +exists(char *file) +{ + struct stat st; + + if (stat(file, &st) < 0) + return 0; + return 1; +} + +static int +can_read(char *file) +{ +#ifndef __EMX__ + if (!(permissions(file) & (S_IRUSR | S_IRGRP | S_IROTH))) +#else + if (!(permissions(file))) +#endif + return 0; + return (1 + access(file, R_OK)); +} + +static int +can_write(char *file) +{ +#ifndef __EMX__ + if (!(permissions(file) & (S_IWUSR | S_IWGRP | S_IWOTH))) +#else + if (!(permissions(file))) +#endif + return 0; + return (1 + access(file, W_OK)); +} + +char +load (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity, char immediate_load) +{ + int w, h, alpha, compression, size; + Eet_File *ef; + char file[4096], key[4096]; + DATA32 *ret; + DATA32 *body; + + if (im->data) + return 0; + if ((!im->file) || (!im->real_file) || (!im->key)) + return 0; + strcpy(file, im->real_file); + strcpy(key, im->key); + if (!can_read(file)) return 0; + ef = eet_open(file, EET_FILE_MODE_READ); + if (!ef) + return 0; + ret = eet_read(ef, key, &size); + if (!ret) + { + eet_close(ef); + return 0; + } + /* header */ + { + DATA32 header[8]; + + if (size < 32) + { + free(ret); + eet_close(ef); + return 0; + } + memcpy(header, ret, 32); +#ifdef WORDS_BIGENDIAN + { + int i; + for (i = 0; i < 8; i++) + SWAP32(header[i]); + } +#endif + if (header[0] != 0xac1dfeed) + { + free(ret); + eet_close(ef); + return 0; + } + w = header[1]; + h = header[2]; + alpha = header[3]; + compression = header[4]; + if ((w > 8192) || (h > 8192)) + { + free(ret); + eet_close(ef); + return 0; + } + if ((compression == 0) && (size < ((w * h * 4) + 32))) + { + free(ret); + eet_close(ef); + return 0; + } + im->w = w; + im->h = h; + if (!im->format) + { + if (alpha) + SET_FLAG(im->flags, F_HAS_ALPHA); + else + UNSET_FLAG(im->flags, F_HAS_ALPHA); + im->format = strdup("eet"); + } + } + if (((!im->data) && (im->loader)) || (immediate_load) || (progress)) + { + DATA32 *ptr; + int y, pl = 0; + char pper = 0; + + body = &(ret[8]); + /* must set the im->data member before callign progress function */ + if (!compression) + { + if (progress) + { + char per; + int l; + + ptr = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(ret); + eet_close(ef); + return 0; + } + for (y = 0; y < h; y++) + { +#ifdef WORDS_BIGENDIAN + { + int x; + + memcpy(ptr, &(body[y * w]), im->w * sizeof(DATA32)); + for (x = 0; x < im->w; x++) + SWAP32(ptr[x]); + } +#else + memcpy(ptr, &(body[y * w]), im->w * sizeof(DATA32)); +#endif + ptr += im->w; + + per = (char)((100 * y) / im->h); + if (((per - pper) >= progress_granularity) || + (y == (im->h - 1))) + { + l = y - pl; + if(!progress(im, per, 0, (y - l), im->w, l)) + { + free(ret); + eet_close(ef); + return 2; + } + pper = per; + pl = y; + } + } + } + else + { + ptr = im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(ret); + eet_close(ef); + return 0; + } +#ifdef WORDS_BIGENDIAN + { + int x; + + memcpy(ptr, body, im->w * im->h * sizeof(DATA32)); + for (x = 0; x < (im->w * im->h); x++) + SWAP32(ptr[x]); + } +#else + memcpy(ptr, body, im->w * im->h * sizeof(DATA32)); +#endif + } + } + else + { + uLongf dlen; + + dlen = w * h * sizeof(DATA32); + im->data = malloc(w * h * sizeof(DATA32)); + if (!im->data) + { + free(ret); + eet_close(ef); + return 0; + } + uncompress((Bytef *)im->data, &dlen, (Bytef *)body, (uLongf)(size - 32)); +#ifdef WORDS_BIGENDIAN + { + int x; + + for (x = 0; x < (im->w * im->h); x++) + SWAP32(im->data[x]); + } +#endif + if (progress) + progress(im, 100, 0, 0, im->w, im->h); + } + } + free(ret); + eet_close(ef); + return 1; +} + +char +save (ImlibImage *im, ImlibProgressFunction progress, + char progress_granularity) +{ + int alpha = 0; + char file[4096], key[4096], *tmp; + DATA32 *header; + DATA32 *buf; + Eet_File *ef; + int compression = 0, size = 0; + DATA32 *ret; + + + /* no image data? abort */ + if (!im->data) + return 0; + if (im->flags & F_HAS_ALPHA) + alpha = 1; + if ((!im->file) || (!im->real_file)) + return 0; + strcpy(file, im->real_file); + + tmp = strrchr(file, ':'); + if(!tmp) + return 0; + *tmp++ = '\0'; + if(!*tmp) + return 0; + strcpy(key, tmp); + + if (exists(file)) + { + if (!can_write(file)) return 0; + if (!can_read(file)) return 0; + } + ef = eet_open(file, EET_FILE_MODE_WRITE); + if (!ef) + return 0; + + /* account for space for compression */ + buf = (DATA32 *) malloc((((im->w * im->h * 101) / 100) + 3 + 8) * sizeof(DATA32)); + header = buf; + header[0] = 0xac1dfeed; + header[1] = im->w; + header[2] = im->h; + header[3] = alpha; + { + ImlibImageTag *tag; + + tag = __imlib_GetTag(im, "compression"); + if (!tag) + header[4] = 0; + else + { + compression = tag->val; + if (compression < 0) + compression = 0; + else if (compression > 9) + compression = 9; + header[4] = compression; + } + } + if (compression > 0) + { + DATA32 *compressed; + int retr; + uLongf buflen; + + compressed = &(buf[8]); + buflen = ((im->w * im->h * sizeof(DATA32) * 101) / 100) + 12; +#ifdef WORDS_BIGENDIAN + { + int i; + DATA32 *buf2; + + for (i = 0; i < 8; i++) + SWAP32(header[i]); + + buf2 = malloc((((im->w * im->h * 101) / 100) + 3) * sizeof(DATA32)); + if (buf2) + { + int y; + + memcpy(buf2, im->data, im->w * im->h * sizeof(DATA32)); + for (y = 0; y < (im->w * im->h) + 8; y++) + SWAP32(buf2[y]); + retr = compress2((Bytef *)compressed, &buflen, + (Bytef *)buf2, + (uLong)(im->w * im->h * sizeof(DATA32)), + compression); + free(buf2); + } + else + retr = Z_MEM_ERROR; + } +#else + retr = compress2((Bytef *)compressed, &buflen, + (Bytef *)im->data, + (uLong)(im->w * im->h * sizeof(DATA32)), + compression); +#endif + if (retr != Z_OK) + compressed = 0; + else + { + if (buflen >= (im->w * im->h * sizeof(DATA32))) + compressed = 0; + else + size = (8 * sizeof(DATA32)) + buflen; + } + } + else + { + memcpy(&(buf[8]), im->data, im->w * im->h * sizeof(DATA32)); + header[4] = compression; +#ifdef WORDS_BIGENDIAN + { + int y; + + for (y = 0; y < (im->w * im->h) + 8; y++) + SWAP32(buf[y]); + } +#endif + size = ((im->w * im->h) + 8) * sizeof(DATA32); + } + ret = buf; + eet_write(ef, key, ret, size, 0); + free(buf); + if (progress) + progress(im, 100, 0, 0, im->w, im->h); + /* finish off */ + eet_close(ef); + return 1; + progress_granularity = 0; +} + +void +formats (ImlibLoader *l) +{ + char *list_formats[] = + { "eet" }; + + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof (char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} + diff --git a/src/modules/loaders/loader_ico.c b/src/modules/loaders/loader_ico.c new file mode 100644 index 0000000..3fafce9 --- /dev/null +++ b/src/modules/loaders/loader_ico.c @@ -0,0 +1,622 @@ +/* + +Copyright (C) 20002 Christian Kreibich . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +sell copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies of the Software and its documentation and acknowledgment shall be +given in the documentation and software packages that this Software was +used. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "common.h" +#include +#include +#include +#include +#include "image.h" +#include "color_values.h" + +/* #define ICO_DBG */ + +#ifdef ICO_DBG +#define D(fmt, args...) \ +{ \ + printf("Imlib2 ICO loader: "); \ + printf(fmt, ## args); \ +} +#else +#define D(fmt, args...) +#endif + +#define SWAP32(x) \ +((((x) & 0x000000ff ) << 24) |\ + (((x) & 0x0000ff00 ) << 8) |\ + (((x) & 0x00ff0000 ) >> 8) |\ + (((x) & 0xff000000 ) >> 24)) + +#define SWAP16(x) \ +((((x) & 0x00ff ) << 8) |\ + (((x) & 0xff00 ) >> 8)) + +#ifdef WORDS_BIGENDIAN +#define ENDIAN_SWAP(x) (SWAP32(x)) +#define ENDIAN_SWAP16(x) (SWAP16(x)) +#else +#define ENDIAN_SWAP(x) (x) +#define ENDIAN_SWAP16(x) (x) +#endif + +typedef struct _MsIconEntry +{ + DATA8 width; /* Width of icon in pixels */ + DATA8 height; /* Height of icon in pixels */ + DATA8 num_colors; /* Maximum number of colors */ + DATA8 reserved; /* Not used */ + DATA16 num_planes; /* Not used */ + DATA16 bpp; + DATA32 size; /* Length of icon bitmap in bytes */ + DATA32 offset; /* Offset position of icon bitmap in file */ +} MsIconEntry; + +typedef struct _MsIconData +{ + /* Bitmap header data */ + DATA32 header_size; /* = 40 Bytes */ + DATA32 width; + DATA32 height; + DATA16 planes; + DATA16 bpp; + DATA32 compression; /* not used for icons */ + DATA32 image_size; /* size of image */ + DATA32 x_res; + DATA32 y_res; + DATA32 used_clrs; + DATA32 important_clrs; + + DATA32 *palette; /* Color palette, only if bpp <= 8. */ + DATA8 *xor_map; /* Icon bitmap */ + DATA8 *and_map; /* Display bit mask */ +} MsIconData; + +typedef struct _MsIcon +{ + FILE *fp; + int cp; + char *filename; + + DATA16 reserved; + DATA16 resource_type; + DATA16 icon_count; + MsIconEntry *icon_dir; + MsIconData *icon_data; +} MsIcon; + +static int ico_read_int8 (FILE *fp, DATA8 *data, int count); +static int ico_read_int16 (FILE *fp, DATA16 *data, int count); +static int ico_read_int32 (FILE *fp, DATA32 *data, int count); +static MsIcon *ico_init (char *filename); +static void ico_cleanup (MsIcon *ico); +static void ico_read_entry(MsIcon *ico, MsIconEntry* entry); +static void ico_read_data(MsIcon *ico, int icon_num); +static void ico_load (MsIcon *ico); +static int ico_to_imlib (MsIcon *ico, ImlibImage *im); + +char load(ImlibImage *im, ImlibProgressFunction progress,char progress_granularity, char immediate_load); +char save(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity); +void formats(ImlibLoader *l); + + +static int +ico_read_int32 (FILE *fp, + DATA32 *data, + int count) +{ + int i, total; + + total = count; + if (count > 0) + { + ico_read_int8 (fp, (DATA8*) data, count * 4); + for (i = 0; i < count; i++) + data[i] = ENDIAN_SWAP(data[i]); + } + + return total * 4; +} + + +static int +ico_read_int16 (FILE *fp, + DATA16 *data, + int count) +{ + int i, total; + + total = count; + if (count > 0) + { + ico_read_int8 (fp, (DATA8*) data, count * 2); + for (i = 0; i < count; i++) + data[i] = ENDIAN_SWAP16(data[i]); + } + + return total * 2; +} + + +static int +ico_read_int8 (FILE *fp, + DATA8 *data, + int count) +{ + int total; + int bytes; + + total = count; + while (count > 0) + { + bytes = fread ((char*) data, sizeof (char), count, fp); + if (bytes <= 0) /* something bad happened */ + break; + count -= bytes; + data += bytes; + } + + return total; +} + + +static MsIcon * +ico_init (char *filename) +{ + MsIcon *ico; + + if (! (ico = (MsIcon*) calloc(1, sizeof(MsIcon)))) + return NULL; + + if (! (ico->fp = fopen (filename, "r"))) + return NULL; + + ico->filename = filename; + ico->cp += ico_read_int16(ico->fp, &ico->reserved, 1); + ico->cp += ico_read_int16(ico->fp, &ico->resource_type, 1); + + /* Icon files use 1 as resource type, that's what I wrote this for. + From descriptions on the web it seems as if this loader should + also be able to handle Win 3.11 - Win 95 cursor files (.cur), + which use resource type 2. I haven't tested this though. */ + if (ico->reserved != 0 || + (ico->resource_type != 1 && ico->resource_type != 2)) + { + ico_cleanup(ico); + return NULL; + } + + return ico; +} + + +static void +ico_cleanup (MsIcon *ico) +{ + int i; + + if (!ico) + return; + + if (ico->fp) + fclose(ico->fp); + + if (ico->icon_dir) + free (ico->icon_dir); + + if (ico->icon_data) + { + for (i = 0; i < ico->icon_count; i++) + { + /* There's not always a palette .. */ + if (ico->icon_data[i].palette) + free (ico->icon_data[i].palette); + free (ico->icon_data[i].xor_map); + free (ico->icon_data[i].and_map); + } + free (ico->icon_data); + } + + free (ico); +} + + +static void +ico_read_entry(MsIcon *ico, MsIconEntry* entry) +{ + if (!ico || !entry) + return; + + ico->cp += ico_read_int8(ico->fp, &entry->width, 1); + ico->cp += ico_read_int8(ico->fp, &entry->height, 1); + ico->cp += ico_read_int8(ico->fp, &entry->num_colors, 1); + ico->cp += ico_read_int8(ico->fp, &entry->reserved, 1); + + ico->cp += ico_read_int16(ico->fp, &entry->num_planes, 1); + ico->cp += ico_read_int16(ico->fp, &entry->bpp, 1); + + ico->cp += ico_read_int32(ico->fp, &entry->size, 1); + ico->cp += ico_read_int32(ico->fp, &entry->offset, 1); + + D("Read entry with w: %i, h: %i, num_colors: %i, bpp: %i\n", + entry->width, entry->height, entry->num_colors, entry->bpp); +} + + +static void +ico_read_data(MsIcon *ico, int icon_num) +{ + MsIconData *data; + MsIconEntry *entry; + int xor_len = 0, and_len = 0; + + if (!ico) + return; + + entry = &ico->icon_dir[icon_num]; + data = &ico->icon_data[icon_num]; + + ico->cp += ico_read_int32(ico->fp, &data->header_size, 1); + ico->cp += ico_read_int32(ico->fp, &data->width, 1); + ico->cp += ico_read_int32(ico->fp, &data->height, 1); + + ico->cp += ico_read_int16(ico->fp, &data->planes, 1); + ico->cp += ico_read_int16(ico->fp, &data->bpp, 1); + + ico->cp += ico_read_int32(ico->fp, &data->compression, 1); + ico->cp += ico_read_int32(ico->fp, &data->image_size, 1); + ico->cp += ico_read_int32(ico->fp, &data->x_res, 1); + ico->cp += ico_read_int32(ico->fp, &data->y_res, 1); + ico->cp += ico_read_int32(ico->fp, &data->used_clrs, 1); + ico->cp += ico_read_int32(ico->fp, &data->important_clrs, 1); + + if (data->used_clrs == 0) + { + switch (data->bpp) + { + case 1: + D("Allocating a 2-slot palette\n"); + data->used_clrs = 2; + data->palette = (DATA32*) calloc(data->used_clrs, sizeof(DATA32)); + ico->cp += ico_read_int32(ico->fp, data->palette, data->used_clrs); + + if (((entry->width * entry->height) % 8) == 0) + xor_len = (entry->width * entry->height / 8); + else + xor_len = (entry->width * entry->height / 8) + 1; + break; + case 4: + D("Allocating a 16-slot palette\n"); + data->used_clrs = 16; + data->palette = (DATA32*) calloc(data->used_clrs, sizeof(DATA32)); + ico->cp += ico_read_int32(ico->fp, data->palette, data->used_clrs); + xor_len = entry->width * entry->height / 2; + break; + case 8: + D("Allocating a 256-slot palette\n"); + data->used_clrs = 256; + data->palette = (DATA32*) calloc(data->used_clrs, sizeof(DATA32)); + ico->cp += ico_read_int32(ico->fp, data->palette, data->used_clrs); + xor_len = entry->width * entry->height; + break; + default: + D("No colormap, used_clrs = %i, bpp = %i\n", data->used_clrs, data->bpp); + /* Otherwise, no colormap is used, but RGB values. */ + xor_len = entry->width * entry->height * (data->bpp/8); + } + } + else + { + switch (data->bpp) + { + case 1: + D("Allocating a %i-slot palette for monochrome\n", data->used_clrs); + data->palette = (DATA32*) calloc(data->used_clrs, sizeof(DATA32)); + ico->cp += ico_read_int32(ico->fp, data->palette, data->used_clrs); + + if (((entry->width * entry->height) % 8) == 0) + xor_len = (entry->width * entry->height / 8); + else + xor_len = (entry->width * entry->height / 8) + 1; + break; + case 4: + D("Allocating a %i-slot palette for 4 bpp\n", data->used_clrs); + data->palette = (DATA32*) calloc(data->used_clrs, sizeof(DATA32)); + ico->cp += ico_read_int32(ico->fp, data->palette, data->used_clrs); + xor_len = entry->width * entry->height / 2; + break; + case 8: + D("Allocating a %i-slot palette for 8 bpp\n", data->used_clrs); + data->palette = (DATA32*) calloc(data->used_clrs, sizeof(DATA32)); + ico->cp += ico_read_int32(ico->fp, data->palette, data->used_clrs); + xor_len = entry->width * entry->height; + break; + default: + D("No colormap, used_clrs = %i, bpp = %i\n", data->used_clrs, data->bpp); + /* Otherwise, no colormap is used, but RGB values. */ + xor_len = entry->width * entry->height * (data->bpp/8); + } + } + + data->xor_map = (DATA8*) calloc(xor_len, sizeof(DATA8)); + ico->cp += ico_read_int8(ico->fp, data->xor_map, xor_len); + + /* Read in and_map. It's padded out to 32 bits: */ + if ((entry->width % 32) == 0) + and_len = ((entry->width/32) * entry->height); + else + and_len = ((entry->width/32 + 1) * entry->height); + + data->and_map = (DATA8*) calloc(and_len, sizeof(DATA32)); + ico->cp += ico_read_int8(ico->fp, data->and_map, and_len * sizeof(DATA32)); + + D("Entry width %i, height %i, bpp %i\n", entry->width, entry->height, data->bpp); + D("Length of xor_map: %i\n", xor_len); + D("Length of and_map: %i\n", and_len * sizeof(DATA32)); +} + + +static void +ico_load (MsIcon *ico) +{ + int i; + + if (!ico) + return; + + ico->cp += ico_read_int16(ico->fp, &ico->icon_count, 1); + ico->icon_dir = (MsIconEntry*) calloc(ico->icon_count, sizeof(MsIconEntry)); + ico->icon_data = (MsIconData*) calloc(ico->icon_count, sizeof(MsIconData)); + + D("%s: Microsoft icon file, containing %i icon(s)\n", + ico->filename, ico->icon_count); + + for (i = 0; i < ico->icon_count; i++) + ico_read_entry(ico, &ico->icon_dir[i]); + + for (i = 0; i < ico->icon_count; i++) + ico_read_data(ico, i); +} + + +static int +ico_get_bit_from_data(DATA8 *data, int line_width, int bit) +{ + int line; + int width32; + int offset; + + /* width per line in multiples of 32 bits */ + width32 = (line_width % 32 == 0 ? line_width/32 : line_width/32 + 1); + + line = bit / line_width; + offset = bit % line_width; + + return (data[line * width32 * 4 + offset/8] & (1 << (7 - bit % 8))); +} + + +static int +ico_get_nibble_from_data(DATA8 *data, int nibble) +{ + int result = (data[nibble/2] & (0x0F << (4 * (1 - nibble % 2)))); + + if (nibble % 2 == 0) + result = result >> 4; + + return result; +} + + +static int +ico_to_imlib (MsIcon *ico, ImlibImage *im) +{ + int x, y, w, h; + DATA8 *xor_map; + DATA8 *and_map; + DATA32 *palette; + MsIconData *data; + + w = ico->icon_dir[0].width; + h = ico->icon_dir[0].height; + palette = ico->icon_data[0].palette; + xor_map = ico->icon_data[0].xor_map; + and_map = ico->icon_data[0].and_map; + + if (! (im->data = (DATA32 *) malloc(sizeof(DATA32) * w * h))) + return 0; + + im->w = w; im->h = h; + SET_FLAG(im->flags, F_HAS_ALPHA); + data = &ico->icon_data[0]; + + switch (data->bpp) + { + case 1: + D("Rendering at 1 bpp\n"); + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + { + DATA32 color = palette[ico_get_bit_from_data(xor_map, w, y * w + x)]; + DATA32 *dest = &(im->data[(h-1-y) * w + x]); + + R_VAL(dest) = R_VAL(&color); + G_VAL(dest) = G_VAL(&color); + B_VAL(dest) = B_VAL(&color); + + if (ico_get_bit_from_data(and_map, w, y*w + x)) + A_VAL(dest) = 0; + else + A_VAL(dest) = 255; + } + break; + + case 4: + D("Rendering at 4 bpp\n"); + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + { + DATA32 color = palette[ico_get_nibble_from_data(xor_map, y * w + x)]; + DATA32 *dest = &(im->data[(h-1-y) * w + x]); + + R_VAL(dest) = R_VAL(&color); + G_VAL(dest) = G_VAL(&color); + B_VAL(dest) = B_VAL(&color); + + if (ico_get_bit_from_data(and_map, w, y*w + x)) + A_VAL(dest) = 0; + else + A_VAL(dest) = 255; + + } + break; + + case 8: + D("Rendering at 8 bpp\n"); + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + { + DATA32 color = palette[xor_map[y * w + x]]; + DATA32 *dest = &(im->data[(h-1-y) * w + x]); + + R_VAL(dest) = R_VAL(&color); + G_VAL(dest) = G_VAL(&color); + B_VAL(dest) = B_VAL(&color); + + if (ico_get_bit_from_data(and_map, w, y*w + x)) + A_VAL(dest) = 0; + else + A_VAL(dest) = 255; + } + break; + + default: + { + int bytespp = data->bpp/8; + + D("Rendering at %i bpp\n", data->bpp); + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) + { + DATA32 *dest = &(im->data[(h-1-y) * w + x]); + + B_VAL(dest) = xor_map[(y * w + x) * bytespp]; + G_VAL(dest) = xor_map[(y * w + x) * bytespp + 1]; + R_VAL(dest) = xor_map[(y * w + x) * bytespp + 2]; + + if (data->bpp < 32) + { + if (ico_get_bit_from_data(and_map, w, y*w + x)) + A_VAL(dest) = 0; + else + A_VAL(dest) = 255; + } + else + { + A_VAL(dest) = xor_map[(y * w + x) * bytespp + 3]; + } + } + } + } + + return 1; +} + + +char +load(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity, char immediate_load) +{ + MsIcon *ico = NULL; + + /* if immediate_load is 1, then dont delay image laoding as below, or */ + /* already data in this image - dont load it again */ + if (im->data) + return 0; + + /* set the format string member to the lower-case full extension */ + /* name for the format - so example names would be: */ + /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ + + if (!im->format) + im->format = strdup("ico"); + + if (im->loader || immediate_load || progress) + { + if (! (ico = ico_init((im->real_file)))) + return 0; + + ico_load (ico); + + if (! ico_to_imlib (ico, im)) + goto error; + + ico_cleanup (ico); + } + + if (progress) + { + progress(im, 100, 0, 0, im->w, im->h); + } + + return 1; + + error: + + if (im->data) + free(im->data); + return 0; + + progress_granularity = 0; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your laoder CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats (ImlibLoader *l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = + { "ico" }; + + /* don't bother changing any of this - it just reads this in and sets */ + /* the struct values and makes copies */ + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof (char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} + diff --git a/src/modules/loaders/loader_xcf.c b/src/modules/loaders/loader_xcf.c new file mode 100644 index 0000000..1653920 --- /dev/null +++ b/src/modules/loaders/loader_xcf.c @@ -0,0 +1,1752 @@ +/* + + -----------------------------[ XCF Loader ]----------------------------- + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + ------------------------------------------------------------------------ + + There's a quick overview of the XCF file structure in Gimp's source + tree, in docs/xcf.doc. However it's brief, so here's a more verbose + overview based on my understanding of XCF. All image characteristics + are defined in "properties". In the data stream properties are defined + through a 4 bit index number (see enum below), followed by a 4 byte + length. The property data directly follows this information. A list of + properties ends when PROP_END is encountered. There is a properties + block at the beginning of the file, as well as at the beginning of each + layer and channel. Layers and channels are read at offsets in the file, + the list of layers (resp. channels) is exhausted when the next offset + read in is zero. + + The actual image data is stored in tiles, which are by default 64x64 in + size, likely with smaller ones on the right and bottom edges. + + The position of the tiles on the image is left->right, row by row. The + actual DATA8* data is contained in a "level" which is contained in a + "hierarchy". I've not really understood the purpose of the hierarchy, as + it seems to always contain only one level anyway. + + Layer masks are stored as channels (basically grayscale layers with a + single color definition. For the purpose of this loader I replaced the + concept of a channel with a layer, since it doesn't really matter. + + Ok, hope this helps with understanding XCF. -- cK. + +*/ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "common.h" +#include "image.h" +#include "color_values.h" + +/* #define XCF_DBG */ + +#define FREE(X) { free(X); X = NULL; } + +#ifdef XCF_DBG +#define D(fmt, args...) \ +{ \ + printf("Imlib2 XCF loader: "); \ + printf(fmt, ## args); \ +} +#else +#define D(fmt, args...) +#endif + + +#define TILE_WIDTH 64 +#define TILE_HEIGHT 64 + +/* --------------------------------------------------------------------------- typedefs ------------ */ + +typedef struct _Layer Layer; +typedef struct _Tile Tile; + +/* ------------------------------------------------------------------------------ enums ------------ */ + + +/* These are all the properties that a layer or channel can have. + Only some of them are actually used. */ +typedef enum +{ + PROP_END = 0, + PROP_COLORMAP = 1, + PROP_ACTIVE_LAYER = 2, + PROP_ACTIVE_CHANNEL = 3, + PROP_SELECTION = 4, + PROP_FLOATING_SELECTION = 5, + PROP_OPACITY = 6, + PROP_MODE = 7, + PROP_VISIBLE = 8, + PROP_LINKED = 9, + PROP_PRESERVE_TRANSPARENCY = 10, + PROP_APPLY_MASK = 11, + PROP_EDIT_MASK = 12, + PROP_SHOW_MASK = 13, + PROP_SHOW_MASKED = 14, + PROP_OFFSETS = 15, + PROP_COLOR = 16, + PROP_COMPRESSION = 17, + PROP_GUIDES = 18, + PROP_RESOLUTION = 19, + PROP_TATTOO = 20, + PROP_PARASITES = 21, + PROP_UNIT = 22, + PROP_PATHS = 23, + PROP_USER_UNIT = 24 +} +PropType; + +/* The tiles can be stored in an encrypted fashion, defined as follows: */ +typedef enum +{ + COMPRESS_NONE = 0, + COMPRESS_RLE = 1, + COMPRESS_ZLIB = 2, + COMPRESS_FRACTAL = 3 /* Unused. */ +} CompressionType; + +/* Layer modes (*SIGH*) */ +typedef enum +{ + NORMAL_MODE, + DISSOLVE_MODE, + BEHIND_MODE, + MULTIPLY_MODE, + SCREEN_MODE, + OVERLAY_MODE, + DIFFERENCE_MODE, + ADDITION_MODE, + SUBTRACT_MODE, + DARKEN_ONLY_MODE, + LIGHTEN_ONLY_MODE, + HUE_MODE, + SATURATION_MODE, + COLOR_MODE, + VALUE_MODE, + DIVIDE_MODE, + ERASE_MODE, /*< skip >*/ + REPLACE_MODE, /*< skip >*/ + ANTI_ERASE_MODE /*< skip >*/ +} +LayerModeEffects; + +/* Base image types */ +typedef enum +{ + RGB, + GRAY, + INDEXED +} GimpImageBaseType; + +/* Image types */ +typedef enum +{ + RGB_GIMAGE, + RGBA_GIMAGE, + GRAY_GIMAGE, + GRAYA_GIMAGE, + INDEXED_GIMAGE, + INDEXEDA_GIMAGE +} GimpImageType; + +/* ---------------------------------------------------------------------------- structs ------------ */ + +/* Ok, this is what's left of Gimp's layer abstraction. I kicked out + all the stuff that's unnecessary and added the necessary stuff + from the Gimp drawable superclass. This one also serves as a + Channel, e.g. for use as a layer mask. + --cK. +*/ +struct _Layer +{ + int visible; /* controls visibility */ + int width, height; /* size of drawable */ + int bpp; /* depth */ + int offset_x, offset_y; /* offset of layer in image */ + + int ID; /* provides a unique ID */ + GimpImageType type; /* type of drawable */ + char has_alpha; /* drawable has alpha */ + + int preserve_trans; /* preserve transparency */ + + Layer *mask; /* possible layer mask */ + + int opacity; /* layer opacity */ + LayerModeEffects mode; /* layer combination mode */ + + + /* XCF stores the actual image data as tiles. A Layer is covered with + tiles, the tiles on the right and bottom will (usually) be a bit + smaller. num_rows and num_cols gives the number of tile rows and + columns. + */ + + Tile* tiles; /* tiles for drawable data */ + int num_rows; + int num_cols; + + /* After the tiles are read in, they're serialized int an array + of DATA8's, that will always contain 4 bpp data. Not optimal, + I know, but makes life easier + */ + + DATA8* data; + + /* Layers are stored as a linked list. */ + struct _Layer* next; + struct _Layer* prev; +}; + + +/* The tile structure: +*/ +struct _Tile +{ + unsigned char bpp; /* the bytes per pixel (1, 2, 3 or 4) */ + unsigned short ewidth; /* the effective width of the tile */ + unsigned short eheight; /* the effective height of the tile */ + + /* a tile's effective width and height may be smaller + * (but not larger) than TILE_WIDTH and TILE_HEIGHT. + * This is to handle edge tiles of a drawable. + */ + + DATA8 *data; +}; + + +/* This struct simply contains everything that didn't fit elsewhere, + based on GimpImage :) +*/ +struct _GimpImage +{ + FILE* fp; + char* filename; + int cp; /* file stream pointer */ + int compression; /* file compression mode */ + int file_version; + + int width, height; /* width and height attributes */ + GimpImageBaseType base_type; /* base gimp_image type */ + + DATA32 floating_sel_offset; + + DATA8* cmap; /* colormap--for indexed */ + int num_cols; /* number of colors in map */ + + /* If a layer number was passed to the loader, it goes here: */ + int single_layer_index; + + /* Tadaa -- the final image data. Layers get pasted + onto this one, bottom-up. + */ + DATA8* data; + + Layer* layers; + Layer* last_layer; + Layer* floating_sel; +} +_image; + +/* ------------------------------------------------------------------------- prototypes ------------ */ + +char load(ImlibImage *im, ImlibProgressFunction progress,char progress_granularity, char immediate_load); +char save(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity); +void formats(ImlibLoader *l); + +/* stuff that was adapted from xcf.c */ + +static void xcf_seek_pos (int pos); +static int xcf_read_int32 (FILE *fp, DATA32 *data, int count); +/*static int xcf_read_float (FILE *fp, float *data, int count);*/ +static int xcf_read_int8 (FILE *fp, DATA8 *data, int count); +static int xcf_read_string (FILE *fp, char **data, int count); +static char xcf_load_prop (PropType *prop_type, DATA32 *prop_size); +static void xcf_load_image (void); +static char xcf_load_image_props (void); + +static Layer* xcf_load_channel (void); +static char xcf_load_channel_props (Layer* layer); +static Layer* xcf_load_layer(void); +static char xcf_load_layer_props (Layer* layer); +static char xcf_load_hierarchy (Tile** tiles, int* num_rows, int* num_cols, int* bpp); +static char xcf_load_level (Tile** tiles, int hierarchy_width, int hierarchy_height, int bpp, int* num_rows, int *num_cols); +static char xcf_load_tile (Tile *tile); +static char xcf_load_tile_rle (Tile *tile, int data_length); + +/* new stuff :) */ + +static Tile* allocate_tiles(int width, int height, int bpp, int* num_rows, int* num_cols); +static void free_tiles(Tile* tiles, int num_tiles); +static void init_tile(Tile* tile, int width, int height, int bpp); +static Layer* new_layer(int width, int height, GimpImageType type, int opacity, LayerModeEffects mode); +static void free_layer(Layer* layer); +static void add_layer_to_image(Layer* layer); +static void read_tiles_into_data(Tile* tiles, int num_cols, int width, int height, int bpp, DATA8** data, int use_cmap); +static void apply_layer_mask(Layer* layer); +static void set_layer_opacity(Layer* layer); +static void flatten_image(void); + +static char xcf_file_init(char* filename); +static void xcf_cleanup(void); +static void xcf_to_imlib(ImlibImage *im); + +/* Stuff for layer merging: +*/ +extern void combine_pixels_normal (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_add (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_sub (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_diff (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_darken (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_lighten (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_div (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_screen (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_overlay (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_hue (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_sat (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_val (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_col (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); +extern void combine_pixels_diss (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y); + + +/* ---------------------------------------------------------------------------- globals ------------ */ + +/* This makes using the Gimp sources easier */ +struct _GimpImage * image = &_image; + +/* ------------------------------------------------------------------------------- code ------------ */ + +static void +xcf_seek_pos (int pos) +{ + if (image->cp != pos) + { + image->cp = pos; + fseek (image->fp, image->cp, SEEK_SET); + } +} + +static int +xcf_read_int32 (FILE *fp, + DATA32 *data, + int count) +{ + int total; + + total = count; + if (count > 0) + { + xcf_read_int8 (fp, (DATA8*) data, count * 4); + + while (count--) + { + *data = (DATA32) ntohl (*data); + data++; + } + } + + return total * 4; +} + +/* +static int +xcf_read_float (FILE *fp, + float *data, + int count) +{ + return (xcf_read_int32(fp, (DATA32 *)((void *)data), count)); +} +*/ + +static int +xcf_read_int8 (FILE *fp, + DATA8 *data, + int count) +{ + int total; + int bytes; + + total = count; + while (count > 0) + { + bytes = fread ((char*) data, sizeof (char), count, fp); + if (bytes <= 0) /* something bad happened */ + break; + count -= bytes; + data += bytes; + } + + return total; +} + +static int +xcf_read_string (FILE *fp, + char **data, + int count) +{ + DATA32 tmp; + int total; + int i; + + total = 0; + for (i = 0; i < count; i++) + { + total += xcf_read_int32 (fp, &tmp, 1); + if (tmp > 0) + { + data[i] = malloc(sizeof(DATA8) * tmp); + total += xcf_read_int8 (fp, (DATA8*) data[i], tmp); + } + else + { + data[i] = NULL; + } + } + + return total; +} + + +static char +xcf_load_prop (PropType *prop_type, + DATA32 *prop_size) +{ + image->cp += xcf_read_int32 (image->fp, (DATA32*) prop_type, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) prop_size, 1); + return 1; +} + + +static char +xcf_load_image_props (void) +{ + PropType prop_type; + DATA32 prop_size; + + while (1) + { + if (!xcf_load_prop (&prop_type, &prop_size)) + return 0; + + switch (prop_type) + { + case PROP_END: + { + D("Finished reading image properties.\n"); + return 1; + } + case PROP_COLORMAP: + { + if (image->file_version == 0) + { + int i; + fprintf (stderr, + "XCF warning: version 0 of XCF file format\n" + "did not save indexed colormaps correctly.\n" + "Substituting grayscale map.\n"); + image->cp += xcf_read_int32 (image->fp, &image->num_cols, 1); + image->cmap = (DATA8*) malloc (sizeof(DATA8) * image->num_cols * 3); + xcf_seek_pos (image->cp + image->num_cols); + for (i = 0; inum_cols; i++) + { + image->cmap[i*3+0] = i; + image->cmap[i*3+1] = i; + image->cmap[i*3+2] = i; + } + } + else + { + D("Loading colormap.\n"); + image->cp += xcf_read_int32 (image->fp, &image->num_cols, 1); + image->cmap = malloc (sizeof(DATA8) * image->num_cols * 3); + image->cp += xcf_read_int8 (image->fp, (DATA8*) image->cmap, image->num_cols*3); + } + } + break; + + case PROP_COMPRESSION: + { + char compression; + + image->cp += xcf_read_int8 (image->fp, (char*) &compression, 1); + + if ((compression != COMPRESS_NONE) && + (compression != COMPRESS_RLE) && + (compression != COMPRESS_ZLIB) && + (compression != COMPRESS_FRACTAL)) + { + fprintf (stderr, "unknown xcf compression type: %d\n", (int) compression); + return 0; + } + + D("Image compression type: %i\n", compression); + + image->compression = compression; + } + break; + + /* I threw out all of the following: --cK */ + case PROP_TATTOO: + case PROP_PARASITES: + case PROP_UNIT: + case PROP_PATHS: + case PROP_USER_UNIT: + case PROP_GUIDES: + case PROP_RESOLUTION: + default: + { + DATA8 buf[16]; + int amount; + + D("Skipping unexpected/unknown image property: %d\n", prop_type); + + while (prop_size > 0) + { + amount = (16 < prop_size ? 16 : prop_size); + image->cp += xcf_read_int8 (image->fp, buf, amount); + prop_size -= (16 < amount ? 16 : amount); + } + } + break; + } + } + + return 0; +} + + +static void +xcf_load_image (void) +{ + Layer* layer; + DATA32 saved_pos; + DATA32 offset; + int width; + int height; + int image_type; + int num_successful_elements = 0; + + /* read in the image width, height and type */ + image->cp += xcf_read_int32 (image->fp, (DATA32*) &width, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &height, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &image_type, 1); + + image->width = width; + image->height = height; + image->base_type = image_type; + + D("Loading %ix%i image.\n", width, height); + + /* read the image properties */ + if (!xcf_load_image_props ()) + goto hard_error; + + while (1) + { + /* read in the offset of the next layer */ + image->cp += xcf_read_int32 (image->fp, &offset, 1); + + /* if the offset is 0 then we are at the end + * of the layer list. + */ + if (offset == 0) + break; + + /* save the current position as it is where the + * next layer offset is stored. + */ + saved_pos = image->cp; + + /* seek to the layer offset */ + xcf_seek_pos (offset); + + /* read in the layer */ + layer = xcf_load_layer(); + if (!layer) + goto error; + + num_successful_elements++; + + /* add the layer to the image if it's visible */ + if (layer->visible) + add_layer_to_image(layer); + else + free_layer(layer); + + /* restore the saved position so we'll be ready to + * read the next offset. + */ + xcf_seek_pos (saved_pos); + + } + + /* If we were a Gimp we would now load the user-defined channels here ... */ + + /* Flat-o-rama now :) */ + flatten_image(); + + return; + + error: + if (num_successful_elements == 0) + goto hard_error; + + fprintf(stderr, "XCF: This file is corrupt! I have loaded as much\nof it as I can, but it is incomplete.\n"); + + return; + + hard_error: + fprintf(stderr, "XCF: This file is corrupt! I could not even\nsalvage any partial image data from it.\n"); + return; +} + + +static char +xcf_load_layer_props (Layer* layer) +{ + PropType prop_type; + DATA32 prop_size; + + while (1) + { + if (!xcf_load_prop (&prop_type, &prop_size)) + return 0; + + switch (prop_type) + { + case PROP_END: + { + D("Finished reading layer properties.\n"); + return 1; + } + case PROP_FLOATING_SELECTION: + D("Loading floating selection.\n"); + image->floating_sel = layer; + image->cp += xcf_read_int32 (image->fp, (DATA32*) &image->floating_sel_offset, 1); + break; + case PROP_OPACITY: + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->opacity, 1); + break; + case PROP_VISIBLE: + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->visible, 1); + break; + case PROP_PRESERVE_TRANSPARENCY: + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->preserve_trans, 1); + break; + case PROP_OFFSETS: + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->offset_x, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->offset_y, 1); + break; + case PROP_MODE: + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->mode, 1); + break; + + /* I threw out all of the following: --cK */ + case PROP_LINKED: + case PROP_ACTIVE_LAYER: + case PROP_TATTOO: + case PROP_APPLY_MASK: + case PROP_EDIT_MASK: + case PROP_SHOW_MASK: + case PROP_PARASITES: + default: + { + DATA8 buf[16]; + int amount; + + D("Skipping unexpected/unknown/unneeded channel property: %d\n", prop_type); + + while (prop_size > 0) + { + amount = (16 < prop_size ? 16 : prop_size); + image->cp += xcf_read_int8 (image->fp, buf, amount); + prop_size -= (16 < amount ? 16 : amount); + } + } + break; + } + } + + return 0; +} + + +static Layer* +xcf_load_layer(void) +{ + Layer *layer; + Layer *layer_mask; + DATA32 hierarchy_offset; + DATA32 layer_mask_offset; + int width; + int height; + int type; + char *name; + + D("Loading one layer ...\n"); + + /* read in the layer width, height and type */ + image->cp += xcf_read_int32 (image->fp, (DATA32*) &width, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &height, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &type, 1); + image->cp += xcf_read_string (image->fp, &name, 1); + + /* ugly, I know */ + FREE(name); + + /* create a new layer */ + layer = new_layer (width, height, type, 255, NORMAL_MODE); + if (!layer) + return NULL; + + /* read in the layer properties */ + if (!xcf_load_layer_props(layer)) + goto error; + + D("Loading opacity: %i \n", layer->opacity); + + if (!layer->visible) + return layer; + + /* read the hierarchy and layer mask offsets */ + image->cp += xcf_read_int32 (image->fp, &hierarchy_offset, 1); + image->cp += xcf_read_int32 (image->fp, &layer_mask_offset, 1); + + /* read in the hierarchy */ + xcf_seek_pos (hierarchy_offset); + if (!xcf_load_hierarchy (&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp))) + goto error; + + /* read in the layer mask */ + if (layer_mask_offset != 0) + { + D("Loading layer mask.\n"); + xcf_seek_pos (layer_mask_offset); + + layer_mask = xcf_load_channel(); + if (!layer_mask) + goto error; + + /* set the offsets of the layer_mask */ + layer_mask->offset_x = layer->offset_x; + layer_mask->offset_y = layer->offset_y; + layer->mask = layer_mask; + } + + read_tiles_into_data(layer->tiles, layer->num_cols, + layer->width, layer->height, + layer->bpp, &(layer->data), + 1); + free_tiles(layer->tiles, layer->num_rows * layer->num_cols); + layer->tiles = NULL; + + set_layer_opacity(layer); + + if (layer->mask) + apply_layer_mask(layer); + + return layer; + +error: + free_layer(layer); + return NULL; +} + + +static void +read_tiles_into_data(Tile* tiles, int num_cols, int width, + int height, int bpp, DATA8** data_p, int use_cmap) +{ + int tile_x, tile_y, x, y, offset_x, offset_y; + DATA8* data; + DATA8* ptr; + DATA8* ptr2; + Tile* t; + int warned=0; + + if (tiles) + { + if (*data_p) + FREE(*data_p); + + /* Always allocate the data as 4 bytes per pixel */ + data = (*data_p) = (DATA8*) malloc (sizeof(DATA32) * width * height); + + ptr = data; + + for (y = 0; y < height; y++) + { + for (x = 0; x < width; x++) + { + tile_x = x / TILE_WIDTH; + tile_y = y / TILE_HEIGHT; + offset_x = x % TILE_WIDTH; + offset_y = y % TILE_HEIGHT; + + t = &tiles[tile_y * num_cols + tile_x]; + ptr2 = &(t->data[offset_y * t->ewidth * bpp + offset_x * bpp]); + + switch (bpp) + { + case 1: + { + /* use colormap if the image has one */ + if (image->cmap && use_cmap) + { + R_VAL(ptr) = image->cmap[*(ptr2) * 3]; + G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1]; + B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2]; + A_VAL(ptr) = 255; + } + /* else use colors themselves */ + else + { + R_VAL(ptr) = *(ptr2); + G_VAL(ptr) = *(ptr2); + B_VAL(ptr) = *(ptr2); + A_VAL(ptr) = 255; + } + break; + } + case 2: + { + /* use colormap if the image has one */ + if (image->cmap && use_cmap) + { + R_VAL(ptr) = image->cmap[*(ptr2) * 3]; + G_VAL(ptr) = image->cmap[*(ptr2) * 3 + 1]; + B_VAL(ptr) = image->cmap[*(ptr2) * 3 + 2]; + A_VAL(ptr) = *(ptr2+1); + } + /* else use colors themselves */ + else if(warned==0) + { + warned++; + fprintf (stderr, "There's nothing to see here. 2 bpp without colormap not implemented yet.\n"); + } + break; + } + case 3: + { + if (image->cmap) + { + if(warned==0) + { + warned++; + fprintf (stderr, "There's nothing to see here. 3 bpp with colormap not implemented yet.\n"); + } + } + else + { + R_VAL(ptr) = *(ptr2); + G_VAL(ptr) = *(ptr2+1); + B_VAL(ptr) = *(ptr2+2); + A_VAL(ptr) = 255; + } + break; + } + default: + { + R_VAL(ptr) = *(ptr2); + G_VAL(ptr) = *(ptr2+1); + B_VAL(ptr) = *(ptr2+2); + A_VAL(ptr) = *(ptr2+3); + break; + } + } + ptr += 4; + } + } + } +} + + +static Layer* +xcf_load_channel (void) +{ + Layer *layer; + DATA32 hierarchy_offset; + int width; + int height; + char *name; + + D("Loading channel ...\n"); + + /* read in the layer width, height and name */ + image->cp += xcf_read_int32 (image->fp, (DATA32*) &width, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &height, 1); + image->cp += xcf_read_string (image->fp, &name, 1); + + /* Yeah, still ugly :) */ + FREE(name); + + /* create a new channel */ + layer = new_layer (width, height, GRAY, 255, NORMAL_MODE); + if (!layer) + return NULL; + + /* read in the channel properties */ + if (!xcf_load_channel_props (layer)) + goto error; + + /* read the hierarchy and layer mask offsets */ + image->cp += xcf_read_int32 (image->fp, &hierarchy_offset, 1); + + /* read in the hierarchy */ + xcf_seek_pos (hierarchy_offset); + if (!xcf_load_hierarchy(&(layer->tiles), &(layer->num_rows), &(layer->num_cols), &(layer->bpp))) + goto error; + + read_tiles_into_data(layer->tiles, layer->num_cols, layer->width, + layer->height, layer->bpp, &(layer->data), 0); + free_tiles(layer->tiles, layer->num_rows * layer->num_cols); + layer->tiles = NULL; + + D("Channel loaded successfully.\n"); + + return layer; + +error: + free_layer(layer); + return NULL; +} + + +static char +xcf_load_channel_props (Layer* layer) +{ + PropType prop_type; + DATA32 prop_size; + + while (1) + { + if (!xcf_load_prop (&prop_type, &prop_size)) + return 0; + + switch (prop_type) + { + case PROP_END: + { + D("Finished loading channel props.\n"); + return 1; + } + case PROP_OPACITY: + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->opacity, 1); + break; + case PROP_VISIBLE: + image->cp += xcf_read_int32 (image->fp, (DATA32*) &layer->visible, 1); + break; + case PROP_ACTIVE_CHANNEL: + case PROP_SHOW_MASKED: + case PROP_SELECTION: + case PROP_COLOR: + case PROP_TATTOO: + case PROP_PARASITES: + default: + { + DATA8 buf[16]; + int amount; + + D("Skipping unexpected/unknown/unneeded channel property: %d\n", prop_type); + + while (prop_size > 0) + { + amount = (16 < prop_size ? 16 : prop_size); + image->cp += xcf_read_int8 (image->fp, buf, amount); + prop_size -= (16 < amount ? 16 : amount); + } + } + break; + } + } + + return 0; +} + + +static char +xcf_load_hierarchy (Tile** tiles, int* num_rows, int* num_cols, int* bpp) +{ + DATA32 saved_pos; + DATA32 offset; + DATA32 junk; + int width; + int height; + + image->cp += xcf_read_int32 (image->fp, (DATA32*) &width, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &height, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) bpp, 1); + + image->cp += xcf_read_int32 (image->fp, &offset, 1); /* top level */ + + D("Loading hierarchy: width %i, height %i, bpp %i\n", width, height, *bpp); + + /* discard offsets for layers below first, if any. + */ + do + { + image->cp += xcf_read_int32 (image->fp, &junk, 1); + } + while (junk != 0); + + /* save the current position as it is where the + * next level offset is stored. + */ + saved_pos = image->cp; + + /* seek to the level offset */ + xcf_seek_pos (offset); + + /* read in the level */ + if (!xcf_load_level (tiles, width, height, *bpp, num_rows, num_cols)) + return 0; + + /* restore the saved position so we'll be ready to + * read the next offset. + */ + xcf_seek_pos (saved_pos); + + D("Loaded hierarchy successfully.\n"); + + return 1; +} + + +static char +xcf_load_level (Tile** tiles_p, int hierarchy_width, int hierarchy_height, int bpp, int* num_rows, int* num_cols) +{ + DATA32 saved_pos; + DATA32 offset, offset2; + int ntiles; + int width; + int height; + int i; + int fail; + + Tile* tiles; + Tile* current_tile; + + image->cp += xcf_read_int32 (image->fp, (DATA32*) &width, 1); + image->cp += xcf_read_int32 (image->fp, (DATA32*) &height, 1); + + if ((width != hierarchy_width) || + (height != hierarchy_height)) + return 0; + + D("Loading level of size %ix%i.\n", width, height); + (*tiles_p) = allocate_tiles(width, height, bpp, num_rows, num_cols); + tiles = (*tiles_p); + + image->cp += xcf_read_int32 (image->fp, &offset, 1); + if (offset == 0) + return 1; + + ntiles = (*num_rows) * (*num_cols); + for (i = 0; i < ntiles; i++) + { + current_tile = &(tiles[i]); + fail = 0; + + if (offset == 0) + { + D("Not enough tiles found in level\n"); + return 0; + } + + /* save the current position as it is where the + * next tile offset is stored. + */ + saved_pos = image->cp; + + /* read in the offset of the next tile so we can calculate the amount + of data needed for this tile*/ + image->cp += xcf_read_int32 (image->fp, &offset2, 1); + + /* if the offset is 0 then we need to read in the maximum possible + allowing for negative compression */ + if (offset2 == 0) + offset2 = offset + TILE_WIDTH*TILE_WIDTH*4*1.5; /* 1.5 is probably more + than we need to allow */ + + /* seek to the tile offset */ + xcf_seek_pos (offset); + + /* read in the current_tile */ + switch (image->compression) + { + case COMPRESS_NONE: + if (!xcf_load_tile (current_tile)) + fail = 1; + break; + case COMPRESS_RLE: + if (!xcf_load_tile_rle (current_tile, offset2 - offset)) + fail = 1; + break; + case COMPRESS_ZLIB: + fprintf (stderr, "xcf: zlib compression unimplemented\n"); + fail = 1; + break; + case COMPRESS_FRACTAL: + fprintf (stderr, "xcf: fractal compression unimplemented\n"); + fail = 1; + break; + } + + if (fail) + { + D("Couldn't load tiles.\n"); + free_tiles(tiles, (*num_rows) * (*num_cols)); + return 0; + } + + /* restore the saved position so we'll be ready to + * read the next offset. + */ + xcf_seek_pos (saved_pos); + + /* read in the offset of the next tile */ + image->cp += xcf_read_int32 (image->fp, &offset, 1); + } + + if (offset != 0) + { + D("encountered garbage after reading level: %d\n", offset); + return 0; + } + + D("Loaded level successfully.\n"); + + return 1; +} + +static char +xcf_load_tile (Tile *tile) +{ + image->cp += xcf_read_int8 (image->fp, tile->data, tile->ewidth * tile->eheight * tile->bpp); + return 1; +} + +static char +xcf_load_tile_rle (Tile *tile, + int data_length) +{ + DATA8 *data; + DATA8 val; + int size; + int count; + int length; + int bpp; + int i, j; + int nmemb_read_successfully; + DATA8 *xcfdata, *xcfodata, *xcfdatalimit; + + data = tile->data; + bpp = tile->bpp; + + /*printf ("Reading encrypted tile %ix%ix%i, data_length %i\n", tile->ewidth, tile->eheight, tile->bpp, data_length);*/ + + xcfdata = xcfodata = malloc (sizeof(DATA8) * data_length); + + /* we have to use fread instead of xcf_read_* because we may be + reading past the end of the file here */ + nmemb_read_successfully = fread ((char*) xcfdata, sizeof (char), + data_length, image->fp); + image->cp += nmemb_read_successfully; + + xcfdatalimit = &xcfodata[nmemb_read_successfully - 1]; + + for (i = 0; i < bpp; i++) + { + data = (tile->data) + i; + size = tile->ewidth * tile->eheight; + count = 0; + + while (size > 0) + { + if (xcfdata > xcfdatalimit) + { + goto bogus_rle; + } + + val = *xcfdata++; + + length = val; + if (length >= 128) + { + length = 255 - (length - 1); + if (length == 128) + { + if (xcfdata >= xcfdatalimit) + { + goto bogus_rle; + } + + length = (*xcfdata << 8) + xcfdata[1]; + xcfdata += 2; + } + + count += length; + size -= length; + + if (size < 0) + { + goto bogus_rle; + } + + if (&xcfdata[length-1] > xcfdatalimit) + { + goto bogus_rle; + } + + while (length-- > 0) + { + *data = *xcfdata++; + data += bpp; + } + } + else + { + length += 1; + if (length == 128) + { + if (xcfdata >= xcfdatalimit) + { + goto bogus_rle; + } + + length = (*xcfdata << 8) + xcfdata[1]; + xcfdata += 2; + } + + count += length; + size -= length; + + if (size < 0) + { + goto bogus_rle; + } + + if (xcfdata > xcfdatalimit) + { + goto bogus_rle; + } + + val = *xcfdata++; + + for (j = 0; j < length; j++) + { + *data = val; + data += bpp; + } + } + } + } + FREE(xcfodata); + return 1; + + bogus_rle: + fprintf(stderr, "WHOOOOOP -- bogus rle? Highly unlikely, blame cK for this one :) \n"); + if (xcfodata) + FREE(xcfodata); + return 0; +} + + +static Layer* +new_layer(int width, int height, GimpImageType type, int opacity, LayerModeEffects mode) +{ + Layer* layer; + + layer = (Layer*) malloc(sizeof(Layer)); + if (!layer) + { + D("Couldn't allocate layer.\n"); + return NULL; + } + + bzero(layer, sizeof(Layer)); + + layer->width = width; + layer->height = height; + layer->type = type; + layer->opacity = opacity; + layer->mode = mode; + + layer->tiles = NULL; + layer->next = NULL; + layer->mask = NULL; + + return layer; +} + + +static void +free_layer(Layer* layer) +{ + if (layer) + { + if (layer->tiles) + free_tiles(layer->tiles, layer->num_rows * layer->num_cols); + + if (layer->mask) + free_layer(layer->mask); + + if (layer->data) + FREE(layer->data); + + FREE(layer); + } +} + + +static Tile* +allocate_tiles(int width, int height, int bpp, int* num_rows, int* num_cols) +{ + Tile* tiles; + int i, j, k, right_tile, bottom_tile; + int tile_width, tile_height; + + (*num_rows) = (height + TILE_HEIGHT - 1) / TILE_HEIGHT; + (*num_cols) = (width + TILE_WIDTH - 1) / TILE_WIDTH; + + tiles = (Tile*) malloc(sizeof(Tile) * (*num_rows) * (*num_cols)); + if (!tiles) + { + D("Couldn't allocate tiles.\n"); + return NULL; + } + + right_tile = width - (((*num_cols) - 1) * TILE_WIDTH); + bottom_tile = height - (((*num_rows) - 1) * TILE_HEIGHT); + + for (i = 0, k = 0; i < (*num_rows); i++) + { + for (j = 0; j < (*num_cols); j++, k++) + { + tile_width = ((j == (*num_cols) - 1) ? right_tile : TILE_WIDTH); + tile_height = ((i == (*num_rows) - 1) ? bottom_tile : TILE_HEIGHT); + init_tile(&(tiles[k]), tile_width, tile_height, bpp); + } + } + + D("Allocated %ix%i tiles.\n", (*num_cols), (*num_rows)); + + return tiles; +} + + +static void +init_tile(Tile* tile, int width, int height, int bpp) +{ + if (tile) + { + tile->bpp = bpp; + tile->ewidth = width; + tile->eheight = height; + tile->data = (DATA8*) malloc (sizeof(DATA8) * width * height * bpp); + if (!tile->data) + { + D("Couldn't allocate tile.\n"); + } + } +} + + +static void +free_tiles(Tile* tiles, int num_tiles) +{ + int i; + + for (i=0; ilast_layer) + { + image->last_layer->next = layer; + layer->prev = image->last_layer; + } + else + { + image->layers = layer; + layer->prev = NULL; + } + layer->next = NULL; + image->last_layer = layer; + } +} + + +static void +set_layer_opacity(Layer* layer) +{ + int i; + DATA8* ptr; + + if (layer) + { + if (layer->opacity != 255) + { + for (i = 0, ptr = layer->data; i < layer->width * layer->height; i++, ptr += 4) + { + *(ptr + 3) = (*(ptr + 3) * layer->opacity) >> 8; + } + } + } +} + +static void +apply_layer_mask(Layer* layer) +{ + DATA8* ptr1; + DATA8* ptr2; + int i, tmp; + + D("Applying layer mask.\n"); + + if (layer) + { + if (layer->mask) + { + ptr1 = layer->data; + ptr2 = layer->mask->data; + + for (i = 0; i < layer->width*layer->height; i++) + { + tmp = (*(ptr1+3) * *(ptr2)) / 256; + if (tmp > 255) + tmp = 255; + + *(ptr1+3) = (DATA8)tmp; + ptr1 += 4; + ptr2 += 4; + } + } + } +} + + +static void +flatten_image(void) +{ + Layer* l = image->last_layer; + Layer* lp; + int layer_index; + + image->data = (DATA8*) calloc(image->width * image->height, sizeof(DATA32)); + layer_index = 0; + + while (l) + { + /* Ok, paste each layer on top of the image, using the mode's merging type. + We're moving upward through the layer stack. + --cK. + */ + if (image->single_layer_index < 0 || layer_index == image->single_layer_index) + { + switch (l->mode) + { + case MULTIPLY_MODE: + D("MULTIPLY\n"); + combine_pixels_mult(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case DIVIDE_MODE: + D("DIVIDE\n"); + combine_pixels_div(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case SCREEN_MODE: + D("SCREEN\n"); + combine_pixels_screen(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case OVERLAY_MODE: + D("OVERLAY\n"); + combine_pixels_overlay(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case DIFFERENCE_MODE: + D("DIFF\n"); + combine_pixels_diff(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case ADDITION_MODE: + D("ADD\n"); + combine_pixels_add(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case SUBTRACT_MODE: + D("SUB\n"); + combine_pixels_sub(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case DARKEN_ONLY_MODE: + D("DARKEN\n"); + combine_pixels_darken(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case LIGHTEN_ONLY_MODE: + D("LIGHTEN\n"); + combine_pixels_lighten(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + + case HUE_MODE: + D("HUE\n"); + combine_pixels_hue(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case SATURATION_MODE: + D("SATURATION\n"); + combine_pixels_sat(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case VALUE_MODE: + D("VALUE\n"); + combine_pixels_val(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case COLOR_MODE: + D("COLOR\n"); + combine_pixels_col(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + case DISSOLVE_MODE: + D("DISSOLVE\n"); + combine_pixels_diss(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + + /* None of the following is actually valid for layer blending, fall through: */ + case BEHIND_MODE: + case REPLACE_MODE: + case ERASE_MODE: + case ANTI_ERASE_MODE: + D("EEEEEK -- this mode shouldn't be here\n"); + + case NORMAL_MODE: + D("NORMAL\n"); + combine_pixels_normal(l->data, l->width, l->height, + image->data, image->width, image->height, + l->offset_x, l->offset_y); + break; + + default: + D("Unknown layer mode: %i. Skipping.\n", l->mode); + } + } + + lp = l->prev; + /* free the layer now, since it's not needed anymore */ + free_layer(l); + + l = lp; + layer_index++; + } + + /* We've used up all the layers now, so set them to NULL in the image: */ + image->layers = NULL; + image->last_layer = NULL; +} + + +static char +xcf_file_init(char* filename) +{ + char success = 1; + char id[14]; + + image->single_layer_index = -1; + /* + if ((suffix = strchr(filename, ':'))) + { + *suffix = '\0'; + image->single_layer_index = atoi(suffix+1); + D("Loading only XCF layer %i.\n", image->single_layer_index); + } + */ + image->fp = fopen (filename, "r"); + if (!image->fp) + return 0; + + image->filename = filename; + image->layers = NULL; + image->last_layer = NULL; + image->cmap = NULL; + image->num_cols = 0; + image->data = NULL; + + image->cp = 0; + + image->cp += xcf_read_int8 (image->fp, (DATA8*) id, 14); + if (strncmp (id, "gimp xcf ", 9) != 0) + { + success = 0; + fclose(image->fp); + } + else if (strcmp (id+9, "file") == 0) + { + image->file_version = 0; + } + else if (id[9] == 'v') + { + image->file_version = atoi(id + 10); + } + else + { + success = 0; + fclose(image->fp); + } + + return success; +} + + +static void +xcf_cleanup(void) +{ + Layer* l; + Layer* lp; + + fclose(image->fp); + + l = image->last_layer; + while (l) + { + lp = l->prev; + free_layer(l); + l = lp; + } + + if (image->cmap) + FREE(image->cmap); +} + +static void +xcf_to_imlib(ImlibImage *im) +{ + im->w = image->width; + im->h = image->height; + SET_FLAG(im->flags, F_HAS_ALPHA); + + im->data = (DATA32*)image->data; +} + + +char +load(ImlibImage *im, ImlibProgressFunction progress, char progress_granularity, char immediate_load) +{ + /* if immediate_load is 1, then dont delay image laoding as below, or */ + /* already data in this image - dont load it again */ + + if (im->data) + return 0; + + /* initialize */ + if (!xcf_file_init(im->real_file)) + return 0; + + /* set the format string member to the lower-case full extension */ + /* name for the format - so example names would be: */ + /* "png", "jpeg", "tiff", "ppm", "pgm", "pbm", "gif", "xpm" ... */ + if (!im->loader) + im->format = strdup("xcf"); + + /* do it! */ + xcf_load_image(); + + /* Now paste stuff into Imlib image */ + xcf_to_imlib(im); + + /* I want to ignore this for now, am I doing this right? --cK */ + if (progress) + { + progress(im, 100, 0, 0, im->w, im->h); + } + + /* cleanup */ + xcf_cleanup(); + + return 1; + + /* shut up warnings: */ + progress_granularity = 0; + immediate_load = 0; +} + +/* fills the ImlibLoader struct with a strign array of format file */ +/* extensions this loader can load. eg: */ +/* loader->formats = { "jpeg", "jpg"}; */ +/* giving permutations is a good idea. case sensitivity is irrelevant */ +/* your laoder CAN load more than one format if it likes - like: */ +/* loader->formats = { "gif", "png", "jpeg", "jpg"} */ +/* if it can load those formats. */ +void +formats (ImlibLoader *l) +{ + /* this is the only bit you have to change... */ + char *list_formats[] = + { "xcf" }; + + /* don't bother changing any of this - it just reads this in and sets */ + /* the struct values and makes copies */ + { + int i; + + l->num_formats = (sizeof(list_formats) / sizeof (char *)); + l->formats = malloc(sizeof(char *) * l->num_formats); + for (i = 0; i < l->num_formats; i++) + l->formats[i] = strdup(list_formats[i]); + } +} + diff --git a/src/modules/loaders/loader_xcf_pixelfuncs.c b/src/modules/loaders/loader_xcf_pixelfuncs.c new file mode 100644 index 0000000..0d7e3c3 --- /dev/null +++ b/src/modules/loaders/loader_xcf_pixelfuncs.c @@ -0,0 +1,757 @@ +/* + + -----------------------------[ XCF Loader ]----------------------------- + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include + +#include "common.h" +#include "image.h" +#include "color_values.h" + +#ifdef XCF_DBG +#define D(s) \ + { \ + printf s; \ + } +#else +#define D(s) +#endif + +#define RS R_VAL(src + s_idx) +#define GS G_VAL(src + s_idx) +#define BS B_VAL(src + s_idx) +#define AS A_VAL(src + s_idx) +#define RD R_VAL(dest + d_idx) +#define GD G_VAL(dest + d_idx) +#define BD B_VAL(dest + d_idx) +#define AD A_VAL(dest + d_idx) + +#define EPS 0.00001 +#define PI 3.141592654 +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define INT_MULT(a,b,t) ((t) = (a) * (b) + 0x80, ((((t) >> 8) + (t)) >> 8)) +#define LINEAR(x,y,w) ((w*y + x)*4) + +void +rgb_to_hls (DATA8 *red, DATA8 *green, DATA8 *blue) +{ + int r, g, b; + double h, l, s; + int min, max; + int delta; + + r = *red; + g = *green; + b = *blue; + + if (r > g) + { + max = MAX (r, b); + min = MIN (g, b); + } + else + { + max = MAX (g, b); + min = MIN (r, b); + } + + l = (max + min) / 2.0; + + if (max == min) + { + s = 0.0; + h = 0.0; + } + else + { + delta = (max - min); + + if (l < 128) + s = 255 * (double) delta / (double) (max + min); + else + s = 255 * (double) delta / (double) (511 - max - min); + + if (r == max) + h = (g - b) / (double) delta; + else if (g == max) + h = 2 + (b - r) / (double) delta; + else + h = 4 + (r - g) / (double) delta; + + h = h * 42.5; + + if (h < 0) + h += 255; + else if (h > 255) + h -= 255; + } + + *red = h; + *green = l; + *blue = s; +} + + +DATA8 +gimp_hls_value (double n1, double n2, double hue) +{ + double value; + + if (hue > 255) + hue -= 255; + else if (hue < 0) + hue += 255; + if (hue < 42.5) + value = n1 + (n2 - n1) * (hue / 42.5); + else if (hue < 127.5) + value = n2; + else if (hue < 170) + value = n1 + (n2 - n1) * ((170 - hue) / 42.5); + else + value = n1; + + return (DATA8) (value * 255); +} + + +void +hls_to_rgb (DATA8 *hue, DATA8 *lightness, DATA8 *saturation) +{ + double h, l, s; + double m1, m2; + + h = *hue; + l = *lightness; + s = *saturation; + + if (s == 0) + { + /* achromatic case */ + *hue = l; + *lightness = l; + *saturation = l; + } + else + { + if (l < 128) + m2 = (l * (255 + s)) / 65025.0; + else + m2 = (l + s - (l * s) / 255.0) / 255.0; + + m1 = (l / 127.5) - m2; + + /* chromatic case */ + *hue = gimp_hls_value (m1, m2, h + 85); + *lightness = gimp_hls_value (m1, m2, h); + *saturation = gimp_hls_value (m1, m2, h - 85); + } +} + + +void +rgb_to_hsv (DATA8 *red, DATA8 *green, DATA8 *blue) +{ + int r, g, b; + double h, s, v; + int min, max; + int delta; + + h = 0.0; + + r = *red; + g = *green; + b = *blue; + + if (r > g) + { + max = MAX (r, b); + min = MIN (g, b); + } + else + { + max = MAX (g, b); + min = MIN (r, b); + } + + v = max; + + if (max != 0) + s = ((max - min) * 255) / (double) max; + else + s = 0; + + if (s == 0) + h = 0; + else + { + delta = max - min; + if (r == max) + h = (g - b) / (double) delta; + else if (g == max) + h = 2 + (b - r) / (double) delta; + else if (b == max) + h = 4 + (r - g) / (double) delta; + h *= 42.5; + + if (h < 0) + h += 255; + if (h > 255) + h -= 255; + } + + *red = h; + *green = s; + *blue = v; +} + +void +hsv_to_rgb (DATA8 *hue, DATA8 *saturation, DATA8 *value) +{ + double h, s, v; + double f, p, q, t; + + if (*saturation == 0) + { + *hue = *value; + *saturation = *value; + *value = *value; + } + else + { + h = *hue * 6.0 / 255.0; + s = *saturation / 255.0; + v = *value / 255.0; + + f = h - (int) h; + p = v * (1.0 - s); + q = v * (1.0 - (s * f)); + t = v * (1.0 - (s * (1.0 - f))); + + switch ((int) h) + { + case 0: + *hue = v * 255; + *saturation = t * 255; + *value = p * 255; + break; + + case 1: + *hue = q * 255; + *saturation = v * 255; + *value = p * 255; + break; + + case 2: + *hue = p * 255; + *saturation = v * 255; + *value = t * 255; + break; + + case 3: + *hue = p * 255; + *saturation = q * 255; + *value = v * 255; + break; + + case 4: + *hue = t * 255; + *saturation = p * 255; + *value = v * 255; + break; + + case 5: + *hue = v * 255; + *saturation = p * 255; + *value = q * 255; + break; + } + } +} + +/* translate negative destinations */ +void _clip(int * src_tl_x, int * src_tl_y, + int * src_br_x, int * src_br_y, + int * dest_x, int * dest_y, + int dest_w, int dest_h) +{ + if (*dest_x + *src_br_x >= dest_w) + { *src_br_x -= (*dest_x + *src_br_x) - dest_w; } + + if (*dest_y + *src_br_y >= dest_h) + { *src_br_y -= (*dest_y + *src_br_y) - dest_h; } + + if (*dest_x < 0) + { + *src_tl_x = -(*dest_x); + *dest_x = 0; + } + if (*dest_y < 0) + { + *src_tl_y = -(*dest_y); + *dest_y = 0; + } +} + +void +combine_pixels_normal (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + int b; + unsigned char src_alpha; + unsigned char new_alpha; + float ratio, compl_ratio; + long tmp; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + src_alpha = AS; + + if (src_alpha != 0) + { + if (src_alpha == 255) + new_alpha = src_alpha; + else + new_alpha = AD + INT_MULT((255 - AD), src_alpha, tmp); + + b = 3; + if (new_alpha != 0) + { + ratio = (float) src_alpha / new_alpha; + compl_ratio = 1.0 - ratio; + + do + { + b--; + dest[d_idx + b] = + (unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPS); + } + while (b); + } + + AD = new_alpha; + } + } +} + + +void +combine_pixels_add (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + int tmp; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + tmp = RD + RS; + RD = (tmp > 255 ? 255 : tmp); + + tmp = GD + GS; + GD = (tmp > 255 ? 255 : tmp); + + tmp = BD + BS; + BD = (tmp > 255 ? 255 : tmp); + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_sub (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + int tmp; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + tmp = RD - RS; + RD = (tmp < 0 ? 0 : tmp); + + tmp = GD - GS; + GD = (tmp < 0 ? 0 : tmp); + + tmp = BD - BS; + BD = (tmp < 0 ? 0 : tmp); + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_diff (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + int tmp; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + tmp = RD - RS; + RD = (tmp < 0 ? -tmp : tmp); + + tmp = GD - GS; + GD = (tmp < 0 ? -tmp : tmp); + + tmp = BD - BS; + BD = (tmp < 0 ? -tmp : tmp); + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_darken (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + RD = MIN(RD, RS); + GD = MIN(GD, GS); + BD = MIN(BD, BS); + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_lighten (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + RD = MAX(RD, RS); + GD = MAX(GD, GS); + BD = MAX(BD, BS); + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_mult (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + int tmp; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + RS = INT_MULT(RS, RD, tmp); + GS = INT_MULT(GS, GD, tmp); + BS = INT_MULT(BS, BD, tmp); + + AS = MIN(AS, AD); + } + + combine_pixels_normal(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y); +} + + +void +combine_pixels_div (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + RS = MIN(255, ((float)RD / (RS + 1)) * 256); + GS = MIN(255, ((float)GD / (GS + 1)) * 256); + BS = MIN(255, ((float)BD / (BS + 1)) * 256); + + AS = MIN(AD, AS); + } + + combine_pixels_normal(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y); +} + + +void +combine_pixels_screen (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + RD = 255 - (((255 - RD) * (255 - RS)) >> 8); + GD = 255 - (((255 - GD) * (255 - GS)) >> 8); + BD = 255 - (((255 - BD) * (255 - BS)) >> 8); + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_overlay (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + int tmp_screen, tmp_mult; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + tmp_screen = 255 - (((255 - RD) * (255 - RS)) >> 8); + tmp_mult = (RD * RS) >> 8; + RD = (RD * tmp_screen + (255 - RD) * tmp_mult) >> 8; + + tmp_screen = 255 - (((255 - GD) * (255 - GS)) >> 8); + tmp_mult = (GD * GS) >> 8; + GD = (GD * tmp_screen + (255 - GD) * tmp_mult) >> 8; + + tmp_screen = 255 - (((255 - BD) * (255 - BS)) >> 8); + tmp_mult = (BD * BS) >> 8; + BD = (BD * tmp_screen + (255 - BD) * tmp_mult) >> 8; + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_hsv (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y, int mode) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + rgb_to_hsv(&RS, &GS, &BS); + rgb_to_hsv(&RD, &GD, &BD); + + switch (mode) + { + case 0: /* hue mode */ + RD = RS; + break; + case 1: /* saturation mode */ + GD = GS; + break; + case 2: /* value mode */ + BD = BS; + break; + default: + break; + } + + hsv_to_rgb(&RD, &GD, &BD); + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_hue (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 0); +} + + +void +combine_pixels_sat (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 1); +} + + +void +combine_pixels_val (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + combine_pixels_hsv(src, src_w, src_h, dest, dest_w, dest_h, dest_x, dest_y, 2); +} + + +void +combine_pixels_col (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + rgb_to_hls(&RS, &GS, &BS); + rgb_to_hls(&RD, &GD, &BD); + RD = RS; + BD = BS; + hls_to_rgb(&RD, &GD, &BD); + + AD = MIN(AD, AS); + } +} + + +void +combine_pixels_diss (DATA8* src, int src_w, int src_h, DATA8* dest, int dest_w, int dest_h, int dest_x, int dest_y) +{ + int x, y, s_idx, d_idx; + int src_tl_x = 0, src_tl_y = 0; + int src_br_x = src_w, src_br_y = src_h; + + srand(12345); + + _clip(&src_tl_x, &src_tl_y, &src_br_x, &src_br_y, &dest_x, &dest_y, dest_w, dest_h); + + for (y = src_tl_y; y < src_br_y; y++) + for (x = src_tl_x; x < src_br_x; x++) + { + d_idx = LINEAR((dest_x + x - src_tl_x), (dest_y + y - src_tl_y), dest_w); + s_idx = LINEAR(x, y, src_w); + + if ((rand() % 255) < AS) + { + int b; + unsigned char src_alpha; + unsigned char new_alpha; + float ratio, compl_ratio; + long tmp; + + src_alpha = AS; + + if (src_alpha != 0) + { + if (src_alpha == 255) + new_alpha = src_alpha; + else + new_alpha = AD + INT_MULT((255 - AD), src_alpha, tmp); + + b = 3; + if (new_alpha != 0) + { + ratio = (float) src_alpha / new_alpha; + compl_ratio = 1.0 - ratio; + + do + { + b--; + dest[d_idx + b] = + (unsigned char) (src[s_idx + b] * ratio + dest[d_idx + b] * compl_ratio + EPS); + } + while (b); + } + + AD = new_alpha; + } + } + } +}