├── .gitignore ├── ChangeLog ├── Makefile.in ├── README ├── TRANSLATION ├── config.guess ├── config.hin ├── config.rpath ├── config.sub ├── configure ├── configure.ac ├── dist-generated ├── exit.1i ├── flatspec.c ├── flatten.c ├── flatten.h ├── gimp ├── base-enums.h ├── gimpbaseenums.h └── xcf-private.h ├── install-sh ├── io-unix.c ├── mancombine.pl ├── manpo ├── .cvsignore ├── da.po ├── manpages.pot ├── mantranslate.pl └── optipot.pl ├── mkenumsc.pl ├── mkenumsh.pl ├── mkopti.pl ├── mktablec.pl ├── options.i ├── palette.c ├── palette.h ├── pixels.c ├── pixels.h ├── po ├── .cvsignore ├── da.po └── xcftools.pot ├── scaletab.c ├── test ├── Makefile ├── README ├── answer │ ├── Addition.png │ ├── Burn.png │ ├── Color.png │ ├── DarkenOnly.png │ ├── Difference.png │ ├── Divide.png │ ├── Dodge.png │ ├── GrainExtract.png │ ├── GrainMerge.png │ ├── Hardlight.png │ ├── Hue.png │ ├── LightenOnly.png │ ├── Multiply.png │ ├── Overlay.png │ ├── Saturation.png │ ├── Screen.png │ ├── Subtract.png │ ├── Value.png │ ├── burmid.png │ ├── comptest.png │ ├── comptestB.png │ ├── crisp1.png │ ├── crisp2.png │ ├── doodle.png │ ├── gray.png │ ├── huetest.png │ ├── i255t.png │ ├── i255tt.png │ ├── index255.png │ ├── index256.png │ ├── index4.png │ ├── indextest.png │ ├── masknoalpha-b.png │ ├── masknoalpha-g.png │ ├── masknoalpha-r.png │ ├── masknoalpha-w.png │ ├── mid.png │ ├── misc1.png │ ├── modeA.png │ ├── modeB.png │ ├── mono.png │ ├── mono1.png │ ├── odoodle.png │ ├── tiletest.png │ └── zlib.png ├── dotest ├── pngtype.pl └── source │ ├── badindexed0.xcf.gz │ ├── comptest.xcf.gz │ ├── huetest.xcf.gz │ ├── i255.xcf.gz │ ├── i256.xcf.gz │ ├── indextest.xcf.gz │ ├── masknoalpha.xcf.gz │ ├── mkbase.i │ ├── mkgradient256.pl │ ├── mkmodebase.c │ ├── mktile0.pl │ ├── mktile1.c │ ├── modetest.xcf.gz │ ├── tiletest-128.xcf.gz │ ├── tiletest-61.xcf.gz │ ├── tiletest.xcf.gz │ ├── truncated.xcf │ ├── wide-pointers.xcf.gz │ └── zlib.xcf.gz ├── utils.c ├── xcf-general.c ├── xcf2png.10 ├── xcf2png.c ├── xcf2pnm.10 ├── xcf2pnm.c ├── xcfinfo.10 ├── xcfinfo.c ├── xcfspec.txt ├── xcftools.h ├── xcftools.spec ├── xcfview.10 └── xcfview.in /.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | autom4te.cache 3 | config.h 4 | config.log 5 | config.status 6 | aclocal.m4 7 | enums.[ch] 8 | table.c 9 | nlsini.c 10 | xcfinfo 11 | xcf2pnm 12 | xcf2png 13 | xcfview 14 | xcf**.1i 15 | xcf*.1il 16 | *.1 17 | xcf*.oi 18 | options.mi 19 | *.o 20 | *~ 21 | 22 | manpo/all 23 | manpo/stamp 24 | 25 | po/*.mo 26 | po/stamp 27 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2009-07-03 Henning Makholm 2 | 3 | * Version 1.0.7 4 | * Fix GPL-to-PD transition: missed copyrigh blurb in online banner. 5 | 6 | 2009-07-03 Henning Makholm 7 | 8 | * Version 1.0.6 9 | * Change licensing from GPL-2 to PD. 10 | * Fix bug: A layer without an alpha channel bug with an active 11 | layer mask was wrongly considered to obscure all lower layers. 12 | * Fix bug: xcf2pnm would guess PBM as the output format even if 13 | the background was explicitly set to an intermediate gray, or 14 | if -T might produce grays. 15 | 16 | 2009-07-02 Henning Makholm 17 | 18 | * Version 1.0.5 19 | * Fix various bugs if extracted part of image contains pixels with 20 | negative canvas-based coordinates. Thanks to J\"orgen Grahn for 21 | reporting these. (Debian bug #533361). 22 | * One of the fixed bugs was a buffer overrun which would allow a 23 | remote attacker to execute arbitrary if he could trick a user 24 | into converting an appropriately crafted XCF file with either 25 | the -C or the -O option. CVE-2009-2175. 26 | * Fix another bug with interpretation of -C flag, which would 27 | convert the *intersection* of the visible layers rather than 28 | their *union*, as intended. Did I ever test this stuff? 29 | * Minor manpage fixes; -C description should be less confusing now. 30 | * Apply patch from Marcus Alanen for easier RPM packaging: 31 | $(DESTDIR) honored in Makefile's install target, spec file added. 32 | 33 | 2006-05-14 Henning Makholm 34 | 35 | * Version 1.0.4 36 | * Work around bug in certain older Gimp releases that would 37 | save the wrong length word of a Colormap property. 38 | 39 | 2006-04-17 Henning Makholm 40 | 41 | * Version 1.0.3 42 | * Also look for color name database in other locations than 43 | /usr/lib/X11, in an attempty to be X11R7 friendly 44 | 45 | 2006-02-22 Henning Makholm 46 | 47 | * Version 1.0.2 48 | * Don't ship aclocal.m4 in tarball; it will be re-assembled 49 | whenever needed anyway. 50 | * Add option -C to autocrop to visible layers, suggested 51 | by Anthony DeRobertis (Debian bug #353883). 52 | * Change metavariable for -Z option argument from "cmd" 53 | to "command", following suggestion by Anthony DeRobertis 54 | (Debian bug #353872). 55 | 56 | 2006-02-20 Henning Makholm 57 | 58 | * Version 1.0.1 59 | * Make sure that -b with an unknown color actually leads to 60 | a fatal error when the X11 color name database is not found. 61 | 62 | * Version 1.0 63 | * xcfview added 64 | * Support for translated manpages added 65 | 66 | 2006-02-13 Henning Makholm 67 | 68 | * Version 0.9.1 69 | * Experimental l10n support added 70 | 71 | 2006-02-12 Henning Makholm 72 | 73 | * Version 0.9 74 | * Add layer mode Color. Now all of the Gimp's layer modes are 75 | supported. :-) 76 | * Revamp the test suite inputs once again (they did not cover all 77 | combinations of colored pixels vs fully white or blacK). 78 | 79 | * Version 0.8.1 80 | * Add layer modes Hue, Value, Saturation and tests for same. 81 | 82 | 2006-02-11 Henning Makholm 83 | 84 | * Version 0.8 85 | * Add tests of various error diagnostics to the test suite 86 | * Revamp some of the test suite inputs such that HSV space 87 | layer modes can be tested with the same files. 88 | 89 | * Version 0.7.2 90 | * Do not precompute the big multiplication table by default, 91 | it is quick enough to do it at run-time as needed (which 92 | lets the binaries shrink significantly). 93 | 94 | 2006-02-07 Henning Makholm 95 | 96 | * Respect -A option when generating indexed PNG (that is, 97 | create a tRNS chunk even if it's trivial); add test of 98 | -A in xcf2png to the test suite. 99 | 100 | 2006-01-29 Henning Makholm 101 | 102 | * Update FSF address in GPL blurbs 103 | 104 | * Version 0.7.1 105 | * A few cosmetic changes done during debianization 106 | * The code now passes the testsuite on several Debian 107 | architectures (powerpc, alpha, ia64, amd64, hppa, 108 | sparc, mipsel, m68k). Unfortunately I lack the 109 | access to test on non-Debian platforms. 110 | 111 | 2006-01-28 Henning Makholm 112 | 113 | * Version 0.7 114 | * xcf2png added 115 | * Test suite added 116 | * Various bug fixes 117 | 118 | 2006-01-24 Henning Makholm 119 | 120 | * Version 0.6 121 | * Allow X11 color names with -b option 122 | 123 | 2006-01-22 Henning Makholm 124 | 125 | * Version 0.5 126 | * First public release 127 | - xcfinfo 128 | - xcf2pnm 129 | -------------------------------------------------------------------------------- /Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile(.in) for xcftools 2 | # This file was written by Henning Makholm 3 | # It is hereby in the public domain. 4 | # 5 | # In jurisdictions that do not recognise grants of copyright to the 6 | # public domain: I, the author and (presumably, in those jurisdictions) 7 | # copyright holder, hereby permit anyone to distribute and use this code, 8 | # in source code or binary form, with or without modifications. This 9 | # permission is world-wide and irrevocable. 10 | # 11 | # Of course, I will not be liable for any errors or shortcomings in the 12 | # code, since I give it away without asking any compenstations. 13 | # 14 | # If you use or distribute this code, I would appreciate receiving 15 | # credit for writing it, in whichever way you find proper and customary. 16 | 17 | all: 18 | 19 | datarootdir = @datarootdir@ 20 | srcdir = @srcdir@ 21 | prefix = @prefix@ 22 | exec_prefix = @exec_prefix@ 23 | bindir = @bindir@ 24 | mandir = @mandir@ 25 | datadir = @datadir@ 26 | sysconfdir = @sysconfdir@ 27 | localedir = $(datadir)/locale 28 | 29 | VERSION = @PACKAGE_VERSION@ 30 | APPNAME = @PACKAGE_TARNAME@ 31 | program_transform_name = @program_transform_name@ 32 | 33 | CC = @CC@ 34 | CFLAGS = @CFLAGS@ 35 | LDFLAGS = @LDFLAGS@ @LIBICONV@ 36 | LIBS = @LIBS@ 37 | 38 | INSTALL = @INSTALL@ -D 39 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 40 | INSTALL_DATA = @INSTALL_DATA@ 41 | 42 | RM = rm -f 43 | SED = sed 44 | PERL = @PERL@ 45 | 46 | o = @OBJEXT@ 47 | e = @EXEEXT@ 48 | 49 | # Allow using Makefile.in directly for cleaning and distmaking purposes 50 | ifneq (,$(findstring @,$o)) 51 | e = 52 | srcdir = . 53 | endif 54 | 55 | ############################################################################# 56 | 57 | FILEIO = io-unix 58 | 59 | BINARIES = xcfinfo$e xcf2pnm$e xcf2png$e xcfview 60 | COMMANDS = $(patsubst %$e,%,$(BINARIES)) 61 | MANPAGES = $(patsubst %,%.1,$(COMMANDS)) 62 | 63 | ifeq (@USE_NLS@,yes) 64 | LINGUAS = da 65 | MANLINGUAS = da 66 | endif 67 | 68 | %.$o: %.c 69 | $(CC) $(CFLAGS) -o $@ -c $< 70 | 71 | 72 | all: $(BINARIES) $(SCRIPTS) $(MANPAGES) po/stamp manpo/all 73 | 74 | xcfinfo$e: xcfinfo.$o $(FILEIO).$o enums.$o xcf-general.$o utils.$o nlsini.$o 75 | $(CC) $(LDFLAGS) $^ -o $@ $(LIBS) 76 | 77 | xcf2pnm$e: xcf2pnm.$o $(FILEIO).$o enums.$o xcf-general.$o utils.$o nlsini.$o \ 78 | pixels.$o flatten.$o flatspec.$o scaletab.$o table.$o 79 | $(CC) $(LDFLAGS) $^ -o $@ $(LIBS) -lz 80 | 81 | xcf2png$e: xcf2png.$o $(FILEIO).$o enums.$o xcf-general.$o utils.$o nlsini.$o \ 82 | pixels.$o flatten.$o flatspec.$o scaletab.$o table.$o palette.$o 83 | $(CC) $(LDFLAGS) $^ -o $@ $(LIBS) -lpng -lz 84 | 85 | xcfview: xcfview.in Makefile 86 | sed '1s,/usr/bin/perl,@PERL@,' < $< > $@ 87 | 88 | testscale$e: testscale.$o 89 | $(CC) $(LDFLAGS) $^ -o $@ $(LIBS) 90 | 91 | install: all 92 | for p in $(BINARIES) ; do \ 93 | case $$p in xcfview) strip= ;; *) strip=-s ;; esac ; \ 94 | $(INSTALL_PROGRAM) $$strip $$p \ 95 | $(DESTDIR)$(bindir)/`echo $$p | $(SED) $(program_transform_name)` \ 96 | || exit 1 ;\ 97 | done 98 | for m in $(MANPAGES) ; do \ 99 | $(INSTALL_DATA) $$m \ 100 | $(DESTDIR)$(mandir)/man1/`echo $$m | $(SED) $(program_transform_name)` \ 101 | || exit 1 ; \ 102 | done 103 | for lang in $(LINGUAS) ; do \ 104 | $(srcdir)/install-sh -d $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES ; \ 105 | $(INSTALL_DATA) po/$$lang.mo \ 106 | $(DESTDIR)$(localedir)/$$lang/LC_MESSAGES/$(APPNAME).mo \ 107 | || exit 1 ; \ 108 | done 109 | for L in $(MANLINGUAS) ; do \ 110 | $(srcdir)/install-sh -d $(DESTDIR)$(mandir)/$$L/man1 || exit 1 ; \ 111 | for P in $(patsubst %.1,%,$(MANPAGES)) ; do \ 112 | $(INSTALL_DATA) manpo/$$P.$$L.1 $(DESTDIR)$(mandir)/$$L/man1/$$P.1 \ 113 | || exit 1; done ; done ; 114 | 115 | C_GENERATED = enums.c table.c nlsini.c 116 | 117 | ENUMSOURCES = gimp/base-enums.h gimp/gimpbaseenums.h gimp/xcf-private.h 118 | enums.h: mkenumsh.pl $(ENUMSOURCES) 119 | $(PERL) $< $(ENUMSOURCES) > $@ 120 | enums.c: mkenumsc.pl enums.h 121 | $(PERL) $< enums.h > $@ 122 | table.c: mktablec.pl config.h 123 | $(PERL) $< > $@ 124 | nlsini.c: Makefile 125 | echo >$@ "#include \"xcftools.h\"" 126 | echo >>$@ "#ifndef nls_init" 127 | echo >>$@ "void nls_init(void) {" 128 | echo >>$@ " bindtextdomain(\"$(APPNAME)\",\"$(localedir)\");" 129 | echo >>$@ " textdomain(\"$(APPNAME)\"); }" 130 | echo >>$@ "#endif" 131 | 132 | %.oi: options.i mkopti.pl config.h 133 | $(PERL) mkopti.pl $* 134 | 135 | %.1: %.oi %.10 config.h mancombine.pl 136 | $(PERL) mancombine.pl $*.10 > $@ 137 | 138 | ############################################################################# 139 | # 140 | # Localization stuff 141 | 142 | POTFILES_NONC = $(patsubst %$e,%.oi,$(BINARIES)) options.i 143 | 144 | po/$(APPNAME).pot$(SUPPRESS_AUTOFOO): $(POTFILES_NONC) \ 145 | $(filter-out table.c nlsini.c, $(C_GENERATED) $(wildcard *.c)) 146 | xgettext -o $@.tmp -C -k_ -kN_ \ 147 | --foreign-user --msgid-bugs-address=henning@makholm.net \ 148 | --flag=FatalGeneric:2:c-format \ 149 | --flag=FatalUnexpected:1:c-format \ 150 | --flag=FatalBadXCF:1:c-format \ 151 | --flag=FatalUnsupportedXCF:1:c-format \ 152 | $^ 153 | if diff $@ $@.tmp | \ 154 | grep -v '^\([^<>]\|. \?"POT-Creation-Date:\)' > /dev/null; \ 155 | then mv -f $@.tmp $@ ; \ 156 | else echo OK, $@ is unchanged ; rm $@.tmp ; fi 157 | 158 | po/%.po: po/$(APPNAME).pot 159 | test -f $@ 160 | msgmerge -U $@ $< 161 | touch $@ 162 | 163 | po/%.mo: po/%.po 164 | msgfmt -c -o$@ $< 165 | 166 | po/stamp: $(patsubst %,po/%.mo,$(LINGUAS)) 167 | if ! make -q po/$(APPNAME).pot ; then \ 168 | touch po/$(APPNAME).pot ; touch po/*.po ; touch po/*.mo ; fi 169 | touch $@ 170 | 171 | # Manpage localization stuff 172 | 173 | POTFILES_MAN = options.mi $(patsubst %.1,%.10,$(MANPAGES)) \ 174 | exit.1i 175 | 176 | options.mi: manpo/optipot.pl options.i 177 | $(PERL) manpo/optipot.pl > $@ 178 | manpo/manpages.pot$(SUPPRESS_AUTOFOO): manpo/mantranslate.pl $(POTFILES_MAN) 179 | $(PERL) manpo/mantranslate.pl -x $(POTFILES_MAN) > $@.tmp 180 | if diff $@ $@.tmp | \ 181 | grep -v '^\([^<>]\|. \?"POT-Creation-Date:\)' > /dev/null; \ 182 | then mv -f $@.tmp $@ ; \ 183 | else echo OK, $@ is unchanged ; rm $@.tmp ; fi 184 | 185 | manpo/%.po: manpo/manpages.pot 186 | test -f $@ 187 | msgmerge -U $@ $< 188 | touch $@ 189 | 190 | manpo/stamp: $(patsubst %,manpo/%.po,$(MANLINGUAS)) 191 | if ! make -q manpo/manpages.pot ; then \ 192 | touch manpo/manpages.pot ; touch $^ ; fi 193 | touch $@ 194 | 195 | manpo/all: manpo/stamp $(MANPAGES) 196 | for L in $(MANLINGUAS) ; do \ 197 | for P in $(patsubst %.1,%,$(MANPAGES)) ; do \ 198 | $(PERL) manpo/mantranslate.pl manpo/$$L.po $$P.1 \ 199 | > manpo/$$P.$$L.1 || exit 1; done ; done ; 200 | touch $@ 201 | 202 | ############################################################################# 203 | # 204 | # Dependency tracking, by hand 205 | 206 | COMMON_HEADERS = xcftools.h config.h enums.h 207 | enums.$o: enums.h 208 | nlsini.$o: $(COMMON_HEADERS) 209 | table.$o: $(COMMON_HEADERS) pixels.h 210 | scaletab.$o: $(COMMON_HEADERS) pixels.h 211 | io-unix.$o: $(COMMON_HEADERS) 212 | xcf-general.$o: $(COMMON_HEADERS) 213 | utils.$o: $(COMMON_HEADERS) 214 | pixels.$o: $(COMMON_HEADERS) pixels.h 215 | palette.$o: $(COMMON_HEADERS) pixels.h flatten.h palette.h 216 | flatten.$o: $(COMMON_HEADERS) pixels.h flatten.h 217 | flatspec.$o: $(COMMON_HEADERS) pixels.h flatten.h 218 | xcfinfo.$o: $(COMMON_HEADERS) xcfinfo.oi 219 | xcf2pnm.$o: $(COMMON_HEADERS) pixels.h flatten.h xcf2pnm.oi 220 | xcf2png.$o: $(COMMON_HEADERS) pixels.h flatten.h xcf2png.oi palette.h 221 | 222 | ############################################################################# 223 | # 224 | # Standard cleaning and other metarules 225 | 226 | check: $(BINARIES) 227 | cd test && $(MAKE) check 228 | 229 | clean: 230 | $(RM) *.$o */*~ *~ .*~ xcf*.1i xcf*.1il *.1 *.oi *.mi 231 | $(RM) enums.h $(C_GENERATED) $(BINARIES) 232 | $(RM) po/*.mo */stamp manpo/all manpo/*.1 233 | cd test && $(MAKE) clean 234 | 235 | distclean: clean 236 | $(RM) Makefile config.log config.cache config.status config.h 237 | $(RM) aclocal.m4 238 | $(RM) -r autom4te.cache 239 | 240 | realclean: distclean 241 | $(RM) configure config.hin 242 | 243 | .SUFFIXES: .c .$o 244 | 245 | .PHONY: clean distclean realclean dist all 246 | 247 | ############################################################################# 248 | # 249 | # Tarball-making rule 250 | 251 | ifeq (,$(findstring @,$o)) 252 | dist: ajour $(patsubst %,po/%.po,$(LINGUAS)) 253 | $(MAKE) distclean 254 | noncvs > notcvsfiles || cp dist-generated notcvsfiles 255 | diff -u dist-generated notcvsfiles 256 | $(RM) notcvsfiles 257 | find . -type f -print | grep -v CVS | grep -v debian | \ 258 | sed 's!^\./!$(APPNAME)-$(VERSION)/!' | sort -o tar-manifest 259 | ln -s . $(APPNAME)-$(VERSION) 260 | GZIP=-9 tar cvzf $(APPNAME)-$(VERSION).tar.gz `cat tar-manifest` 261 | rm tar-manifest 262 | rm $(APPNAME)-$(VERSION) 263 | else 264 | dist: ajour 265 | $(MAKE) dist 266 | endif 267 | 268 | 269 | ############################################################################# 270 | # 271 | # Autofoo rules: 272 | 273 | $(srcdir)/configure$(SUPPRESS_AUTOFOO): configure.ac 274 | cd $(srcdir) && aclocal 275 | cd $(srcdir) && autoconf 276 | cd $(srcdir) && autoheader 277 | 278 | $(srcdir)/config.hin$(SUPPRESS_AUTOFOO): $(srcdir)/configure 279 | 280 | config.status: $(srcdir)/configure config.sub config.guess 281 | if [ -f config.status ] ; \ 282 | then ./config.status --recheck ; \ 283 | else ./configure ; fi 284 | 285 | Makefile$(SUPPRESS_AUTOFOO): Makefile.in config.status 286 | ./config.status $@ 287 | 288 | config.h: config.hin config.status 289 | ./config.status $@ 290 | touch $@ 291 | 292 | ajour: Makefile config.h 293 | 294 | config.sub config.guess: 295 | -test -r /usr/share/misc/$@ && cp /usr/share/misc/$@ . 296 | 297 | .PHONY: ajour dist 298 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | What is this? 2 | ============= 3 | 4 | Xcftools is a set of fast command-line tools for extracting 5 | information from the Gimp's native file format XCF. The tools 6 | are designed to allow efficient use of layered XCF files as 7 | sources in a build system that use 'make' and similar tools 8 | to manage automatic processing of the graphics. These tools 9 | work independently of the Gimp engine and do not require the 10 | Gimp to even be installed. 11 | 12 | xcf2pnm converts XCF files to ppm, pgm or pbm format, 13 | flattening layers if necessary. If the image 14 | contains transparency, an alpha map can be written 15 | to a separate file, or a background color can be 16 | specified on the command line. 17 | 18 | xcf2png converts XCF files to PNG format, flattening 19 | layers if necessary. Transparency information 20 | can be kept in the image, or a background color 21 | can be specified on the command line. 22 | 23 | xcfinfo lists information about layers in an XCF file. 24 | 25 | The tools can either flatten an XCF file as given, or extract specific 26 | layers named on the command line. 27 | 28 | Portability 29 | =========== 30 | 31 | The software was developed on an Intel-based PC running Debian 32 | GNU/Linux. It ought to work on other Linux variants also. I would 33 | not be surprised if it ran on other unix systems too, but porting 34 | to non-unix platforms will require some work. Most of the code 35 | attempts to be prepared for porting, but this has not been 36 | explicitly tested. 37 | 38 | Installation 39 | ============ 40 | 41 | You need GNU make, a C compiler, and perl. 42 | 43 | After the source archive is extracted, the command sequence 44 | ./configure 45 | make all 46 | make install 47 | should compile the tools and install them in /usr/local. 48 | 49 | The 'configure' script is generated by GNU autoconf, and accepts 50 | the arguments that such scripts commonly do. 51 | 52 | You can use 53 | ./configure --enable-precomputed-scaletable 54 | to precompute lookup tables for pixel composing at compile time. 55 | Normally these tables are initialized at run time if a layer that 56 | needs them is detected. Precomputing them may improve performance 57 | by a few percent, at the cost of doubling the size of each binary. 58 | 59 | License 60 | ======= 61 | 62 | Xcftools is written by Henning Makholm 63 | It is hereby in the public domain. 64 | 65 | In jurisdictions that do not recognise grants of copyright to the 66 | public domain: I, the author and (presumably, in those jurisdictions) 67 | copyright holder, hereby permit anyone to distribute and use this code, 68 | in source code or binary form, with or without modifications. This 69 | permission is world-wide and irrevocable. 70 | 71 | Of course, I will not be liable for any errors or shortcomings in the 72 | code, since I give it away without asking any compenstations. 73 | 74 | If you use or distribute this code, I would appreciate receiving 75 | credit for writing it, in whichever way you find proper and customary. 76 | -------------------------------------------------------------------------------- /TRANSLATION: -------------------------------------------------------------------------------- 1 | The run-time messages from the program can be localized using standard 2 | GNU gettext tools in the po/ directory. There is no Makefile in po/; 3 | the processing is governed by the main Makefile in the top 4 | directory. Simply use 5 | make po/xcftools.pot 6 | to update the pot file if necessary. 7 | 8 | After creating a po file, add the language code to the definition of 9 | LINGUAS in the master Makefile.in. 10 | 11 | The manpo/ directory contains some experimental support for 12 | translating the manpages. Because much text is shared between the 13 | various manpages, the translation is done by po files, a few sentences 14 | at a time, and finished translated manpages are collected at build 15 | time. 16 | 17 | Note that the manpo/*.po files are parsed by a very ad-hoc parser in 18 | manpo/mantranslate.pl rather than by the standard gettext support 19 | programs. In particular, the "fuzzy" flag does not prevent an entry 20 | from being used. Also there is no charset handling, so the po files 21 | should be written with the same character set as should be used in the 22 | roff source of the combined man page. 23 | 24 | After writing a po file, add the language code to the definition 25 | of MANLINGUAS in the master Makefile.in. 26 | -------------------------------------------------------------------------------- /config.hin: -------------------------------------------------------------------------------- 1 | /* config.hin. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define if building universal (internal helper macro) */ 4 | #undef AC_APPLE_UNIVERSAL_BUILD 5 | 6 | /* Define for CPUs that can read unaligned words without traps or faults */ 7 | #undef CAN_DO_UNALIGNED_WORDS 8 | 9 | /* Define to 1 if translation of program messages to the user's native 10 | language is requested. */ 11 | #undef ENABLE_NLS 12 | 13 | /* Define to 1 if you have the header file. */ 14 | #undef HAVE_ARPA_INET_H 15 | 16 | /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the 17 | CoreFoundation framework. */ 18 | #undef HAVE_CFLOCALECOPYCURRENT 19 | 20 | /* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in 21 | the CoreFoundation framework. */ 22 | #undef HAVE_CFPREFERENCESCOPYAPPVALUE 23 | 24 | /* Define if the GNU dcgettext() function is already present or preinstalled. 25 | */ 26 | #undef HAVE_DCGETTEXT 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #undef HAVE_GETOPT_H 30 | 31 | /* Define to 1 if you have the `getopt_long' function. */ 32 | #undef HAVE_GETOPT_LONG 33 | 34 | /* Define to 1 if you have the `getpagesize' function. */ 35 | #undef HAVE_GETPAGESIZE 36 | 37 | /* Define if the GNU gettext() function is already present or preinstalled. */ 38 | #undef HAVE_GETTEXT 39 | 40 | /* Define if you have the iconv() function and it works. */ 41 | #undef HAVE_ICONV 42 | 43 | /* Define to 1 if you have the header file. */ 44 | #undef HAVE_INTTYPES_H 45 | 46 | /* Define to 1 if you have the header file. */ 47 | #undef HAVE_MEMORY_H 48 | 49 | /* Define to 1 if you have a working `mmap' system call. */ 50 | #undef HAVE_MMAP 51 | 52 | /* Define to 1 if you have the header file. */ 53 | #undef HAVE_NETINET_IN_H 54 | 55 | /* Define to 1 if you have the header file. */ 56 | #undef HAVE_STDINT_H 57 | 58 | /* Define to 1 if you have the header file. */ 59 | #undef HAVE_STDLIB_H 60 | 61 | /* Define to 1 if you have the `strcasecmp' function. */ 62 | #undef HAVE_STRCASECMP 63 | 64 | /* Define to 1 if you have the header file. */ 65 | #undef HAVE_STRINGS_H 66 | 67 | /* Define to 1 if you have the header file. */ 68 | #undef HAVE_STRING_H 69 | 70 | /* Define to 1 if you have the header file. */ 71 | #undef HAVE_SYS_STAT_H 72 | 73 | /* Define to 1 if you have the header file. */ 74 | #undef HAVE_SYS_TYPES_H 75 | 76 | /* Define to 1 if you have the header file. */ 77 | #undef HAVE_UNISTD_H 78 | 79 | /* Define as const if the declaration of iconv() needs const. */ 80 | #undef ICONV_CONST 81 | 82 | /* Define to the address where bug reports for this package should be sent. */ 83 | #undef PACKAGE_BUGREPORT 84 | 85 | /* Define to the full name of this package. */ 86 | #undef PACKAGE_NAME 87 | 88 | /* Define to the full name and version of this package. */ 89 | #undef PACKAGE_STRING 90 | 91 | /* Define to the one symbol short name of this package. */ 92 | #undef PACKAGE_TARNAME 93 | 94 | /* Define to the version of this package. */ 95 | #undef PACKAGE_VERSION 96 | 97 | /* Define to use a precomputed multiplication table (adds 64 KB per binary) */ 98 | #undef PRECOMPUTED_SCALETABLE 99 | 100 | /* Define to 1 if you have the ANSI C header files. */ 101 | #undef STDC_HEADERS 102 | 103 | /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most 104 | significant byte first (like Motorola and SPARC, unlike Intel). */ 105 | #if defined AC_APPLE_UNIVERSAL_BUILD 106 | # if defined __BIG_ENDIAN__ 107 | # define WORDS_BIGENDIAN 1 108 | # endif 109 | #else 110 | # ifndef WORDS_BIGENDIAN 111 | # undef WORDS_BIGENDIAN 112 | # endif 113 | #endif 114 | 115 | /* Define to `__inline__' or `__inline' if that's what the C compiler 116 | calls it, or to nothing if 'inline' is not supported under any name. */ 117 | #ifndef __cplusplus 118 | #undef inline 119 | #endif 120 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Configure script for xcftools 2 | dnl 3 | dnl This file was written by Henning Makholm 4 | dnl It is hereby in the public domain. 5 | dnl 6 | dnl In jurisdictions that do not recognise grants of copyright to the 7 | dnl public domain: I, the author and (presumably, in those jurisdictions) 8 | dnl copyright holder, hereby permit anyone to distribute and use this code, 9 | dnl in source code or binary form, with or without modifications. This 10 | dnl permission is world-wide and irrevocable. 11 | dnl 12 | dnl Of course, I will not be liable for any errors or shortcomings in the 13 | dnl code, since I give it away without asking any compenstations. 14 | dnl 15 | dnl If you use or distribute this code, I would appreciate receiving 16 | dnl credit for writing it, in whichever way you find proper and customary. 17 | dnl 18 | dnl ------------------------ 19 | dnl The following line is the MASTER SOURCE for the version number 20 | AC_INIT(Xcftools,1.0.7,henning@makholm.net,xcftools) 21 | AC_CONFIG_SRCDIR(xcfinfo.c) 22 | 23 | AC_PROG_INSTALL 24 | AC_ARG_PROGRAM 25 | 26 | AC_ARG_ENABLE(precomputed-scaletable, 27 | AC_HELP_STRING([--enable-precomputed-scaletable], 28 | [Use precomputed multiplication table (adds 64 KB per binary)]), 29 | [AC_DEFINE(PRECOMPUTED_SCALETABLE,1, 30 | [Define to use a precomputed multiplication table (adds 64 KB per binary)] 31 | )]) 32 | 33 | AC_PROG_CC 34 | case $GCC::$CFLAGS in yes::*-Wall* ) ;; 35 | yes::*) CFLAGS="$CFLAGS -Wall" ;; 36 | esac 37 | case $GCC::$CFLAGS in *-g* | *omit-frame-pointer* ) ;; 38 | yes::*) CFLAGS="$CFLAGS -fomit-frame-pointer" ;; 39 | esac 40 | AC_C_INLINE 41 | 42 | AC_C_BIGENDIAN 43 | AC_CANONICAL_HOST 44 | case $host_cpu in i?86 | x86_64 | powerpc) 45 | AC_DEFINE(CAN_DO_UNALIGNED_WORDS,1, 46 | [Define for CPUs that can read unaligned words without traps or faults]) 47 | esac 48 | AC_CHECK_HEADERS(inttypes.h netinet/in.h arpa/inet.h getopt.h) 49 | 50 | AC_CHECK_FUNCS(getopt_long strcasecmp) 51 | AC_FUNC_MMAP 52 | AM_GNU_GETTEXT(external) 53 | AM_ICONV 54 | 55 | AC_PATH_PROG(PERL,perl,perl) 56 | 57 | AC_CONFIG_HEADERS(config.h:config.hin) 58 | AC_CONFIG_FILES(Makefile:Makefile.in) 59 | AC_OUTPUT 60 | -------------------------------------------------------------------------------- /dist-generated: -------------------------------------------------------------------------------- 1 | config.guess 2 | config.hin 3 | config.sub 4 | configure 5 | notcvsfiles 6 | -------------------------------------------------------------------------------- /exit.1i: -------------------------------------------------------------------------------- 1 | .SH EXIT STATUS 2 | The exit status of 3 | .B \*p 4 | is 5 | .TP 5 6 | 0 7 | Success 8 | .TP 9 | 20 10 | #ifdef XCF2FOO 11 | Problems parsing the command line, including unknown color names 12 | (or missing color name directory) for 13 | .BR \-b . 14 | #else 15 | Problems parsing the command line. 16 | #endif 17 | .TP 18 | 21 19 | The specified XCF file does not exist or cannot be read. 20 | #ifdef XCF2FOO 21 | .TP 22 | 22 23 | A layer named on the command line was not found, or the 24 | .B --mask 25 | option was used for a layer that has no layer mask. 26 | #ifdef XCF2PNM 27 | .TP 28 | 100 29 | Transparent pixels were found, but neither 30 | .B \-a 31 | nor 32 | .B \-b 33 | was given. 34 | .TP 35 | 101 36 | The 37 | .B \-a 38 | option was given yet the image has no transparency. 39 | (Use 40 | .B \-A 41 | to go on anyway). 42 | #endif 43 | .TP 44 | 102 45 | The 46 | .B \-G 47 | option was given, yet partial transparency was found. 48 | .TP 49 | 103 50 | #ifdef XCF2PNM 51 | .B \-g 52 | (or 53 | .BR \-m ) 54 | was given, yet colored (or gray) pixels were found. 55 | #else 56 | .B \-g 57 | was given, yet colored pixels were found. 58 | #endif 59 | #endif 60 | .TP 61 | 123 62 | The XCF file contains presumably valid features that 63 | .B xcftools 64 | does not support. 65 | (As of this writing there is no known way of getting the Gimp to write 66 | an XCF file that will provoke this return. Please notify the author if you 67 | discover one). 68 | .TP 69 | 125 70 | The XCF file is malformed. 71 | .TP 72 | 126 73 | An uncompression program could not be executed, or terminated 74 | abnormally. 75 | .TP 76 | 127 77 | Unexpected I/O error, internal errors, or other "this can't happen" 78 | situations. 79 | .P 80 | If an uncompression program returns an error exit status, this will 81 | be returned from 82 | .B \*p 83 | too. 84 | -------------------------------------------------------------------------------- /flatspec.c: -------------------------------------------------------------------------------- 1 | /* Flattening selections function for xcftools 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "xcftools.h" 20 | #include "flatten.h" 21 | #include 22 | #include 23 | 24 | void 25 | init_flatspec(struct FlattenSpec *spec) 26 | { 27 | spec->window_mode = USE_CANVAS ; 28 | spec->default_pixel = PERHAPS_ALPHA_CHANNEL ; 29 | spec->numLayers = 0 ; 30 | spec->layers = NULL ; 31 | spec->transmap_filename = NULL ; 32 | spec->output_filename = "-" ; 33 | spec->out_color_mode = COLOR_BY_CONTENTS ; 34 | spec->partial_transparency_mode = ALLOW_PARTIAL_TRANSPARENCY ; 35 | spec->process_in_memory = 0 ; 36 | spec->gimpish_indexed = 1 ; 37 | } 38 | 39 | void 40 | add_layer_request(struct FlattenSpec *spec, const char *layer) 41 | { 42 | spec->layers = realloc(spec->layers, 43 | sizeof(struct xcfLayer) * (1+spec->numLayers)); 44 | if( spec->layers == NULL ) 45 | FatalUnexpected(_("Out of memory")); 46 | spec->layers[spec->numLayers].name = layer ; 47 | spec->layers[spec->numLayers].mode = (GimpLayerModeEffects)-1 ; 48 | spec->layers[spec->numLayers].opacity = 9999 ; 49 | spec->layers[spec->numLayers].hasMask = -1 ; 50 | spec->numLayers++ ; 51 | } 52 | 53 | struct xcfLayer * 54 | lastlayerspec(struct FlattenSpec *spec,const char *option) 55 | { 56 | if( spec->numLayers == 0 ) 57 | FatalGeneric(20,_("The %s option must follow a layer name on the " 58 | "command line"),option); 59 | return spec->layers + (spec->numLayers-1) ; 60 | } 61 | 62 | static int 63 | typeHasTransparency(GimpImageType type) 64 | { 65 | switch( type ) { 66 | case GIMP_RGB_IMAGE: 67 | case GIMP_GRAY_IMAGE: 68 | case GIMP_INDEXED_IMAGE: 69 | return 0 ; 70 | case GIMP_RGBA_IMAGE: 71 | case GIMP_GRAYA_IMAGE: 72 | case GIMP_INDEXEDA_IMAGE: 73 | return 1 ; 74 | } 75 | return 1 ; 76 | } 77 | 78 | static enum out_color_mode 79 | color_by_layers(struct FlattenSpec *spec) 80 | { 81 | int colormap_is_colored = 0 ; 82 | enum out_color_mode grayish ; 83 | int i ; 84 | 85 | if( spec->default_pixel == CHECKERED_BACKGROUND ) 86 | grayish = COLOR_GRAY ; 87 | else { 88 | int degrayed = degrayPixel(spec->default_pixel); 89 | if( degrayed < 0 ) { 90 | return COLOR_RGB ; 91 | } else if( spec->gimpish_indexed && 92 | (degrayed == 0 || degrayed == 255) ) { 93 | grayish = COLOR_MONO ; 94 | } else { 95 | grayish = COLOR_GRAY ; 96 | } 97 | } 98 | for( i=0; inumLayers; i++ ) 109 | switch( spec->layers[i].type ) { 110 | case GIMP_RGB_IMAGE: 111 | case GIMP_RGBA_IMAGE: 112 | return COLOR_RGB ; 113 | case GIMP_GRAY_IMAGE: 114 | case GIMP_GRAYA_IMAGE: 115 | grayish = COLOR_GRAY ; 116 | break ; 117 | case GIMP_INDEXED_IMAGE: 118 | case GIMP_INDEXEDA_IMAGE: 119 | if( colormap_is_colored ) return COLOR_RGB ; 120 | break ; 121 | } 122 | return grayish ; 123 | } 124 | 125 | void 126 | complete_flatspec(struct FlattenSpec *spec, guesser guess_callback) 127 | { 128 | unsigned i ; 129 | int anyPartial ; 130 | 131 | /* Find the layers to convert. 132 | */ 133 | if( spec->numLayers == 0 ) { 134 | spec->layers = XCF.layers ; 135 | spec->numLayers = XCF.numLayers ; 136 | } else { 137 | for( i=0; inumLayers; i++ ) { 138 | GimpLayerModeEffects mode ; 139 | int opacity, hasMask ; 140 | unsigned j ; 141 | 142 | for( j=0; ; j++ ) { 143 | if( j == XCF.numLayers ) 144 | FatalGeneric(22,_("The image has no layer called '%s'"), 145 | spec->layers[i].name); 146 | if( strcmp(spec->layers[i].name,XCF.layers[j].name) == 0 ) 147 | break ; 148 | } 149 | mode = spec->layers[i].mode == (GimpLayerModeEffects)-1 ? 150 | XCF.layers[j].mode : spec->layers[i].mode ; 151 | opacity = spec->layers[i].opacity == 9999 ? 152 | XCF.layers[j].opacity : spec->layers[i].opacity ; 153 | hasMask = spec->layers[i].hasMask == -1 ? 154 | XCF.layers[j].hasMask : spec->layers[i].hasMask ; 155 | if( hasMask && !XCF.layers[j].hasMask && 156 | XCF.layers[j].mask.hierarchy == 0 ) 157 | FatalGeneric(22,_("Layer '%s' has no layer mask to enable"), 158 | spec->layers[i].name); 159 | spec->layers[i] = XCF.layers[j] ; 160 | spec->layers[i].mode = mode ; 161 | spec->layers[i].opacity = opacity ; 162 | spec->layers[i].hasMask = hasMask ; 163 | spec->layers[i].isVisible = 1 ; 164 | } 165 | } 166 | 167 | /* Force the mode of the lowest visible layer to be Normal or Dissolve. 168 | * That may not be logical, but the Gimp does it 169 | */ 170 | for( i=0; i < spec->numLayers; i++ ) { 171 | if( spec->layers[i].isVisible ) { 172 | if( spec->layers[i].mode != GIMP_DISSOLVE_MODE ) 173 | spec->layers[i].mode = GIMP_NORMAL_MODE ; 174 | break ; 175 | } 176 | } 177 | 178 | /* Mimic the Gimp's behavior on indexed layers */ 179 | if( XCF.type == GIMP_INDEXED && spec->gimpish_indexed ) { 180 | for( i=0; inumLayers; i++ ) 181 | if( spec->layers[i].mode != GIMP_DISSOLVE_MODE ) 182 | spec->layers[i].mode = GIMP_NORMAL_NOPARTIAL_MODE ; 183 | } else 184 | spec->gimpish_indexed = 0 ; 185 | 186 | /* compute dimensions of the window */ 187 | if( spec->window_mode == AUTOCROP ) { 188 | int first = 1 ; 189 | for( i=0; inumLayers; i++ ) 190 | if( spec->layers[i].isVisible ) { 191 | computeDimensions(&spec->layers[i].dim) ; 192 | if( first ) { 193 | spec->dim = spec->layers[i].dim ; 194 | first = 0 ; 195 | } else { 196 | if( spec->dim.c.l > spec->layers[i].dim.c.l ) 197 | spec->dim.c.l = spec->layers[i].dim.c.l ; 198 | if( spec->dim.c.r < spec->layers[i].dim.c.r ) 199 | spec->dim.c.r = spec->layers[i].dim.c.r ; 200 | if( spec->dim.c.t > spec->layers[i].dim.c.t ) 201 | spec->dim.c.t = spec->layers[i].dim.c.t ; 202 | if( spec->dim.c.b < spec->layers[i].dim.c.b ) 203 | spec->dim.c.b = spec->layers[i].dim.c.b ; 204 | } 205 | } 206 | if( first ) { 207 | spec->window_mode = USE_CANVAS ; 208 | } else { 209 | spec->dim.width = spec->dim.c.r - spec->dim.c.l ; 210 | spec->dim.height = spec->dim.c.b - spec->dim.c.t ; 211 | } 212 | } 213 | if( spec->window_mode != AUTOCROP ) { 214 | if( (spec->window_mode & MANUAL_OFFSET) == 0 ) 215 | spec->dim.c.t = spec->dim.c.l = 0 ; 216 | if( (spec->window_mode & MANUAL_CROP) == 0 ) { 217 | spec->dim.height = XCF.height ; 218 | spec->dim.width = XCF.width ; 219 | } 220 | } 221 | computeDimensions(&spec->dim); 222 | 223 | /* Turn off layers that we don't hit at all */ 224 | for( i=0; inumLayers; i++ ) 225 | if( spec->layers[i].isVisible && 226 | disjointRects(spec->dim.c,spec->layers[i].dim.c) ) 227 | spec->layers[i].isVisible = 0 ; 228 | 229 | /* See if there is a completely covering layer somewhere in the stack */ 230 | /* Also check if partial transparency is possible */ 231 | anyPartial = 0 ; 232 | for( i=spec->numLayers; i-- ; ) { 233 | if( !spec->layers[i].isVisible ) 234 | continue ; 235 | if( typeHasTransparency(spec->layers[i].type) ) { 236 | if( spec->layers[i].mode == GIMP_NORMAL_MODE ) 237 | anyPartial = 1; 238 | } else if( isSubrect(spec->dim.c,spec->layers[i].dim.c) && 239 | !spec->layers[i].hasMask && 240 | (spec->layers[i].mode == GIMP_NORMAL_MODE || 241 | spec->layers[i].mode == GIMP_NORMAL_NOPARTIAL_MODE || 242 | spec->layers[i].mode == GIMP_DISSOLVE_MODE) ) { 243 | /* This layer fills out the entire image. 244 | * Turn off anly lower layers, and note that we cannot have 245 | * transparency at all. 246 | */ 247 | while(i) spec->layers[--i].isVisible = 0 ; 248 | if( spec->default_pixel != FORCE_ALPHA_CHANNEL ) 249 | spec->default_pixel = NEWALPHA(colormap[0],255); 250 | anyPartial = 0 ; 251 | break ; 252 | } 253 | } 254 | if( spec->partial_transparency_mode == ALLOW_PARTIAL_TRANSPARENCY && 255 | (!anyPartial || ALPHA(spec->default_pixel) >= 128) ) 256 | spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ; 257 | 258 | /* Initialize layers and print overview if we're verbose */ 259 | for( i=spec->numLayers; i--; ) 260 | if( spec->layers[i].isVisible ) { 261 | initLayer(&spec->layers[i]) ; 262 | if( verboseFlag ) { 263 | fprintf(stderr,"%dx%d%+d%+d %s %s", 264 | spec->layers[i].dim.width, spec->layers[i].dim.height, 265 | spec->layers[i].dim.c.l - spec->dim.c.l, 266 | spec->layers[i].dim.c.t - spec->dim.c.t, 267 | _(showGimpImageType(spec->layers[i].type)), 268 | _(showGimpLayerModeEffects(spec->layers[i].mode))); 269 | if( spec->layers[i].opacity < 255 ) 270 | fprintf(stderr,"/%02d%%",spec->layers[i].opacity * 100 / 255); 271 | if( XCF.layers[i].hasMask ) 272 | fprintf(stderr,_("/mask")); 273 | fprintf(stderr," %s\n",spec->layers[i].name); 274 | } 275 | } 276 | 277 | /* Resolve color mode unless we wait until we have the entire image */ 278 | if( spec->out_color_mode == COLOR_BY_CONTENTS && 279 | !spec->process_in_memory ) { 280 | if( guess_callback ) 281 | spec->out_color_mode = guess_callback(spec,NULL); 282 | if( spec->out_color_mode == COLOR_BY_CONTENTS ) 283 | spec->out_color_mode = color_by_layers(spec) ; 284 | } 285 | } 286 | 287 | void 288 | analyse_colormode(struct FlattenSpec *spec,rgba **allPixels, 289 | guesser guess_callback) 290 | { 291 | unsigned x,y ; 292 | int status ; 293 | /* 8 - looking for any transparency 294 | * 4 - looking for partially transparent pixels 295 | * 2 - looking for pixels other than black and white 296 | * 1 - looking for colored pixels 297 | */ 298 | int known_absent = 0 ; 299 | int assume_present = 0 ; 300 | 301 | if( spec->out_color_mode == COLOR_BY_CONTENTS && guess_callback ) 302 | spec->out_color_mode = guess_callback(spec,allPixels) ; 303 | 304 | if( spec->out_color_mode == COLOR_RGB ) assume_present |= 3 ; 305 | if( spec->out_color_mode == COLOR_INDEXED ) assume_present |= 3 ; 306 | if( spec->out_color_mode == COLOR_GRAY ) assume_present |= 2 ; 307 | switch( color_by_layers(spec) ) { 308 | case COLOR_GRAY: known_absent |= 1 ; break ; 309 | case COLOR_MONO: known_absent |= 3 ; break ; 310 | default: break ; 311 | } 312 | if( spec->partial_transparency_mode == DISSOLVE_PARTIAL_TRANSPARENCY || 313 | spec->partial_transparency_mode == PARTIAL_TRANSPARENCY_IMPOSSIBLE ) 314 | known_absent |= 4 ; 315 | if( ALPHA(spec->default_pixel) >= 128 ) known_absent |= 12 ; 316 | else if( spec->default_pixel == FORCE_ALPHA_CHANNEL ) assume_present |= 8 ; 317 | 318 | status = 15 - (known_absent | assume_present) ; 319 | 320 | for( y=0; status && ydim.height; y++ ) { 321 | rgba *row = allPixels[y] ; 322 | if( (status & 3) != 0 ) { 323 | /* We're still interested in color */ 324 | for( x=0; status && xdim.width; x++ ) { 325 | if( NULLALPHA(row[x]) ) 326 | status &= ~8 ; 327 | else { 328 | rgba full = row[x] | (255 << ALPHA_SHIFT) ; 329 | if( !FULLALPHA(row[x]) ) status &= ~12 ; 330 | if( full == NEWALPHA(0,255) || full == NEWALPHA(-1,255) ) 331 | /* Black or white */ ; 332 | else if( degrayPixel(row[x]) != -1 ) 333 | status &= ~2 ; /* gray */ 334 | else 335 | status &= ~3 ; /* color */ 336 | } 337 | } 338 | } else { 339 | /* Not interested in color */ 340 | for( x=0; status && xdim.width; x++ ) { 341 | if( NULLALPHA(row[x]) ) 342 | status &= ~8 ; 343 | else if( !FULLALPHA(row[x]) ) 344 | status &= ~12 ; 345 | } 346 | } 347 | } 348 | 349 | status |= known_absent ; 350 | 351 | switch( spec->out_color_mode ) { 352 | case COLOR_INDEXED: /* The caller takes responsibility */ 353 | case COLOR_RGB: /* Everything is fine. */ 354 | break ; 355 | case COLOR_GRAY: 356 | if( (status & 1) == 0 ) 357 | FatalGeneric(103, 358 | _("Grayscale output selected, but colored pixel(s) found")); 359 | break ; 360 | case COLOR_MONO: 361 | if( (status & 2) == 0 ) 362 | FatalGeneric(103,_("Monochrome output selected, but not all pixels " 363 | "are black or white")); 364 | break ; 365 | case COLOR_BY_FILENAME: /* Should not happen ... */ 366 | case COLOR_BY_CONTENTS: 367 | if( (status & 1) == 0 ) 368 | spec->out_color_mode = COLOR_RGB ; 369 | else if( (status & 2) == 0 ) 370 | spec->out_color_mode = COLOR_GRAY ; 371 | else 372 | spec->out_color_mode = COLOR_MONO ; 373 | break ; 374 | } 375 | 376 | if( (status & 12) == 12 ) /* No transparency found */ 377 | spec->default_pixel = NEWALPHA(colormap[0],255); 378 | else if( (status & 12) == 4 ) 379 | spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ; 380 | } 381 | -------------------------------------------------------------------------------- /flatten.h: -------------------------------------------------------------------------------- 1 | /* Flattning functions for xcftools 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #ifndef FLATTEN_H 20 | #define FLATTEN_H 21 | 22 | #include "xcftools.h" 23 | #include "pixels.h" 24 | 25 | #define PERHAPS_ALPHA_CHANNEL (NEWALPHA(0,1)) 26 | #define FORCE_ALPHA_CHANNEL (NEWALPHA(0,2)) 27 | #define CHECKERED_BACKGROUND (NEWALPHA(0,200)) 28 | struct FlattenSpec { 29 | struct tileDimensions dim ; 30 | rgba default_pixel ; 31 | int numLayers ; 32 | struct xcfLayer *layers ; 33 | 34 | const char * transmap_filename ; 35 | const char * output_filename ; 36 | enum out_color_mode { 37 | COLOR_BY_FILENAME, 38 | COLOR_BY_CONTENTS, 39 | COLOR_INDEXED, 40 | COLOR_RGB, 41 | COLOR_GRAY, 42 | COLOR_MONO 43 | } out_color_mode ; 44 | enum { ALLOW_PARTIAL_TRANSPARENCY, 45 | DISSOLVE_PARTIAL_TRANSPARENCY, 46 | FORBID_PARTIAL_TRANSPARENCY, 47 | PARTIAL_TRANSPARENCY_IMPOSSIBLE 48 | } partial_transparency_mode ; 49 | enum { USE_CANVAS = 0, 50 | MANUAL_OFFSET = 1, 51 | MANUAL_CROP = 2, 52 | AUTOCROP = 4 } window_mode ; 53 | int process_in_memory ; 54 | int gimpish_indexed ; 55 | }; 56 | 57 | /* From flatspec.c */ 58 | 59 | void init_flatspec(struct FlattenSpec *); 60 | 61 | void add_layer_request(struct FlattenSpec *,const char *name); 62 | struct xcfLayer *lastlayerspec(struct FlattenSpec *,const char *option); 63 | 64 | typedef enum out_color_mode (*guesser) (struct FlattenSpec *,rgba **); 65 | 66 | /* Call this after processing options, and after opening the XCF file */ 67 | void complete_flatspec(struct FlattenSpec *,guesser); 68 | void analyse_colormode(struct FlattenSpec *,rgba **allPixels,guesser); 69 | 70 | /* From flatten.c */ 71 | 72 | typedef void (*lineCallback)(unsigned num,rgba *pixels); 73 | void flattenIncrementally(struct FlattenSpec *,lineCallback); 74 | rgba **flattenAll(struct FlattenSpec*); 75 | void shipoutWithCallback(struct FlattenSpec *,rgba **pixels,lineCallback); 76 | 77 | #endif /* FLATTEN_H */ 78 | -------------------------------------------------------------------------------- /gimp/base-enums.h: -------------------------------------------------------------------------------- 1 | /* The GIMP -- an image manipulation program 2 | * Copyright (C) 1995 Spencer Kimball and Peter Mattis 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program; if not, write to the Free Software 16 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | */ 18 | 19 | #ifndef __BASE_ENUMS_H__ 20 | #define __BASE_ENUMS_H__ 21 | 22 | #if 0 23 | This file is parsed by two scripts, enumgen.pl in tools/pdbgen, 24 | and gimp-mkenums. All enums that are not marked with 25 | /*< pdb-skip >*/ are exported to libgimp and the PDB. Enums that are 26 | not marked with /*< skip >*/ are registered with the GType system. 27 | If you want the enum to be skipped by both scripts, you have to use 28 | /*< pdb-skip, skip >*/. 29 | 30 | The same syntax applies to enum values. 31 | #endif 32 | 33 | 34 | /* 35 | * these enums that are registered with the type system 36 | */ 37 | 38 | #define GIMP_TYPE_CURVE_TYPE (gimp_curve_type_get_type ()) 39 | 40 | GType gimp_curve_type_get_type (void) G_GNUC_CONST; 41 | 42 | typedef enum /*< pdb-skip >*/ 43 | { 44 | GIMP_CURVE_SMOOTH, /*< desc="Smooth" >*/ 45 | GIMP_CURVE_FREE /*< desc="Freehand" >*/ 46 | } GimpCurveType; 47 | 48 | 49 | #define GIMP_TYPE_HISTOGRAM_CHANNEL (gimp_histogram_channel_get_type ()) 50 | 51 | GType gimp_histogram_channel_get_type (void) G_GNUC_CONST; 52 | 53 | typedef enum 54 | { 55 | GIMP_HISTOGRAM_VALUE = 0, /*< desc="Value" >*/ 56 | GIMP_HISTOGRAM_RED = 1, /*< desc="Red" >*/ 57 | GIMP_HISTOGRAM_GREEN = 2, /*< desc="Green" >*/ 58 | GIMP_HISTOGRAM_BLUE = 3, /*< desc="Blue" >*/ 59 | GIMP_HISTOGRAM_ALPHA = 4, /*< desc="Alpha" >*/ 60 | GIMP_HISTOGRAM_RGB = 5 /*< desc="RGB", pdb-skip >*/ 61 | } GimpHistogramChannel; 62 | 63 | 64 | #define GIMP_TYPE_INTERPOLATION_TYPE (gimp_interpolation_type_get_type ()) 65 | 66 | GType gimp_interpolation_type_get_type (void) G_GNUC_CONST; 67 | 68 | typedef enum 69 | { 70 | GIMP_INTERPOLATION_NONE, /*< desc="None (Fastest)" >*/ 71 | GIMP_INTERPOLATION_LINEAR, /*< desc="Linear" >*/ 72 | GIMP_INTERPOLATION_CUBIC /*< desc="Cubic (Best)" >*/ 73 | } GimpInterpolationType; 74 | 75 | 76 | #define GIMP_TYPE_LAYER_MODE_EFFECTS (gimp_layer_mode_effects_get_type ()) 77 | 78 | GType gimp_layer_mode_effects_get_type (void) G_GNUC_CONST; 79 | 80 | typedef enum 81 | { 82 | GIMP_NORMAL_MODE, 83 | GIMP_DISSOLVE_MODE, 84 | GIMP_BEHIND_MODE, 85 | GIMP_MULTIPLY_MODE, 86 | GIMP_SCREEN_MODE, 87 | GIMP_OVERLAY_MODE, 88 | GIMP_DIFFERENCE_MODE, 89 | GIMP_ADDITION_MODE, 90 | GIMP_SUBTRACT_MODE, 91 | GIMP_DARKEN_ONLY_MODE, 92 | GIMP_LIGHTEN_ONLY_MODE, 93 | GIMP_HUE_MODE, 94 | GIMP_SATURATION_MODE, 95 | GIMP_COLOR_MODE, 96 | GIMP_VALUE_MODE, 97 | GIMP_DIVIDE_MODE, 98 | GIMP_DODGE_MODE, 99 | GIMP_BURN_MODE, 100 | GIMP_HARDLIGHT_MODE, 101 | GIMP_SOFTLIGHT_MODE, 102 | GIMP_GRAIN_EXTRACT_MODE, 103 | GIMP_GRAIN_MERGE_MODE, 104 | GIMP_COLOR_ERASE_MODE, 105 | GIMP_ERASE_MODE, /*< pdb-skip, skip >*/ 106 | GIMP_REPLACE_MODE, /*< pdb-skip, skip >*/ 107 | GIMP_ANTI_ERASE_MODE /*< pdb-skip, skip >*/ 108 | } GimpLayerModeEffects; 109 | 110 | 111 | #define GIMP_TYPE_TRANSFER_MODE (gimp_transfer_mode_get_type ()) 112 | 113 | GType gimp_transfer_mode_get_type (void) G_GNUC_CONST; 114 | 115 | typedef enum 116 | { 117 | GIMP_SHADOWS, /*< desc="Shadows" >*/ 118 | GIMP_MIDTONES, /*< desc="Midtones" >*/ 119 | GIMP_HIGHLIGHTS /*< desc="Highlights" >*/ 120 | } GimpTransferMode; 121 | 122 | 123 | /* 124 | * non-registered enums; register them if needed 125 | */ 126 | 127 | typedef enum /*< skip >*/ 128 | { 129 | GIMP_NORMAL_CONVOL, /* Negative numbers truncated */ 130 | GIMP_ABSOLUTE_CONVOL, /* Absolute value */ 131 | GIMP_NEGATIVE_CONVOL /* add 127 to values */ 132 | } GimpConvolutionType; 133 | 134 | typedef enum /*< skip >*/ 135 | { 136 | GIMP_ALL_HUES, 137 | GIMP_RED_HUES, 138 | GIMP_YELLOW_HUES, 139 | GIMP_GREEN_HUES, 140 | GIMP_CYAN_HUES, 141 | GIMP_BLUE_HUES, 142 | GIMP_MAGENTA_HUES 143 | } GimpHueRange; 144 | 145 | 146 | #endif /* __BASE_ENUMS_H__ */ 147 | -------------------------------------------------------------------------------- /gimp/gimpbaseenums.h: -------------------------------------------------------------------------------- 1 | /* LIBGIMP - The GIMP Library 2 | * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball 3 | * 4 | * This library is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU Lesser General Public 6 | * License as published by the Free Software Foundation; either 7 | * version 2 of the License, or (at your option) any later version. 8 | * 9 | * This library is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | * Library General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU Lesser General Public 15 | * License along with this library; if not, write to the 16 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 | * Boston, MA 02111-1307, USA. 18 | */ 19 | 20 | #ifndef __GIMP_BASE_ENUMS_H__ 21 | #define __GIMP_BASE_ENUMS_H__ 22 | 23 | 24 | G_BEGIN_DECLS 25 | 26 | /* For information look into the C source or the html documentation */ 27 | 28 | 29 | #define GIMP_TYPE_CHECK_SIZE (gimp_check_size_get_type ()) 30 | 31 | GType gimp_check_size_get_type (void) G_GNUC_CONST; 32 | 33 | typedef enum /*< pdb-skip >*/ 34 | { 35 | GIMP_CHECK_SIZE_SMALL_CHECKS = 0, /*< desc="Small" >*/ 36 | GIMP_CHECK_SIZE_MEDIUM_CHECKS = 1, /*< desc="Medium" >*/ 37 | GIMP_CHECK_SIZE_LARGE_CHECKS = 2 /*< desc="Large" >*/ 38 | } GimpCheckSize; 39 | 40 | 41 | #define GIMP_TYPE_CHECK_TYPE (gimp_check_type_get_type ()) 42 | 43 | GType gimp_check_type_get_type (void) G_GNUC_CONST; 44 | 45 | typedef enum /*< pdb-skip >*/ 46 | { 47 | GIMP_CHECK_TYPE_LIGHT_CHECKS = 0, /*< desc="Light Checks" >*/ 48 | GIMP_CHECK_TYPE_GRAY_CHECKS = 1, /*< desc="Mid-Tone Checks" >*/ 49 | GIMP_CHECK_TYPE_DARK_CHECKS = 2, /*< desc="Dark Checks" >*/ 50 | GIMP_CHECK_TYPE_WHITE_ONLY = 3, /*< desc="White Only" >*/ 51 | GIMP_CHECK_TYPE_GRAY_ONLY = 4, /*< desc="Gray Only" >*/ 52 | GIMP_CHECK_TYPE_BLACK_ONLY = 5 /*< desc="Black Only" >*/ 53 | } GimpCheckType; 54 | 55 | 56 | #define GIMP_TYPE_IMAGE_BASE_TYPE (gimp_image_base_type_get_type ()) 57 | 58 | GType gimp_image_base_type_get_type (void) G_GNUC_CONST; 59 | 60 | typedef enum 61 | { 62 | GIMP_RGB, /*< desc="RGB color" >*/ 63 | GIMP_GRAY, /*< desc="Grayscale" >*/ 64 | GIMP_INDEXED /*< desc="Indexed color" >*/ 65 | } GimpImageBaseType; 66 | 67 | 68 | #define GIMP_TYPE_IMAGE_TYPE (gimp_image_type_get_type ()) 69 | 70 | GType gimp_image_type_get_type (void) G_GNUC_CONST; 71 | 72 | typedef enum 73 | { 74 | GIMP_RGB_IMAGE, /*< desc="RGB" >*/ 75 | GIMP_RGBA_IMAGE, /*< desc="RGB-alpha" >*/ 76 | GIMP_GRAY_IMAGE, /*< desc="Grayscale" >*/ 77 | GIMP_GRAYA_IMAGE, /*< desc="Grayscale-alpha" >*/ 78 | GIMP_INDEXED_IMAGE, /*< desc="Indexed" >*/ 79 | GIMP_INDEXEDA_IMAGE /*< desc="Indexed-alpha" >*/ 80 | } GimpImageType; 81 | 82 | 83 | typedef enum /*< skip >*/ 84 | { 85 | GIMP_UNIT_PIXEL = 0, 86 | 87 | GIMP_UNIT_INCH = 1, 88 | GIMP_UNIT_MM = 2, 89 | GIMP_UNIT_POINT = 3, 90 | GIMP_UNIT_PICA = 4, 91 | 92 | GIMP_UNIT_END = 5, 93 | 94 | GIMP_UNIT_PERCENT = 65536 /*< pdb-skip >*/ 95 | } GimpUnit; 96 | 97 | 98 | #define GIMP_TYPE_PDB_ARG_TYPE (gimp_pdb_arg_type_get_type ()) 99 | 100 | GType gimp_pdb_arg_type_get_type (void) G_GNUC_CONST; 101 | 102 | typedef enum 103 | { 104 | GIMP_PDB_INT32, 105 | GIMP_PDB_INT16, 106 | GIMP_PDB_INT8, 107 | GIMP_PDB_FLOAT, 108 | GIMP_PDB_STRING, 109 | GIMP_PDB_INT32ARRAY, 110 | GIMP_PDB_INT16ARRAY, 111 | GIMP_PDB_INT8ARRAY, 112 | GIMP_PDB_FLOATARRAY, 113 | GIMP_PDB_STRINGARRAY, 114 | GIMP_PDB_COLOR, 115 | GIMP_PDB_REGION, 116 | GIMP_PDB_DISPLAY, 117 | GIMP_PDB_IMAGE, 118 | GIMP_PDB_LAYER, 119 | GIMP_PDB_CHANNEL, 120 | GIMP_PDB_DRAWABLE, 121 | GIMP_PDB_SELECTION, 122 | GIMP_PDB_BOUNDARY, 123 | GIMP_PDB_PATH, 124 | GIMP_PDB_PARASITE, 125 | GIMP_PDB_STATUS, 126 | GIMP_PDB_END 127 | } GimpPDBArgType; 128 | 129 | 130 | #define GIMP_TYPE_PDB_PROC_TYPE (gimp_pdb_proc_type_get_type ()) 131 | 132 | GType gimp_pdb_proc_type_get_type (void) G_GNUC_CONST; 133 | 134 | typedef enum 135 | { 136 | GIMP_INTERNAL, 137 | GIMP_PLUGIN, 138 | GIMP_EXTENSION, 139 | GIMP_TEMPORARY 140 | } GimpPDBProcType; 141 | 142 | 143 | #define GIMP_TYPE_PDB_STATUS_TYPE (gimp_pdb_status_type_get_type ()) 144 | 145 | GType gimp_pdb_status_type_get_type (void) G_GNUC_CONST; 146 | 147 | typedef enum 148 | { 149 | GIMP_PDB_EXECUTION_ERROR, 150 | GIMP_PDB_CALLING_ERROR, 151 | GIMP_PDB_PASS_THROUGH, 152 | GIMP_PDB_SUCCESS, 153 | GIMP_PDB_CANCEL 154 | } GimpPDBStatusType; 155 | 156 | 157 | #define GIMP_TYPE_PRECISION (gimp_precision_get_type ()) 158 | 159 | GType gimp_precision_get_type (void) G_GNUC_CONST; 160 | 161 | typedef enum 162 | { 163 | GIMP_PRECISION_U8_LINEAR = 100, /*< desc="8-bit linear integer" >*/ 164 | GIMP_PRECISION_U8_NON_LINEAR = 150, /*< desc="8-bit non-linear integer" >*/ 165 | GIMP_PRECISION_U8_PERCEPTUAL = 175, /*< desc="8-bit perceptual integer" >*/ 166 | GIMP_PRECISION_U16_LINEAR = 200, /*< desc="16-bit linear integer" >*/ 167 | GIMP_PRECISION_U16_NON_LINEAR = 250, /*< desc="16-bit non-linear integer" >*/ 168 | GIMP_PRECISION_U16_PERCEPTUAL = 275, /*< desc="16-bit perceptual integer" >*/ 169 | GIMP_PRECISION_U32_LINEAR = 300, /*< desc="32-bit linear integer" >*/ 170 | GIMP_PRECISION_U32_NON_LINEAR = 350, /*< desc="32-bit non-linear integer" >*/ 171 | GIMP_PRECISION_U32_PERCEPTUAL = 375, /*< desc="32-bit perceptual integer" >*/ 172 | GIMP_PRECISION_HALF_LINEAR = 500, /*< desc="16-bit linear floating point" >*/ 173 | GIMP_PRECISION_HALF_NON_LINEAR = 550, /*< desc="16-bit non-linear floating point" >*/ 174 | GIMP_PRECISION_HALF_PERCEPTUAL = 575, /*< desc="16-bit perceptual floating point" >*/ 175 | GIMP_PRECISION_FLOAT_LINEAR = 600, /*< desc="32-bit linear floating point" >*/ 176 | GIMP_PRECISION_FLOAT_NON_LINEAR = 650, /*< desc="32-bit non-linear floating point" >*/ 177 | GIMP_PRECISION_FLOAT_PERCEPTUAL = 675, /*< desc="32-bit perceptual floating point" >*/ 178 | GIMP_PRECISION_DOUBLE_LINEAR = 700, /*< desc="64-bit linear floating point" >*/ 179 | GIMP_PRECISION_DOUBLE_NON_LINEAR = 750, /*< desc="64-bit non-linear floating point" >*/ 180 | GIMP_PRECISION_DOUBLE_PERCEPTUAL = 775, /*< desc="64-bit perceptual floating point" >*/ 181 | } GimpPrecision; 182 | 183 | 184 | #define GIMP_TYPE_MESSAGE_HANDLER_TYPE (gimp_message_handler_type_get_type ()) 185 | 186 | GType gimp_message_handler_type_get_type (void) G_GNUC_CONST; 187 | 188 | typedef enum 189 | { 190 | GIMP_MESSAGE_BOX, 191 | GIMP_CONSOLE, 192 | GIMP_ERROR_CONSOLE 193 | } GimpMessageHandlerType; 194 | 195 | 196 | #define GIMP_TYPE_STACK_TRACE_MODE (gimp_stack_trace_mode_get_type ()) 197 | 198 | GType gimp_stack_trace_mode_get_type (void) G_GNUC_CONST; 199 | 200 | typedef enum 201 | { 202 | GIMP_STACK_TRACE_NEVER, 203 | GIMP_STACK_TRACE_QUERY, 204 | GIMP_STACK_TRACE_ALWAYS 205 | } GimpStackTraceMode; 206 | 207 | 208 | #define GIMP_TYPE_PROGRESS_COMMAND (gimp_progress_command_get_type ()) 209 | 210 | GType gimp_progress_command_get_type (void) G_GNUC_CONST; 211 | 212 | typedef enum 213 | { 214 | GIMP_PROGRESS_COMMAND_START, 215 | GIMP_PROGRESS_COMMAND_END, 216 | GIMP_PROGRESS_COMMAND_SET_TEXT, 217 | GIMP_PROGRESS_COMMAND_SET_VALUE 218 | } GimpProgressCommand; 219 | 220 | 221 | G_END_DECLS 222 | 223 | #endif /* __GIMP_BASE_ENUMS_H__ */ 224 | -------------------------------------------------------------------------------- /gimp/xcf-private.h: -------------------------------------------------------------------------------- 1 | /* GIMP - The GNU Image Manipulation Program 2 | * Copyright (C) 1995 Spencer Kimball and Peter Mattis 3 | * 4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | */ 17 | 18 | #ifndef __XCF_PRIVATE_H__ 19 | #define __XCF_PRIVATE_H__ 20 | 21 | 22 | typedef enum 23 | { 24 | PROP_END = 0, 25 | PROP_COLORMAP = 1, 26 | PROP_ACTIVE_LAYER = 2, 27 | PROP_ACTIVE_CHANNEL = 3, 28 | PROP_SELECTION = 4, 29 | PROP_FLOATING_SELECTION = 5, 30 | PROP_OPACITY = 6, 31 | PROP_MODE = 7, 32 | PROP_VISIBLE = 8, 33 | PROP_LINKED = 9, 34 | PROP_LOCK_ALPHA = 10, 35 | PROP_APPLY_MASK = 11, 36 | PROP_EDIT_MASK = 12, 37 | PROP_SHOW_MASK = 13, 38 | PROP_SHOW_MASKED = 14, 39 | PROP_OFFSETS = 15, 40 | PROP_COLOR = 16, 41 | PROP_COMPRESSION = 17, 42 | PROP_GUIDES = 18, 43 | PROP_RESOLUTION = 19, 44 | PROP_TATTOO = 20, 45 | PROP_PARASITES = 21, 46 | PROP_UNIT = 22, 47 | PROP_PATHS = 23, 48 | PROP_USER_UNIT = 24, 49 | PROP_VECTORS = 25, 50 | PROP_TEXT_LAYER_FLAGS = 26, 51 | PROP_SAMPLE_POINTS = 27, 52 | PROP_LOCK_CONTENT = 28, 53 | PROP_GROUP_ITEM = 29, 54 | PROP_ITEM_PATH = 30, 55 | PROP_GROUP_ITEM_FLAGS = 31 56 | } PropType; 57 | 58 | typedef enum 59 | { 60 | COMPRESS_NONE = 0, 61 | COMPRESS_RLE = 1, 62 | COMPRESS_ZLIB = 2, /* unused */ 63 | COMPRESS_FRACTAL = 3 /* unused */ 64 | } XcfCompressionType; 65 | 66 | typedef enum 67 | { 68 | XCF_ORIENTATION_HORIZONTAL = 1, 69 | XCF_ORIENTATION_VERTICAL = 2 70 | } XcfOrientationType; 71 | 72 | typedef enum 73 | { 74 | XCF_STROKETYPE_STROKE = 0, 75 | XCF_STROKETYPE_BEZIER_STROKE = 1 76 | } XcfStrokeType; 77 | 78 | typedef enum 79 | { 80 | XCF_GROUP_ITEM_EXPANDED = 1 81 | } XcfGroupItemFlagsType; 82 | 83 | typedef struct _XcfInfo XcfInfo; 84 | 85 | struct _XcfInfo 86 | { 87 | Gimp *gimp; 88 | GimpProgress *progress; 89 | FILE *fp; 90 | guint cp; 91 | const gchar *filename; 92 | GimpTattoo tattoo_state; 93 | GimpLayer *active_layer; 94 | GimpChannel *active_channel; 95 | GimpDrawable *floating_sel_drawable; 96 | GimpLayer *floating_sel; 97 | guint floating_sel_offset; 98 | gint swap_num; 99 | gint *ref_count; 100 | XcfCompressionType compression; 101 | gint file_version; 102 | }; 103 | 104 | 105 | #endif /* __XCF_PRIVATE_H__ */ 106 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # install - install a program, script, or datafile 4 | # 5 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 6 | # later released in X11R6 (xc/config/util/install.sh) with the 7 | # following copyright and license. 8 | # 9 | # Copyright (C) 1994 X Consortium 10 | # 11 | # Permission is hereby granted, free of charge, to any person obtaining a copy 12 | # of this software and associated documentation files (the "Software"), to 13 | # deal in the Software without restriction, including without limitation the 14 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 15 | # sell copies of the Software, and to permit persons to whom the Software is 16 | # furnished to do so, subject to the following conditions: 17 | # 18 | # The above copyright notice and this permission notice shall be included in 19 | # all copies or substantial portions of the Software. 20 | # 21 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 24 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 25 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 26 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 27 | # 28 | # Except as contained in this notice, the name of the X Consortium shall not 29 | # be used in advertising or otherwise to promote the sale, use or other deal- 30 | # ings in this Software without prior written authorization from the X Consor- 31 | # tium. 32 | # 33 | # 34 | # FSF changes to this file are in the public domain. 35 | # 36 | # Calling this script install-sh is preferred over install.sh, to prevent 37 | # `make' implicit rules from creating a file called install from it 38 | # when there is no Makefile. 39 | # 40 | # This script is compatible with the BSD install script, but was written 41 | # from scratch. It can only install one file at a time, a restriction 42 | # shared with many OS's install programs. 43 | 44 | 45 | # set DOITPROG to echo to test this script 46 | 47 | # Don't use :- since 4.3BSD and earlier shells don't like it. 48 | doit="${DOITPROG-}" 49 | 50 | 51 | # put in absolute paths if you don't have them in your path; or use env. vars. 52 | 53 | mvprog="${MVPROG-mv}" 54 | cpprog="${CPPROG-cp}" 55 | chmodprog="${CHMODPROG-chmod}" 56 | chownprog="${CHOWNPROG-chown}" 57 | chgrpprog="${CHGRPPROG-chgrp}" 58 | stripprog="${STRIPPROG-strip}" 59 | rmprog="${RMPROG-rm}" 60 | mkdirprog="${MKDIRPROG-mkdir}" 61 | 62 | transformbasename="" 63 | transform_arg="" 64 | instcmd="$mvprog" 65 | chmodcmd="$chmodprog 0755" 66 | chowncmd="" 67 | chgrpcmd="" 68 | stripcmd="" 69 | rmcmd="$rmprog -f" 70 | mvcmd="$mvprog" 71 | src="" 72 | dst="" 73 | dir_arg="" 74 | 75 | while [ x"$1" != x ]; do 76 | case $1 in 77 | -c) instcmd="$cpprog" 78 | shift 79 | continue;; 80 | 81 | -d) dir_arg=true 82 | shift 83 | continue;; 84 | 85 | -m) chmodcmd="$chmodprog $2" 86 | shift 87 | shift 88 | continue;; 89 | 90 | -o) chowncmd="$chownprog $2" 91 | shift 92 | shift 93 | continue;; 94 | 95 | -g) chgrpcmd="$chgrpprog $2" 96 | shift 97 | shift 98 | continue;; 99 | 100 | -s) stripcmd="$stripprog" 101 | shift 102 | continue;; 103 | 104 | -t=*) transformarg=`echo $1 | sed 's/-t=//'` 105 | shift 106 | continue;; 107 | 108 | -b=*) transformbasename=`echo $1 | sed 's/-b=//'` 109 | shift 110 | continue;; 111 | 112 | *) if [ x"$src" = x ] 113 | then 114 | src=$1 115 | else 116 | # this colon is to work around a 386BSD /bin/sh bug 117 | : 118 | dst=$1 119 | fi 120 | shift 121 | continue;; 122 | esac 123 | done 124 | 125 | if [ x"$src" = x ] 126 | then 127 | echo "install: no input file specified" 128 | exit 1 129 | else 130 | : 131 | fi 132 | 133 | if [ x"$dir_arg" != x ]; then 134 | dst=$src 135 | src="" 136 | 137 | if [ -d $dst ]; then 138 | instcmd=: 139 | chmodcmd="" 140 | else 141 | instcmd=$mkdirprog 142 | fi 143 | else 144 | 145 | # Waiting for this to be detected by the "$instcmd $src $dsttmp" command 146 | # might cause directories to be created, which would be especially bad 147 | # if $src (and thus $dsttmp) contains '*'. 148 | 149 | if [ -f "$src" ] || [ -d "$src" ] 150 | then 151 | : 152 | else 153 | echo "install: $src does not exist" 154 | exit 1 155 | fi 156 | 157 | if [ x"$dst" = x ] 158 | then 159 | echo "install: no destination specified" 160 | exit 1 161 | else 162 | : 163 | fi 164 | 165 | # If destination is a directory, append the input filename; if your system 166 | # does not like double slashes in filenames, you may need to add some logic 167 | 168 | if [ -d $dst ] 169 | then 170 | dst="$dst"/`basename $src` 171 | else 172 | : 173 | fi 174 | fi 175 | 176 | ## this sed command emulates the dirname command 177 | dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` 178 | 179 | # Make sure that the destination directory exists. 180 | # this part is taken from Noah Friedman's mkinstalldirs script 181 | 182 | # Skip lots of stat calls in the usual case. 183 | if [ ! -d "$dstdir" ]; then 184 | defaultIFS=' 185 | ' 186 | IFS="${IFS-${defaultIFS}}" 187 | 188 | oIFS="${IFS}" 189 | # Some sh's can't handle IFS=/ for some reason. 190 | IFS='%' 191 | set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` 192 | IFS="${oIFS}" 193 | 194 | pathcomp='' 195 | 196 | while [ $# -ne 0 ] ; do 197 | pathcomp="${pathcomp}${1}" 198 | shift 199 | 200 | if [ ! -d "${pathcomp}" ] ; 201 | then 202 | $mkdirprog "${pathcomp}" 203 | else 204 | : 205 | fi 206 | 207 | pathcomp="${pathcomp}/" 208 | done 209 | fi 210 | 211 | if [ x"$dir_arg" != x ] 212 | then 213 | $doit $instcmd $dst && 214 | 215 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else : ; fi && 216 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else : ; fi && 217 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else : ; fi && 218 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else : ; fi 219 | else 220 | 221 | # If we're going to rename the final executable, determine the name now. 222 | 223 | if [ x"$transformarg" = x ] 224 | then 225 | dstfile=`basename $dst` 226 | else 227 | dstfile=`basename $dst $transformbasename | 228 | sed $transformarg`$transformbasename 229 | fi 230 | 231 | # don't allow the sed command to completely eliminate the filename 232 | 233 | if [ x"$dstfile" = x ] 234 | then 235 | dstfile=`basename $dst` 236 | else 237 | : 238 | fi 239 | 240 | # Make a temp file name in the proper directory. 241 | 242 | dsttmp=$dstdir/#inst.$$# 243 | 244 | # Move or copy the file name to the temp name 245 | 246 | $doit $instcmd $src $dsttmp && 247 | 248 | trap "rm -f ${dsttmp}" 0 && 249 | 250 | # and set any options; do chmod last to preserve setuid bits 251 | 252 | # If any of these fail, we abort the whole thing. If we want to 253 | # ignore errors from any of these, just make sure not to ignore 254 | # errors from the above "$doit $instcmd $src $dsttmp" command. 255 | 256 | if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else :;fi && 257 | if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else :;fi && 258 | if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else :;fi && 259 | if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else :;fi && 260 | 261 | # Now rename the file to the real destination. 262 | 263 | $doit $rmcmd -f $dstdir/$dstfile && 264 | $doit $mvcmd $dsttmp $dstdir/$dstfile 265 | 266 | fi && 267 | 268 | 269 | exit 0 270 | -------------------------------------------------------------------------------- /io-unix.c: -------------------------------------------------------------------------------- 1 | /* OS-specific IO functions for xcftools 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "xcftools.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #if HAVE_MMAP 28 | #include 29 | #endif 30 | 31 | static FILE *xcfstream = 0 ; 32 | 33 | void 34 | free_or_close_xcf(void) 35 | { 36 | if( xcf_file ) { 37 | if( xcfstream ) { 38 | munmap(xcf_file,xcf_length) ; 39 | fclose(xcfstream); 40 | xcf_file = 0 ; 41 | xcfstream = 0 ; 42 | } else { 43 | free(xcf_file) ; 44 | xcf_file = 0 ; 45 | } 46 | } 47 | } 48 | 49 | void 50 | read_or_mmap_xcf(const char *filename,const char *unzipper) 51 | { 52 | struct stat statbuf ; 53 | 54 | free_or_close_xcf() ; 55 | 56 | if( strcmp(filename,"-") != 0 ) { 57 | if( access(filename,R_OK) != 0 ) 58 | FatalGeneric(21,"!%s",filename); 59 | } 60 | 61 | if( !unzipper ) { 62 | const char *pc ; 63 | pc = filename + strlen(filename) ; 64 | if( pc-filename > 2 && strcmp(pc-2,"gz") == 0 ) 65 | unzipper = "zcat" ; 66 | else if ( pc-filename > 3 && strcmp(pc-3,"bz2") == 0 ) 67 | unzipper = "bzcat" ; 68 | else 69 | unzipper = "" ; 70 | } else if( strcmp(unzipper,"cat") == 0 ) 71 | unzipper = "" ; 72 | 73 | if( *unzipper ) { 74 | int pid, status, outfd ; 75 | #if HAVE_MMAP 76 | xcfstream = tmpfile() ; 77 | if( !xcfstream ) 78 | FatalUnexpected(_("!Cannot create temporary unzipped file")); 79 | outfd = fileno(xcfstream) ; 80 | #else 81 | int fh[2] ; 82 | if( pipe(fh) < 0 ) 83 | FatalUnexpected("!Cannot create pipe for %s",unzipper); 84 | xcfstream = fdopen(fh[1],"rb") ; 85 | if( !xcfstream ) 86 | FatalUnexpected("!Cannot fdopen() unzipper pipe"); 87 | outfd = fh[0] ; 88 | #endif 89 | if( (pid = fork()) == 0 ) { 90 | /* We're the child */ 91 | if( dup2(outfd,1) < 0 ) { 92 | perror("Cannot dup2 in unzip process"); 93 | exit(127) ; 94 | } 95 | fclose(xcfstream) ; 96 | execlp(unzipper,unzipper,filename,NULL) ; 97 | fprintf(stderr,_("Cannot execute ")); 98 | perror(unzipper); 99 | exit(126) ; 100 | } 101 | #if HAVE_MMAP 102 | while( wait(&status) != pid ) 103 | ; 104 | if( WIFEXITED(status) ) { 105 | status = WEXITSTATUS(status) ; 106 | if( status > 0 ) { 107 | fclose(xcfstream) ; 108 | xcfstream = 0 ; 109 | FatalGeneric(status,NULL); 110 | } 111 | } else { 112 | fclose(xcfstream) ; 113 | xcfstream = 0 ; 114 | FatalGeneric(126,_("%s terminated abnormally"),unzipper); 115 | } 116 | #else 117 | close(fh[0]) ; 118 | #endif 119 | } else if( strcmp(filename,"-") == 0 ) { 120 | xcfstream = fdopen(dup(0),"rb") ; 121 | if( !xcfstream ) 122 | FatalUnexpected("!Cannot dup stdin for input") ; 123 | } else { 124 | xcfstream = fopen(filename,"rb") ; 125 | if( !xcfstream ) 126 | FatalGeneric(21,_("!Cannot open %s"),filename); 127 | } 128 | /* OK, now we have an open stream ... */ 129 | if( fstat(fileno(xcfstream),&statbuf) == 0 && 130 | (statbuf.st_mode & S_IFMT) == S_IFREG ) { 131 | xcf_length = statbuf.st_size ; 132 | #if HAVE_MMAP 133 | xcf_file = mmap(0,xcf_length,PROT_READ,MAP_SHARED,fileno(xcfstream),0); 134 | if( xcf_file != (void*)-1 ) 135 | return ; 136 | if( errno != ENODEV ) { 137 | int saved = errno ; 138 | fclose(xcfstream) ; 139 | xcf_file = 0 ; 140 | errno = saved ; 141 | FatalUnexpected("!Could not mmap input"); 142 | } 143 | #endif 144 | xcf_file = malloc(xcf_length); 145 | if( xcf_file == 0 ) 146 | FatalUnexpected(_("Out of memory for xcf data")); 147 | if( fread(xcf_file,1,xcf_length,xcfstream) != xcf_length ) { 148 | if( feof(xcfstream) ) 149 | FatalUnexpected(_("XCF file shrunk while reading it")); 150 | else 151 | FatalUnexpected(_("!Could not read xcf data")); 152 | } 153 | fclose(xcfstream) ; 154 | xcfstream = 0 ; 155 | } else { 156 | size_t blocksize = 0x80000 ; /* 512 KB */ 157 | xcf_length = 0 ; 158 | xcf_file = 0 ; 159 | while(1) { 160 | xcf_file = realloc(xcf_file,blocksize) ; 161 | if( xcf_file == 0 ) 162 | FatalUnexpected(_("Out of memory for xcf data")); 163 | size_t actual = fread(xcf_file+xcf_length,1,blocksize-xcf_length, 164 | xcfstream) ; 165 | xcf_length += actual ; 166 | if( feof(xcfstream) ) 167 | break ; 168 | if( xcf_length < blocksize ) { 169 | FatalUnexpected(_("!Could not read xcf data")) ; 170 | } 171 | blocksize += (blocksize >> 1) & ~(size_t)0x3FFF ; /* 16 KB granularity */ 172 | } 173 | fclose(xcfstream) ; 174 | xcfstream = 0 ; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /mancombine.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # This script compiles final manpages for xcftools 3 | # 4 | # This file was written by Henning Makholm 5 | # It is hereby in the public domain. 6 | # 7 | # In jurisdictions that do not recognise grants of copyright to the 8 | # public domain: I, the author and (presumably, in those jurisdictions) 9 | # copyright holder, hereby permit anyone to distribute and use this code, 10 | # in source code or binary form, with or without modifications. This 11 | # permission is world-wide and irrevocable. 12 | # 13 | # Of course, I will not be liable for any errors or shortcomings in the 14 | # code, since I give it away without asking any compenstations. 15 | # 16 | # If you use or distribute this code, I would appreciate receiving 17 | # credit for writing it, in whichever way you find proper and customary. 18 | 19 | use strict ; use warnings ; 20 | 21 | if( @ARGV != 1 ) { 22 | print STDERR "Usage: $0 infile.10\n" ; 23 | exit 1 ; 24 | } 25 | 26 | my %defs ; 27 | 28 | sub copyfile($); 29 | sub copyfile($) { 30 | my ($fn) = @_ ; 31 | local *FILE ; 32 | open FILE, "<", $fn or die "Cannot read $fn" ; 33 | my $ignore = 0 ; 34 | while( ) { 35 | if( /^\#else/ ) { 36 | if( $ignore ) { 37 | $ignore-- ; 38 | } else { 39 | $ignore = 1 ; 40 | } 41 | } elsif( /^\#endif/ ) { 42 | $ignore-- if $ignore ; 43 | print ".\\\"---\n" unless $ignore ; 44 | } elsif( $ignore ) { 45 | if( /^\#if/ ) { 46 | $ignore++ ; 47 | } 48 | } elsif( /^\#ifdef\s+(\S+)/ ) { 49 | print ".\\\"---\n" ; 50 | $ignore = 1 unless $defs{$1} ; 51 | } elsif( /^\s*.so\s*(.*)/ ) { 52 | copyfile($1) ; 53 | } else { 54 | print ; 55 | } 56 | } 57 | } 58 | 59 | 60 | if( open CONFIG, "<", "config.h" ) { 61 | while( ) { 62 | if( /^#define\s+(\S*)/ ) { 63 | $defs{$1} = 1 ; 64 | } 65 | } 66 | close CONFIG ; 67 | } 68 | 69 | my $fn0 = $ARGV[0] ; 70 | $fn0 =~ s/\.\d*$// ; 71 | $defs{"\U$fn0"} = 1 ; 72 | $defs{"XCF2FOO"} = 1 if $fn0 =~ /^xcf2/ ; 73 | 74 | copyfile($ARGV[0]) ; 75 | -------------------------------------------------------------------------------- /manpo/.cvsignore: -------------------------------------------------------------------------------- 1 | *.1 2 | stamp 3 | all 4 | 5 | -------------------------------------------------------------------------------- /manpo/da.po: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/manpo/da.po -------------------------------------------------------------------------------- /manpo/mantranslate.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # This script extracts translateable strings from a manpage and/or 3 | # translates a manpage using gettext. 4 | # 5 | # This file was written by Henning Makholm 6 | # It is hereby in the public domain. 7 | # 8 | # In jurisdictions that do not recognise grants of copyright to the 9 | # public domain: I, the author and (presumably, in those jurisdictions) 10 | # copyright holder, hereby permit anyone to distribute and use this code, 11 | # in source code or binary form, with or without modifications. This 12 | # permission is world-wide and irrevocable. 13 | # 14 | # Of course, I will not be liable for any errors or shortcomings in the 15 | # code, since I give it away without asking any compenstations. 16 | # 17 | # If you use or distribute this code, I would appreciate receiving 18 | # credit for writing it, in whichever way you find proper and customary. 19 | 20 | use strict ; use warnings ; 21 | 22 | my ($gettext,$shipout) ; 23 | 24 | sub fontexpand1($$) { 25 | my ($kinds,$text) = @_ ; 26 | return "\\f$kinds$text\\fP" if 1 == length $kinds ; 27 | my $out = "" ; 28 | my $last = "R" ; 29 | while( $text ) { 30 | $kinds =~ s/^(.)(.*)/$2$1/ ; 31 | $last = $1 ; 32 | if( $text =~ s/^([^\" ]+)\s*// || 33 | $text =~ s/^"([^\"]+)"\s*// ) { 34 | $out .= "\\f$last$1" ; 35 | } else { 36 | die "Bad font-change tail '$text'" ; 37 | } 38 | } 39 | $out .= "\\fR" unless $last eq "R" ; 40 | return $out ; 41 | } 42 | 43 | 44 | sub ggettext($$$) { 45 | my ($filename,$lineno,$text) = @_ ; 46 | return $text if $text =~ /^\d*$/ ; 47 | $text =~ s/\\\".*//g ; 48 | $text =~ s/\\\*p/%s/g ; 49 | $text =~ s/([^-])\\(-[a-zA-Z])/$1$2/g ; 50 | $text =~ s/^\.([BIR]+)\s+(.*)$/ fontexpand1($1,$2) /mge ; 51 | my $fontcode = $text !~ /[{}]/ ; 52 | if( $fontcode ) { 53 | $text =~ s/\\f([BI])(([^\\]|\\[^f])*)\\f[RP]/$1\{$2\}/mg ; 54 | } 55 | my $newline = $text =~ s/\n$//s ; 56 | if( $text !~ /^[.\']/m || $text =~ /\n/ ) { 57 | $text =~ s/\s+/ /gs ; 58 | my $pre = "" ; 59 | while( length($text) > 65 ) { 60 | $text =~ s/^(.{1,65}) // or $text =~ s/^([^ ]*) // ; 61 | $pre .= "$1\n" ; 62 | } 63 | $text = "$pre$text" ; 64 | $text =~ s/\s*$// ; 65 | } 66 | $text = $gettext->($filename,$lineno,$text); 67 | $text .= "\n" if $newline ; 68 | if( $fontcode ) { 69 | $text =~ s/([BI])\{([^{}]*)\}/\\f$1$2\\fP/g ; 70 | } 71 | $text =~ s/([^-])(-[a-zA-Z])/$1\\$2/g ; 72 | $text =~ s/%s/\\*p/g ; 73 | return $text ; 74 | } 75 | 76 | sub partraverse { 77 | my ($filename,$lineno,@lines) = @_ ; 78 | return unless @lines ; 79 | my @front ; 80 | foreach my $line ( @lines ) { 81 | if( @front && 82 | $front[$#front] =~ /\.\)?\s*$/ && 83 | $line =~ /^\(?[A-Z]/ ) { 84 | $shipout->(ggettext($filename,$lineno,join "",@front)); 85 | $lineno += @front ; 86 | @front = () ; 87 | } 88 | push @front, $line ; 89 | } 90 | $shipout->(ggettext($filename,$lineno,join "",@front)); 91 | } 92 | 93 | sub traverser($) { 94 | my ($filename) = @_ ; 95 | open MAN, "<", $filename or die "Cannot open $filename" ; 96 | my $lineno = 0 ; 97 | my @saved = () ; 98 | while( ) { 99 | $lineno++ ; 100 | if( /^([^.\'\#]|.([BI]|[BRI][IRB]) )/ ) { 101 | push @saved, $_ ; 102 | next ; 103 | } 104 | if( @saved ) { 105 | partraverse($filename,$lineno-@saved,@saved); 106 | @saved = () ; 107 | } 108 | if( /^#line (\d+) \"(.*)\"/ ) { 109 | my ($newline,$newfile) = ($1,$2); 110 | $filename = $newfile ; 111 | $lineno = $newline-1 ; 112 | } elsif( /^\#/ ) { 113 | # Ok, breaking the translation block is all we need. 114 | } elsif( /^\.\\\"-+$/ ){ 115 | # Another way to request block breaking. 116 | } elsif( /^\.(\\\"|TH|so|P|IP|ds)($| )/ ) { 117 | $shipout->($_) ; 118 | } elsif( /^\.(SH) (.*)$/ ) { 119 | $shipout->(".$1 ".ggettext($filename,$lineno,$2)."\n") ; 120 | } elsif( /^\.TP/ ) { 121 | $shipout->($_) ; 122 | $_ = ; $lineno++ ; 123 | if( /^\\fB\\-/ ) { 124 | s/\\fI(.*?)\\fR/ 125 | "\\fI".ggettext($filename,$lineno,$1)."\\fR"/ge ; 126 | $shipout->($_) ; 127 | } else { 128 | partraverse($filename,$lineno,$_) ; 129 | } 130 | } else { 131 | /^.?(.?.?)/ ; 132 | die "$filename:$lineno: unsupported request .$1\n" ; 133 | } 134 | } 135 | if( @saved ) { 136 | partraverse($filename,$lineno-@saved,@saved); 137 | } 138 | close MAN ; 139 | } 140 | 141 | 142 | if( @ARGV && $ARGV[0] eq '-x' ) { 143 | shift @ARGV ; 144 | my %seenwhere = () ; 145 | my @strings = () ; 146 | $gettext = sub { 147 | my ($file,$line,$text) = @_ ; 148 | push @strings, $text unless exists $seenwhere{$text} ; 149 | push @{$seenwhere{$text}}, "$file:$line" ; 150 | }; 151 | $shipout = sub {} ; 152 | for my $filename ( @ARGV ) { 153 | traverser($filename) ; 154 | } 155 | my $date = `date "+%Y-%m-%d %H:%M%z"` ; 156 | chomp $date ; 157 | print << "EOF" ; 158 | # SOME DESCRIPTIVE TITLE. 159 | # This file is put in the public domain. 160 | # FIRST AUTHOR , YEAR. 161 | # 162 | #, fuzzy 163 | msgid "" 164 | msgstr "" 165 | "Project-Id-Version: Xcftools-manpages VERSION\\n" 166 | "Report-Msgid-Bugs-To: henning\@makholm.net\\n" 167 | "POT-Creation-Date: $date\\n" 168 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n" 169 | "Last-Translator: FULL NAME \\n" 170 | "Language-Team: LANGUAGE \\n" 171 | "MIME-Version: 1.0\\n" 172 | "Content-Type: text/plain; charset=CHARSET\\n" 173 | "Content-Transfer-Encoding: 8bit\\n" 174 | 175 | EOF 176 | ; 177 | for my $string ( @strings ) { 178 | print(join(" ","#:",@{$seenwhere{$string}}),"\n"); 179 | $string =~ s/([\\\"])/\\$1/g ; 180 | $string =~ s/\n$/\\n/ ; 181 | print "msgid \"" ; 182 | print(join "\\n\"\n \"",split /\n/, $string) ; 183 | print "\"\n"; 184 | print "msgstr \"\"\n\n" ; 185 | } 186 | exit 0 ; 187 | } 188 | 189 | if( @ARGV == 2 ) { 190 | my ($pofile,$manfile) = @ARGV ; 191 | open PO, "<", $pofile or die "Pofile $pofile not found" ; 192 | my %catalog ; 193 | my $msgid ; 194 | my $addto ; 195 | while( ) { 196 | # This is an extremely simple-minded parser. 197 | if( s/^\s*msgid\s+\"/\"/ ) { 198 | $msgid = "" ; 199 | $addto = \$msgid ; 200 | } elsif( s/^\s*msgstr\s+\"/\"/ ) { 201 | $catalog{$msgid} = "" ; 202 | $addto = \$catalog{$msgid} ; 203 | } 204 | if( /^\s*\"(.*)\"\s*$/ ) { 205 | $_ = $1 ; 206 | s/\\(.)/$1 eq 'n' ? "\n" : $1/ge ; 207 | $$addto .= $_ ; 208 | } 209 | } 210 | close PO ; 211 | $gettext = sub { 212 | my ($file,$line,$text) = @_ ; 213 | return $catalog{$text} if $catalog{$text} ; 214 | return $text ; 215 | }; 216 | $shipout = sub { 217 | print @_ ; 218 | }; 219 | traverser($manfile) ; 220 | exit 0 ; 221 | } 222 | 223 | print STDERR "Usage: $0 -x man-source-files\n" ; 224 | print STDERR " or: $0 pofile manfile\n" ; 225 | 226 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /manpo/optipot.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # This script extracts translatable manpage fragments from 3 | # option.i 4 | # 5 | # This file was written by Henning Makholm 6 | # It is hereby in the public domain. 7 | # 8 | # In jurisdictions that do not recognise grants of copyright to the 9 | # public domain: I, the author and (presumably, in those jurisdictions) 10 | # copyright holder, hereby permit anyone to distribute and use this code, 11 | # in source code or binary form, with or without modifications. This 12 | # permission is world-wide and irrevocable. 13 | # 14 | # Of course, I will not be liable for any errors or shortcomings in the 15 | # code, since I give it away without asking any compenstations. 16 | # 17 | # If you use or distribute this code, I would appreciate receiving 18 | # credit for writing it, in whichever way you find proper and customary. 19 | 20 | use strict ; use warnings ; 21 | 22 | my $masterfile = "options.i" ; 23 | 24 | open OPTIONS, "<", $masterfile or die "Cannot open $masterfile" ; 25 | 26 | while( ) { 27 | if( /OPTION\(([^,]*),([^,]*),(.*),\s*$/ ) { 28 | my ($option,$long,$help) = ($1,$2,$3) ; 29 | if( $help =~ s/^\s*\(([^()]+)\)\s*// ) { 30 | my $arg = $1 ; 31 | $arg =~ s/"([^\"]*)"/\\fB$1\\fP/g ; 32 | print "#line $. \"$masterfile\"\n.TP\n" ; 33 | print "\\fB\\-X\\fR \\fI$arg\\fR\n" ; 34 | } 35 | $_ = ; 36 | s/^\s*\(// ; 37 | print "#line $. \"$masterfile\"\n$_" ; 38 | while( ) { 39 | last if /^\s*\)\);/ ; 40 | s/^\s*// ; 41 | s/''/'/g ; 42 | print $_ ; 43 | } 44 | } 45 | } 46 | 47 | close OPTIONS ; 48 | -------------------------------------------------------------------------------- /mkenumsc.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # This short script extracts enum definitions from files stolen 3 | # from the Gimp's sources. 4 | # 5 | # This file was written by Henning Makholm 6 | # It is hereby in the public domain. 7 | # 8 | # In jurisdictions that do not recognise grants of copyright to the 9 | # public domain: I, the author and (presumably, in those jurisdictions) 10 | # copyright holder, hereby permit anyone to distribute and use this code, 11 | # in source code or binary form, with or without modifications. This 12 | # permission is world-wide and irrevocable. 13 | # 14 | # Of course, I will not be liable for any errors or shortcomings in the 15 | # code, since I give it away without asking any compenstations. 16 | # 17 | # If you use or distribute this code, I would appreciate receiving 18 | # credit for writing it, in whichever way you find proper and customary. 19 | 20 | use strict ; use warnings ; 21 | 22 | print "/* Autogenerated from ",@ARGV," */\n" ; 23 | print "#include \"enums.h\"\n" ; 24 | print "#define N_\n" ; 25 | print "#include \n" ; 26 | while(<>) { 27 | if( /^\s*typedef\s+enum\s/ ) { 28 | my @nodesc ; 29 | my @all ; 30 | my %desc ; 31 | my $enum ; 32 | $_ = <> ; 33 | /^\{\s*$/ or die "Expected opening brace" ; 34 | while( <> ) { 35 | if( s/^\s*,?(\w+)\s*(=\s*\d+)?,?\s*// ) { 36 | my $constant = $1 ; 37 | push @all, $constant ; 38 | if( m' desc="([^"]+)"' ) { 39 | $desc{$constant} = $1 ; 40 | } else { 41 | push @nodesc, $constant ; 42 | $desc{$constant} = $constant ; 43 | } 44 | } elsif( /^\}\s*(\w+)\s*;/ ) { 45 | $enum = $1 ; 46 | last ; 47 | } else { 48 | die "Unparseable line [$_]" ; 49 | } 50 | } 51 | die "Unexpected EOF" unless defined $enum ; 52 | if( @nodesc ) { 53 | my $prefix = $nodesc[0] ; 54 | $prefix =~ s/.$// ; 55 | for( @desc{@nodesc} ) { 56 | while( substr($_,0,length $prefix) ne $prefix ) { 57 | $prefix =~ s/.$// ; 58 | } 59 | } 60 | $prefix = length $prefix ; 61 | for( @desc{@nodesc} ) { 62 | $_ = substr($_,$prefix); 63 | $_ = "\u\L$_" ; 64 | s/_(.)/\U$1/g ; 65 | s/^Rle/RLE/; 66 | } 67 | my $suffix = substr($desc{$nodesc[0]},1) ; 68 | for( @desc{@nodesc} ) { 69 | while( substr($_,-length($suffix)) ne $suffix ) { 70 | goto nosuffix if $suffix eq "" ; 71 | $suffix =~ s/^.// ; 72 | } 73 | } 74 | $suffix = length $suffix ; 75 | $_ = substr($_,0,-$suffix) for @desc{@nodesc} ; 76 | nosuffix: ; 77 | } 78 | my $gettext = "" ; 79 | if( $enum ne "PropType" ) { 80 | $gettext = "N_" ; 81 | } 82 | my $buflen = 15 + length($enum); 83 | print "const char*\nshow$enum($enum x)\n{\n" ; 84 | print " static char buf[$buflen];\n switch(x) {\n" ; 85 | for my $c (@all) { 86 | print " case $c: return $gettext(\"$desc{$c}\");\n" ; 87 | } 88 | print " default: sprintf(buf,\"($enum:%d)\",(int)x);\n" ; 89 | print " return buf;\n }\n}\n"; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /mkenumsh.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # This short script extracts enum definitions from files stolen 3 | # from the Gimp's sources. 4 | # 5 | # This file was written by Henning Makholm 6 | # It is hereby in the public domain. 7 | # 8 | # In jurisdictions that do not recognise grants of copyright to the 9 | # public domain: I, the author and (presumably, in those jurisdictions) 10 | # copyright holder, hereby permit anyone to distribute and use this code, 11 | # in source code or binary form, with or without modifications. This 12 | # permission is world-wide and irrevocable. 13 | # 14 | # Of course, I will not be liable for any errors or shortcomings in the 15 | # code, since I give it away without asking any compenstations. 16 | # 17 | # If you use or distribute this code, I would appreciate receiving 18 | # credit for writing it, in whichever way you find proper and customary. 19 | 20 | use strict ; use warnings ; 21 | 22 | my @wantenums = qw( GimpImageBaseType 23 | GimpImageType 24 | GimpLayerModeEffects 25 | PropType 26 | XcfCompressionType 27 | GimpPrecision 28 | ); 29 | my %wantenums ; 30 | @wantenums{@wantenums} = (-1) x @wantenums ; 31 | 32 | my $last ; 33 | my @collect ; 34 | print join("\n * ","/* Extracted from",@ARGV),"\n * by $0\n */\n" ; 35 | while( <> ) { 36 | if( /^\s*typedef\s+enum\s/ ) { 37 | @collect = ($_) ; 38 | } elsif( /^\}\s+(\w+)\s*;/ && @collect ) { 39 | my $enum = $1 ; 40 | if( ++$wantenums{$enum} == 0 ) { 41 | if( $enum eq 'GimpLayerModeEffects' ) { 42 | push @collect, " ,GIMP_NORMAL_NOPARTIAL_MODE=-1\n" ; 43 | } 44 | push @collect, $_ ; 45 | print @collect ; 46 | print "const char *show$enum($enum);\n" ; 47 | print "#define ${enum}_LAST $last\n" ; 48 | } 49 | @collect = () ; 50 | } elsif( @collect ) { 51 | push @collect, $_ ; 52 | $last = $1 if /^\s*(\w+)/ ; 53 | } 54 | } 55 | for my $enum ( @wantenums ) { 56 | my $count = 1 + $wantenums{$enum} ; 57 | if( $count != 1 ) { 58 | print STDERR "$count definitions of $enum\n" ; 59 | } 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /mkopti.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # This script extracts option strings, longopt arrays and 3 | # manpage fragments for xcftools 4 | # 5 | # This file was written by Henning Makholm 6 | # It is hereby in the public domain. 7 | # 8 | # In jurisdictions that do not recognise grants of copyright to the 9 | # public domain: I, the author and (presumably, in those jurisdictions) 10 | # copyright holder, hereby permit anyone to distribute and use this code, 11 | # in source code or binary form, with or without modifications. This 12 | # permission is world-wide and irrevocable. 13 | # 14 | # Of course, I will not be liable for any errors or shortcomings in the 15 | # code, since I give it away without asking any compenstations. 16 | # 17 | # If you use or distribute this code, I would appreciate receiving 18 | # credit for writing it, in whichever way you find proper and customary. 19 | 20 | use strict ; use warnings ; 21 | 22 | my $mastersource = "options.i" ; 23 | 24 | my $target = shift ; 25 | my @defines = ( "\U$target", "OPTI_TARGET \"$target\"" ) ; 26 | push @defines, "\U$1foo" if $target =~ /^(xcf(2|to))/ ; 27 | push @defines, "XCF2FOO" if $target eq "xcfview" ; 28 | 29 | open INFILE, "-|", join(" ","cpp -imacros config.h", 30 | (map {(my $a = "-D$_")=~s/ /=/; $a} @defines), 31 | $mastersource) 32 | or die "Cannot preprocess options." ; 33 | 34 | open OUTFILE, ">", "$target.oi" 35 | or die "Cannot write $target.oi" ; 36 | print OUTFILE "/* Autogenerated by $0 $target */\n" ; 37 | print OUTFILE "#define $_\n" for @defines ; 38 | print OUTFILE "#define OPTIONGROUP(a,b)\n" ; 39 | 40 | my %manstrings ; 41 | my $mansection = '1i' ; 42 | my @desc ; 43 | my $optstring = "" ; 44 | 45 | print OUTFILE "#ifdef HAVE_GETOPT_LONG\n" ; 46 | print OUTFILE "static const struct option longopts[] = {\n" ; 47 | 48 | my $manref = undef ; 49 | my $parskip ; 50 | while( ) { 51 | next if /^#/ ; 52 | if( /^OPTION\(([^,]+),([^,]+),(.*),\s*/ ) { 53 | my ($short,$long,$desc) = ($1,$2,$3) ; 54 | my $hasarg = '' ; 55 | if( $desc =~ s/^\s*\(([^()]+)\)\s*// ) { 56 | $hasarg = $1 ; 57 | } 58 | my @long = split / /,$long ; 59 | my $longfordesc = $long[0] ; 60 | for my $l ( @long ) { 61 | my $long = $l ; 62 | $long =~ s/^--// 63 | or print STDERR "Long option $long should have dashes\n" ; 64 | print OUTFILE "\t{ \"$long\", ",$hasarg ? 1 : 0,", 0, $short},\n" ; 65 | } 66 | if( $short =~ s/^\s*'(.)'\s*$/-$1/ ) { 67 | unshift @long, $short ; 68 | $optstring .= $1 . ($hasarg && ':') ; 69 | } else { 70 | undef $short ; 71 | } 72 | if( @long ) { 73 | (my $descarg = $hasarg ) =~ s/\"//g ; 74 | $manref = \$manstrings{$mansection}{$long[0]} ; 75 | $long[0] =~ s/^(-[^-])/\\$1/ ; 76 | $$manref = "" ; 77 | my $next = ".TP 8\n" ; 78 | $hasarg =~ s/"([^\"]*)"/\\fB$1\\fP/g ; 79 | $hasarg = " \\fI$hasarg\\fR" if $hasarg ; 80 | for my $long ( @long ) { 81 | $$manref .= $next . "\\fB$long\\fR$hasarg" ; 82 | $next = ", " ; 83 | } 84 | $$manref .= "\n" ; 85 | $parskip = 1 ; 86 | push @desc, [$short || $long[0], 87 | $descarg, 88 | $desc, 89 | $short && $long[1] ] ; 90 | } 91 | } elsif( /^\s*\)\);/ ) { 92 | $manref = undef ; 93 | } elsif( defined $manref ) { 94 | s/^\s*// ; 95 | s/''/\'/g ; 96 | s/^\(\s*// if $parskip ; 97 | $$manref .= $_ ; 98 | $parskip = 0 ; 99 | } elsif( /^OPTIONGROUP\(([^(,)]+),([^(,)]*)\)/ ) { 100 | push @desc,$2 unless $mansection eq $1 ; 101 | $mansection = $1 ; 102 | } 103 | } 104 | print OUTFILE "{0}};\n" ; 105 | print OUTFILE "#define LONGALT(s) \" (\" s \")\"\n" ; 106 | print OUTFILE "#else\n" ; 107 | print OUTFILE "#define LONGALT(s) \"\"\n" ; 108 | print OUTFILE "#endif\n" ; 109 | close INFILE ; 110 | 111 | print OUTFILE "static void\nopt_usage(FILE *f)\n{\n" ; 112 | my %d15plus ; 113 | my $longest = 2 ; 114 | for my $desc ( @desc ) { 115 | next unless ref $desc ; 116 | my $l = length $$desc[0] ; 117 | my $x = $$desc[1] ; 118 | if( $x ) { 119 | next if exists($d15plus{$x}) && $d15plus{$x} >= $l+1 ; 120 | $d15plus{$x} = $l+1 ; 121 | } else { 122 | $longest = $l if $longest < length $l ; 123 | } 124 | } 125 | print OUTFILE " int i = $longest;\n int j;\n" ; 126 | 127 | for my $d15 ( sort keys %d15plus ) { 128 | print OUTFILE " j=strlen(_(\"$d15\"))+$d15plus{$d15}; if( j>i ) i=j;\n" ; 129 | } 130 | for my $desc ( @desc ) { 131 | unless( ref $desc ) { 132 | print OUTFILE " fprintf(f,\"%s:\\n\",_(\"$desc\"));\n" 133 | if $desc ; 134 | next ; 135 | } 136 | my ($optname,$d15,$helptext,$alternative) = @$desc ; 137 | my $d1l = length($optname) ; 138 | print OUTFILE (" fprintf(f,\" ",$optname); 139 | my $f2a = "i-$d1l,\"\"" ; 140 | if( $d15 ) { 141 | print OUTFILE " " ; 142 | $f2a = "i-".($d1l+1).",_(\"$d15\")" ; 143 | } 144 | print OUTFILE "%-*s %s" ; 145 | if( $alternative ) { 146 | print OUTFILE "\" LONGALT(\"$alternative\") \""; 147 | } 148 | print OUTFILE "\\n\",$f2a,\n _(\"$helptext\"));\n" ; 149 | } 150 | print OUTFILE "}\n" ; 151 | print OUTFILE "#undef LONGALT\n" ; 152 | print OUTFILE "#define OPTSTRING \"$optstring\"\n" ; 153 | close OUTFILE 154 | or die "Problems closing $target.oi" ; 155 | 156 | for $mansection ( keys %manstrings ) { 157 | my $hash = $manstrings{$mansection} ; 158 | 159 | open OUTFILE,">","$target.$mansection" 160 | or die "Cannot write $target.$mansection" ; 161 | print OUTFILE @$hash{sort { "\U$a" cmp "\U$b" or $b cmp $a } 162 | keys %$hash} ; 163 | close OUTFILE or die "Problems closing $target.$mansection" ; 164 | } 165 | 166 | 167 | -------------------------------------------------------------------------------- /mktablec.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # This short script creates fixed look-up tables for xcftools 3 | # 4 | # This file was written by Henning Makholm 5 | # It is hereby in the public domain. 6 | # 7 | # In jurisdictions that do not recognise grants of copyright to the 8 | # public domain: I, the author and (presumably, in those jurisdictions) 9 | # copyright holder, hereby permit anyone to distribute and use this code, 10 | # in source code or binary form, with or without modifications. This 11 | # permission is world-wide and irrevocable. 12 | # 13 | # Of course, I will not be liable for any errors or shortcomings in the 14 | # code, since I give it away without asking any compenstations. 15 | # 16 | # If you use or distribute this code, I would appreciate receiving 17 | # credit for writing it, in whichever way you find proper and customary. 18 | 19 | use strict ; use warnings ; 20 | 21 | sub shipsubarray (@) { 22 | while( @_ > 1 && $_[$#_] == 0 ) { 23 | pop @_ ; 24 | } 25 | my $last = pop @_ ; 26 | print " {" ; 27 | my $left = 75 ; 28 | for my $d ( (map{ $_ . "," } @_), "$last}," ) { 29 | if( length($d) > $left ) { 30 | print "\n " ; 31 | $left = 75 ; 32 | } 33 | print $d ; 34 | $left -= length($d) ; 35 | } 36 | print "\n" ; 37 | } 38 | 39 | my $precompute_it = 1 ; 40 | if( open CONFIGH, "<", "config.h" ) { 41 | $precompute_it = 0 ; 42 | while( ) { 43 | if( /\#\s*define\s+PRECOMPUTED_SCALETABLE/ ) { 44 | $precompute_it = 1 ; 45 | last ; 46 | } 47 | } 48 | close CONFIGH ; 49 | } 50 | 51 | print "/* Autogenerated by $0 */\n" ; 52 | print "#include \"pixels.h\"\n" ; 53 | print "#ifdef PRECOMPUTED_SCALETABLE\n" ; 54 | if( $precompute_it ) { 55 | print "const uint8_t scaletable[256][256] = {\n" ; 56 | for my $p ( 0..255 ) { 57 | shipsubarray( map { int(($p*$_+127)/255) } ( 0 .. 255 ) ); 58 | # This formula has the property that 59 | # scaletable[p][q] + scaletable[255-p][q] == q 60 | # for all uint8_t values of p and q. 61 | # This is important in order that a partially transparent 62 | # pixel does not change the color of the underlying pixel 63 | # unless the two pixels have different colors. 64 | } 65 | print "};\n" ; 66 | } else { 67 | print "#error PRECOMPUTED_SCALETABLE was not defined at generation time\n"; 68 | } 69 | print "#endif\n" ; 70 | 71 | if(0) { 72 | 73 | print "const uint8_t divtable[256][256] = {\n" ; 74 | for my $p ( 0..255 ) { 75 | shipsubarray( map { $_ >= $p ? 255 : int(0.5 + 255*$_/$p) } 76 | ( 0 .. 255 ) ); 77 | } 78 | print "};\n" ; 79 | 80 | } 81 | 82 | print "const rgba graytable[256] = {\n" ; 83 | for my $p ( 0..255 ) { 84 | print " (rgba)$p << RED_SHIFT | (rgba)$p << GREEN_SHIFT | (rgba)$p << BLUE_SHIFT,\n" ; 85 | } 86 | print "};\n" ; 87 | -------------------------------------------------------------------------------- /palette.c: -------------------------------------------------------------------------------- 1 | /* Palette-manipulation functions functions for xcftools 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "palette.h" 20 | #include 21 | 22 | #define HASH_SIZE 1711 23 | /* If I remember correctly, this size hash will be able to handle 24 | * either of 25 | * a) the Netscape cube with intensities 0x00, 0x33, 0x66, 0x99, 0xCC, xFF 26 | * b) the EGA cube with intensities 0x00, 0x55, 0xAA, 0xFF 27 | * c) the "CGA cube" with intensites 0x00, 0x80, 0xFF 28 | * d) a full 256-step grayscale 29 | * without collisions. It will also have a minimal number of collisions 30 | * (4) on a full 16-to-a-side cube with intensities 31 | * 0x00, 0x11, 0x22, ..., 0xDD, 0xEE, 0xFF. 32 | */ 33 | 34 | unsigned paletteSize ; 35 | rgba palette[MAX_PALETTE] ; 36 | static int masterhash[HASH_SIZE]; 37 | static int bucketlinks[MAX_PALETTE]; 38 | 39 | void 40 | init_palette_hash(void) 41 | { 42 | unsigned i ; 43 | for( i=0; i= 0 ) { 54 | if( palette[*target] == color ) 55 | return *target ; 56 | target = &bucketlinks[*target] ; 57 | } 58 | #if 0 59 | fprintf(stderr,"Palette[%u] = %08x (%u --> %d)\n",paletteSize,color, 60 | color % HASH_SIZE, *target); 61 | #endif 62 | if( paletteSize >= MAX_PALETTE ) 63 | return -1 ; 64 | *target = paletteSize ; 65 | palette[paletteSize] = color ; 66 | return paletteSize++ ; 67 | } 68 | 69 | static inline void 70 | unpalettify_row(rgba *row,unsigned ncols) 71 | { 72 | index_t *newrow = (index_t*) row ; 73 | unsigned i ; 74 | for( i=ncols; i--; ) { 75 | row[i] = palette[newrow[i]] ; 76 | } 77 | } 78 | 79 | int 80 | palettify_row(rgba *row,unsigned ncols) 81 | { 82 | index_t *newrow = (index_t*)row ; 83 | assert(sizeof(index_t) <= sizeof(rgba)); 84 | unsigned i ; 85 | for( i=0; i 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #ifndef PALETTE_H 20 | #define PALETTE_H 21 | 22 | #include "xcftools.h" 23 | #include "pixels.h" 24 | 25 | #define MAX_PALETTE 256 26 | extern rgba palette[MAX_PALETTE] ; 27 | extern unsigned paletteSize ; 28 | 29 | typedef uint8_t index_t ; 30 | 31 | void init_palette_hash(void); 32 | 33 | /* lookup_or_intern() returns a negative number if there is no room 34 | * for the color in the palette. 35 | */ 36 | int lookup_or_intern(rgba color); 37 | 38 | /* palettify_row will convert a row of 'rgba' values into a packed row 39 | * of 'uint8_t' indces. If it succeeds without running out of colormap 40 | * entries, it returns nonzero. On the other hand if it does run out 41 | * of colormap entries it returns zero _and_ undoes the conversions 42 | * already done, so that the row is still a full row of 'rgba' values 43 | * afterwards. 44 | */ 45 | int palettify_row(rgba *row,unsigned ncols); 46 | 47 | /* palettify_rows is like palettify_rows, but works on several 48 | * rows at a time. 49 | */ 50 | int palettify_rows(rgba *rows[],unsigned ncols,unsigned nlines); 51 | 52 | #endif /* PALETTE_H */ 53 | -------------------------------------------------------------------------------- /pixels.h: -------------------------------------------------------------------------------- 1 | /* Pixel and tile functions for xcftools 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #ifndef PIXELS_H 20 | #define PIXELS_H 21 | 22 | #include "xcftools.h" 23 | 24 | /* MACROS FOR INTERNAL PIXEL ORDERING HERE */ 25 | /*=========================================*/ 26 | /* In principle the internal representation of pixels may change. 27 | * - this was supposed to allow an optimization where a layer could 28 | * be represented as a pointer into the mmapped xcf file, if 29 | * alignment, bpp, and endianness agreed (the point was that the 30 | * pixel representation had to agree with the endianness). 31 | * 32 | * However, it turns out that the current Gimp _always_ saves images 33 | * with RLE encoding of tiles, so such an effort would be in vain. 34 | * 35 | * Just for modularity, nevertheless try to isolate knowledge of 36 | * the RGBA-to-machine-word packing in this section of the 37 | * header file. Define new macros if necessary. 38 | * 39 | * Given that we don't have to agree with the uncompressed 40 | * RLE format, we choose to have the alpha in the _least_ 41 | * significant byte on all archs - it is tested and used more 42 | * often than the visible channels. 43 | */ 44 | typedef uint32_t rgba ; 45 | 46 | #define ALPHA_SHIFT 0 47 | #define RED_SHIFT 8 48 | #define GREEN_SHIFT 16 49 | #define BLUE_SHIFT 24 50 | 51 | #define ALPHA(rgba) ((uint8_t)(rgba)) 52 | #define FULLALPHA(rgba) ((uint8_t)(rgba) == 255) 53 | #define NULLALPHA(rgba) ((uint8_t)(rgba) == 0) 54 | #define NEWALPHA(rgb,a) (((rgba)(rgb) & 0xFFFFFF00) + (a)) 55 | 56 | #ifdef PRECOMPUTED_SCALETABLE 57 | extern const uint8_t scaletable[256][256] ; 58 | #define INIT_SCALETABLE_IF(foo) ((void)0) 59 | #else 60 | extern uint8_t scaletable[256][256] ; 61 | extern int ok_scaletable ; 62 | void mk_scaletable(void); 63 | #define INIT_SCALETABLE_IF(foo) \ 64 | (ok_scaletable || !(foo) || (mk_scaletable(),0) ) 65 | #endif 66 | 67 | extern const rgba graytable[256] ; 68 | extern rgba colormap[256] ; 69 | extern unsigned colormapLength ; 70 | void initLayer(struct xcfLayer *); 71 | void initColormap(); 72 | 73 | int degrayPixel(rgba); /* returns -1 for non-gray pixels */ 74 | 75 | /* ******************************************************* */ 76 | 77 | #define TILEXn(dim,tx) \ 78 | ((tx)==(dim).tilesx ? (dim).c.r : (dim).c.l + ((tx)*TILE_WIDTH)) 79 | #define TILEYn(dim,ty) \ 80 | ((ty)==(dim).tilesy ? (dim).c.b : (dim).c.t + ((ty)*TILE_HEIGHT)) 81 | 82 | #if __i386__ 83 | /* This is probably the only common architecture where small constants 84 | * are more efficient for byte operations. 85 | */ 86 | typedef int8_t summary_t ; 87 | typedef short int refcount_t ; 88 | #else 89 | typedef int summary_t ; 90 | typedef int refcount_t ; 91 | #endif 92 | 93 | #define TILESUMMARY_UPTODATE 8 94 | #define TILESUMMARY_ALLNULL 4 95 | #define TILESUMMARY_ALLFULL 2 96 | #define TILESUMMARY_CRISP 1 /* everyting either null or full */ 97 | struct Tile { 98 | refcount_t refcount ; 99 | summary_t summary ; /* a combination of TIMESUMMARY_FOO constatns */ 100 | unsigned count ; 101 | rgba pixels[TILE_WIDTH * TILE_HEIGHT]; 102 | }; 103 | /* Actually, the Tile structures that get allocated many not have 104 | * room for that many pixels. We subtract the space for those we don't 105 | * use - which is Not Legal C, but ought to be portable. 106 | * OTOH, one can also use a static struct Tile for temporary storage. 107 | */ 108 | 109 | 110 | #define assertTileCompatibility(t1,t2) assert((t1)->count==(t2)->count) 111 | 112 | struct Tile *newTile(struct rect); 113 | struct Tile *forkTile(struct Tile*); 114 | void freeTile(struct Tile*); 115 | #define invalidateSummary(tile,mask) \ 116 | do{ assert((tile)->refcount==1); (tile)->summary &= mask; } while(0) 117 | summary_t __ATTRIBUTE__((pure)) tileSummary(struct Tile *); 118 | 119 | void fillTile(struct Tile*,rgba); 120 | 121 | /* applyMask() destructively changes tile, 122 | * applyMask() gets ownership of mask 123 | */ 124 | void applyMask(struct Tile *tile, struct Tile *mask); 125 | 126 | struct Tile *getLayerTile(struct xcfLayer *,const struct rect *); 127 | 128 | #endif /* FLATTEN_H */ 129 | -------------------------------------------------------------------------------- /po/.cvsignore: -------------------------------------------------------------------------------- 1 | xcftools.pot 2 | stamp 3 | *.mo 4 | -------------------------------------------------------------------------------- /po/da.po: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/po/da.po -------------------------------------------------------------------------------- /po/xcftools.pot: -------------------------------------------------------------------------------- 1 | # SOME DESCRIPTIVE TITLE. 2 | # This file is put in the public domain. 3 | # FIRST AUTHOR , YEAR. 4 | # 5 | #, fuzzy 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PACKAGE VERSION\n" 9 | "Report-Msgid-Bugs-To: henning@makholm.net\n" 10 | "POT-Creation-Date: 2009-07-03 13:55+0200\n" 11 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language-Team: LANGUAGE \n" 14 | "MIME-Version: 1.0\n" 15 | "Content-Type: text/plain; charset=CHARSET\n" 16 | "Content-Transfer-Encoding: 8bit\n" 17 | 18 | #: xcfinfo.oi:24 xcfinfo.oi:35 xcf2pnm.oi:48 xcf2pnm.oi:64 xcf2png.oi:45 19 | #: xcf2png.oi:61 xcfview.oi:45 xcfview.oi:61 20 | msgid "command" 21 | msgstr "" 22 | 23 | #: xcfinfo.oi:26 xcf2pnm.oi:55 xcf2png.oi:52 xcfview.oi:52 24 | msgid "show this message" 25 | msgstr "" 26 | 27 | #: xcfinfo.oi:28 xcf2pnm.oi:57 xcf2png.oi:54 xcfview.oi:54 28 | msgid "show version" 29 | msgstr "" 30 | 31 | #: xcfinfo.oi:30 xcf2pnm.oi:59 xcf2png.oi:56 xcfview.oi:56 32 | msgid "show progress messages" 33 | msgstr "" 34 | 35 | #: xcfinfo.oi:32 xcf2pnm.oi:61 xcf2png.oi:58 xcfview.oi:58 36 | msgid "input is bzip2 compressed" 37 | msgstr "" 38 | 39 | #: xcfinfo.oi:34 xcf2pnm.oi:63 xcf2png.oi:60 xcfview.oi:60 40 | msgid "input is gzip compressed" 41 | msgstr "" 42 | 43 | #: xcfinfo.oi:36 xcf2pnm.oi:65 xcf2png.oi:62 xcfview.oi:62 44 | msgid "use 'command' to decompress input" 45 | msgstr "" 46 | 47 | #: xcfinfo.oi:38 xcf2pnm.oi:108 xcf2png.oi:99 xcfview.oi:98 48 | msgid "use UTF-8 for layer names" 49 | msgstr "" 50 | 51 | #: xcf2pnm.oi:47 xcf2pnm.oi:70 xcf2png.oi:44 xcf2png.oi:65 xcfview.oi:44 52 | #: xcfview.oi:65 xcf2png.c:147 53 | msgid "color" 54 | msgstr "" 55 | 56 | #: xcf2pnm.oi:49 xcf2pnm.oi:66 xcf2pnm.oi:68 xcf2png.oi:46 xcf2png.oi:63 57 | #: xcfview.oi:46 xcfview.oi:63 58 | msgid "filename" 59 | msgstr "" 60 | 61 | #: xcf2pnm.oi:50 xcf2pnm.oi:97 xcf2png.oi:47 xcf2png.oi:88 xcfview.oi:47 62 | #: xcfview.oi:87 63 | msgid "mode" 64 | msgstr "" 65 | 66 | #: xcf2pnm.oi:51 xcf2pnm.oi:99 xcf2pnm.oi:101 xcf2png.oi:48 xcf2png.oi:90 67 | #: xcf2png.oi:92 xcfview.oi:48 xcfview.oi:89 xcfview.oi:91 68 | msgid "n" 69 | msgstr "" 70 | 71 | #: xcf2pnm.oi:52 xcf2pnm.oi:90 xcf2png.oi:49 xcf2png.oi:81 xcfview.oi:49 72 | #: xcfview.oi:81 73 | msgid "wxh" 74 | msgstr "" 75 | 76 | #: xcf2pnm.oi:53 xcf2pnm.oi:92 xcf2png.oi:50 xcf2png.oi:83 xcfview.oi:50 77 | #: xcfview.oi:83 78 | msgid "x,y" 79 | msgstr "" 80 | 81 | #: xcf2pnm.oi:67 xcf2png.oi:64 xcfview.oi:64 82 | msgid "name output file" 83 | msgstr "" 84 | 85 | #: xcf2pnm.oi:69 86 | msgid "write transparency map" 87 | msgstr "" 88 | 89 | #: xcf2pnm.oi:71 xcf2png.oi:66 xcfview.oi:66 90 | msgid "select background color" 91 | msgstr "" 92 | 93 | #: xcf2pnm.oi:73 xcf2png.oi:68 xcfview.oi:68 94 | msgid "force alpha channel in output" 95 | msgstr "" 96 | 97 | #: xcf2pnm.oi:75 xcf2png.oi:70 xcfview.oi:70 98 | msgid "select color output" 99 | msgstr "" 100 | 101 | #: xcf2pnm.oi:77 xcf2png.oi:72 xcfview.oi:72 102 | msgid "select grayscale output" 103 | msgstr "" 104 | 105 | #: xcf2pnm.oi:79 106 | msgid "select monochrome output" 107 | msgstr "" 108 | 109 | #: xcf2pnm.oi:81 110 | msgid "select -c/-g/-m by image contents" 111 | msgstr "" 112 | 113 | #: xcf2pnm.oi:83 xcf2png.oi:74 xcfview.oi:74 114 | msgid "treat indexed images as RGB for flattening" 115 | msgstr "" 116 | 117 | #: xcf2pnm.oi:85 xcf2png.oi:76 xcfview.oi:76 118 | msgid "disallow partial transparency" 119 | msgstr "" 120 | 121 | #: xcf2pnm.oi:87 xcf2png.oi:78 xcfview.oi:78 122 | msgid "dissolve partial transparency" 123 | msgstr "" 124 | 125 | #: xcf2pnm.oi:89 xcf2png.oi:80 xcfview.oi:80 126 | msgid "flatten to memory; then analyse" 127 | msgstr "" 128 | 129 | #: xcf2pnm.oi:91 xcf2png.oi:82 xcfview.oi:82 130 | msgid "crop image while converting" 131 | msgstr "" 132 | 133 | #: xcf2pnm.oi:93 xcf2png.oi:84 xcfview.oi:84 134 | msgid "translate converted part of image" 135 | msgstr "" 136 | 137 | #: xcf2pnm.oi:95 xcf2png.oi:86 xcfview.oi:86 138 | msgid "autocrop to visible layer boundaries" 139 | msgstr "" 140 | 141 | #: xcf2pnm.oi:96 xcf2png.oi:87 142 | msgid "Layer-selection options" 143 | msgstr "" 144 | 145 | #: xcf2pnm.oi:98 xcf2png.oi:89 xcfview.oi:88 146 | msgid "set layer mode" 147 | msgstr "" 148 | 149 | #: xcf2pnm.oi:100 xcf2png.oi:91 xcfview.oi:90 150 | msgid "set opacity in percent" 151 | msgstr "" 152 | 153 | #: xcf2pnm.oi:102 xcf2png.oi:93 xcfview.oi:92 154 | msgid "set opacity in 1/255 units" 155 | msgstr "" 156 | 157 | #: xcf2pnm.oi:104 xcf2png.oi:95 xcfview.oi:94 158 | msgid "enable layer mask" 159 | msgstr "" 160 | 161 | #: xcf2pnm.oi:106 xcf2png.oi:97 xcfview.oi:96 162 | msgid "disable layer mask" 163 | msgstr "" 164 | 165 | #: options.i:167 166 | #, c-format 167 | msgid "Could not find X11 color database\n" 168 | msgstr "" 169 | 170 | #: options.i:171 171 | #, c-format 172 | msgid "Unknown background color '%s'" 173 | msgstr "" 174 | 175 | #: options.i:295 176 | #, c-format 177 | msgid "-S option must have an argument of the form wxh" 178 | msgstr "" 179 | 180 | #: options.i:314 181 | #, c-format 182 | msgid "-O option must have an argument of the form x,y" 183 | msgstr "" 184 | 185 | #: options.i:353 186 | #, c-format 187 | msgid "Layer mode '%s' is unknown" 188 | msgstr "" 189 | 190 | #: options.i:369 191 | #, c-format 192 | msgid "The argument to --percent is not a percentage" 193 | msgstr "" 194 | 195 | #: options.i:382 196 | #, c-format 197 | msgid "The argument to --opacity is not a number between 0 and 255" 198 | msgstr "" 199 | 200 | #: enums.c:10 201 | msgid "Normal" 202 | msgstr "" 203 | 204 | #: enums.c:11 205 | msgid "Dissolve" 206 | msgstr "" 207 | 208 | #: enums.c:12 209 | msgid "Behind" 210 | msgstr "" 211 | 212 | #: enums.c:13 213 | msgid "Multiply" 214 | msgstr "" 215 | 216 | #: enums.c:14 217 | msgid "Screen" 218 | msgstr "" 219 | 220 | #: enums.c:15 221 | msgid "Overlay" 222 | msgstr "" 223 | 224 | #: enums.c:16 225 | msgid "Difference" 226 | msgstr "" 227 | 228 | #: enums.c:17 229 | msgid "Addition" 230 | msgstr "" 231 | 232 | #: enums.c:18 233 | msgid "Subtract" 234 | msgstr "" 235 | 236 | #: enums.c:19 237 | msgid "DarkenOnly" 238 | msgstr "" 239 | 240 | #: enums.c:20 241 | msgid "LightenOnly" 242 | msgstr "" 243 | 244 | #: enums.c:21 245 | msgid "Hue" 246 | msgstr "" 247 | 248 | #: enums.c:22 249 | msgid "Saturation" 250 | msgstr "" 251 | 252 | #: enums.c:23 253 | msgid "Color" 254 | msgstr "" 255 | 256 | #: enums.c:24 257 | msgid "Value" 258 | msgstr "" 259 | 260 | #: enums.c:25 261 | msgid "Divide" 262 | msgstr "" 263 | 264 | #: enums.c:26 265 | msgid "Dodge" 266 | msgstr "" 267 | 268 | #: enums.c:27 269 | msgid "Burn" 270 | msgstr "" 271 | 272 | #: enums.c:28 273 | msgid "Hardlight" 274 | msgstr "" 275 | 276 | #: enums.c:29 277 | msgid "Softlight" 278 | msgstr "" 279 | 280 | #: enums.c:30 281 | msgid "GrainExtract" 282 | msgstr "" 283 | 284 | #: enums.c:31 285 | msgid "GrainMerge" 286 | msgstr "" 287 | 288 | #: enums.c:32 289 | msgid "ColorErase" 290 | msgstr "" 291 | 292 | #: enums.c:33 293 | msgid "Erase" 294 | msgstr "" 295 | 296 | #: enums.c:34 297 | msgid "Replace" 298 | msgstr "" 299 | 300 | #: enums.c:35 301 | msgid "AntiErase" 302 | msgstr "" 303 | 304 | #: enums.c:36 305 | msgid "NormalNopartial" 306 | msgstr "" 307 | 308 | #: enums.c:46 309 | msgid "RGB color" 310 | msgstr "" 311 | 312 | #: enums.c:47 enums.c:60 313 | msgid "Grayscale" 314 | msgstr "" 315 | 316 | #: enums.c:48 317 | msgid "Indexed color" 318 | msgstr "" 319 | 320 | #: enums.c:58 321 | msgid "RGB" 322 | msgstr "" 323 | 324 | #: enums.c:59 325 | msgid "RGB-alpha" 326 | msgstr "" 327 | 328 | #: enums.c:61 329 | msgid "Grayscale-alpha" 330 | msgstr "" 331 | 332 | #: enums.c:62 333 | msgid "Indexed" 334 | msgstr "" 335 | 336 | #: enums.c:63 337 | msgid "Indexed-alpha" 338 | msgstr "" 339 | 340 | #: enums.c:109 341 | msgid "None" 342 | msgstr "" 343 | 344 | #: enums.c:110 345 | msgid "RLE" 346 | msgstr "" 347 | 348 | #: enums.c:111 349 | msgid "Zlib" 350 | msgstr "" 351 | 352 | #: enums.c:112 353 | msgid "Fractal" 354 | msgstr "" 355 | 356 | #: flatspec.c:45 utils.c:105 357 | #, c-format 358 | msgid "Out of memory" 359 | msgstr "" 360 | 361 | #: flatspec.c:57 362 | #, c-format 363 | msgid "The %s option must follow a layer name on the command line" 364 | msgstr "" 365 | 366 | #: flatspec.c:144 367 | #, c-format 368 | msgid "The image has no layer called '%s'" 369 | msgstr "" 370 | 371 | #: flatspec.c:157 372 | #, c-format 373 | msgid "Layer '%s' has no layer mask to enable" 374 | msgstr "" 375 | 376 | #: flatspec.c:272 xcfinfo.c:97 377 | #, c-format 378 | msgid "/mask" 379 | msgstr "" 380 | 381 | #: flatspec.c:358 xcf2png.c:233 xcf2pnm.c:158 382 | #, c-format 383 | msgid "Grayscale output selected, but colored pixel(s) found" 384 | msgstr "" 385 | 386 | #: flatspec.c:362 xcf2pnm.c:172 387 | #, c-format 388 | msgid "Monochrome output selected, but not all pixels are black or white" 389 | msgstr "" 390 | 391 | #: flatten.c:388 392 | #, c-format 393 | msgid "'%s' layer mode" 394 | msgstr "" 395 | 396 | #: flatten.c:568 397 | #, c-format 398 | msgid "Flattened image has partially transparent pixels" 399 | msgstr "" 400 | 401 | #: flatten.c:674 402 | #, c-format 403 | msgid "Flattening image ..." 404 | msgstr "" 405 | 406 | #: io-unix.c:78 407 | #, c-format 408 | msgid "!Cannot create temporary unzipped file" 409 | msgstr "" 410 | 411 | #: io-unix.c:97 412 | #, c-format 413 | msgid "Cannot execute " 414 | msgstr "" 415 | 416 | #: io-unix.c:114 417 | #, c-format 418 | msgid "%s terminated abnormally" 419 | msgstr "" 420 | 421 | #: io-unix.c:126 422 | #, c-format 423 | msgid "!Cannot open %s" 424 | msgstr "" 425 | 426 | #: io-unix.c:146 io-unix.c:162 427 | #, c-format 428 | msgid "Out of memory for xcf data" 429 | msgstr "" 430 | 431 | #: io-unix.c:149 432 | #, c-format 433 | msgid "XCF file shrunk while reading it" 434 | msgstr "" 435 | 436 | #: io-unix.c:151 io-unix.c:169 437 | #, c-format 438 | msgid "!Could not read xcf data" 439 | msgstr "" 440 | 441 | #: pixels.c:134 442 | #, c-format 443 | msgid "Layer type %s" 444 | msgstr "" 445 | 446 | #: pixels.c:152 447 | #, c-format 448 | msgid "Color map has more than 256 entries" 449 | msgstr "" 450 | 451 | #: pixels.c:187 452 | #, c-format 453 | msgid "" 454 | "Unbelievably many layers?\n" 455 | "More likely to be a bug in %s" 456 | msgstr "" 457 | 458 | #: pixels.c:340 459 | #, c-format 460 | msgid "%s compression" 461 | msgstr "" 462 | 463 | #: utils.c:64 464 | msgid "Corrupted or malformed XCF file" 465 | msgstr "" 466 | 467 | #: utils.c:73 468 | msgid "Corrupted or truncated XCF file" 469 | msgstr "" 470 | 471 | #: utils.c:85 472 | msgid "The image contains features not understood by this program:" 473 | msgstr "" 474 | 475 | #: utils.c:94 476 | #, c-format 477 | msgid "Type \"%s -h\" to get an option summary.\n" 478 | msgstr "" 479 | 480 | #: utils.c:130 481 | #, c-format 482 | msgid "!Cannot create file %s" 483 | msgstr "" 484 | 485 | #: utils.c:154 486 | #, c-format 487 | msgid "!Error writing file %s" 488 | msgstr "" 489 | 490 | #: xcf-general.c:172 491 | #, c-format 492 | msgid "" 493 | "Warning: one or more layer names could not be\n" 494 | " translated to the local character set.\n" 495 | msgstr "" 496 | 497 | #: xcf-general.c:208 498 | #, c-format 499 | msgid "Not an XCF file at all (magic not recognized)" 500 | msgstr "" 501 | 502 | #: xcf-general.c:212 503 | #, c-format 504 | msgid "Warning: XCF version %d not supported (trying anyway...)\n" 505 | msgstr "" 506 | 507 | #: xcf2png.c:41 xcf2pnm.c:39 508 | #, c-format 509 | msgid "Usage: %s [options] filename.xcf[.gz] [layers]\n" 510 | msgstr "" 511 | 512 | #: xcf2png.c:43 xcf2pnm.c:41 xcfinfo.c:38 513 | #, c-format 514 | msgid "Options:\n" 515 | msgstr "" 516 | 517 | #: xcf2png.c:59 518 | #, c-format 519 | msgid "Libpng error '%s'" 520 | msgstr "" 521 | 522 | #: xcf2png.c:78 523 | #, c-format 524 | msgid "Couldn't initialize libpng library" 525 | msgstr "" 526 | 527 | #: xcf2png.c:147 528 | msgid "grayscale" 529 | msgstr "" 530 | 531 | #: xcf2png.c:148 532 | msgid "+palette" 533 | msgstr "" 534 | 535 | #: xcf2png.c:149 536 | msgid "+alpha" 537 | msgstr "" 538 | 539 | #: xcf2png.c:151 540 | msgid "+transparency" 541 | msgstr "" 542 | 543 | #: xcf2png.c:154 544 | #, c-format 545 | msgid " (%d colors)" 546 | msgstr "" 547 | 548 | #: xcf2pnm.c:65 549 | #, c-format 550 | msgid "Writing converted image as %s\n" 551 | msgstr "" 552 | 553 | #: xcf2pnm.c:66 554 | #, c-format 555 | msgid "Writing transparency map as %s\n" 556 | msgstr "" 557 | 558 | #: xcf2pnm.c:75 559 | #, c-format 560 | msgid " # Converted by xcf2pnm %s" 561 | msgstr "" 562 | 563 | #: xcf2pnm.c:77 564 | #, c-format 565 | msgid " # Transparency map by xcf2pnm %s" 566 | msgstr "" 567 | 568 | #: xcf2pnm.c:131 569 | #, c-format 570 | msgid "Transparency found, but -a option not given" 571 | msgstr "" 572 | 573 | #: xcf2pnm.c:193 574 | #, c-format 575 | msgid "The -a option was given, but the image has no transparency" 576 | msgstr "" 577 | 578 | #: xcfinfo.c:37 579 | #, c-format 580 | msgid "Usage: %s [options] filename.xcf[.gz]\n" 581 | msgstr "" 582 | 583 | #: xcfinfo.c:66 584 | #, c-format 585 | msgid "Only one XCF file per command line, please" 586 | msgstr "" 587 | 588 | #: xcfinfo.c:82 589 | #, c-format 590 | msgid "Version %d, %dx%d %s, %d layers, compressed %s\n" 591 | msgstr "" 592 | -------------------------------------------------------------------------------- /scaletab.c: -------------------------------------------------------------------------------- 1 | /* Run-time scaletable computation for Xcftools 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "pixels.h" 20 | #ifndef PRECOMPUTED_SCALETABLE 21 | 22 | uint8_t scaletable[256][256] ; 23 | int ok_scaletable = 0 ; 24 | 25 | void 26 | mk_scaletable(void) 27 | { 28 | unsigned p, q, r ; 29 | if( ok_scaletable ) return ; 30 | for( p = 0 ; p < 128 ; p++ ) 31 | for( q = 0 ; q <= p ; q++ ) { 32 | r = (p*q+127)/255 ; 33 | scaletable[p][q] = scaletable[q][p] = r ; 34 | scaletable[255-p][q] = scaletable[q][255-p] = q-r ; 35 | scaletable[p][255-q] = scaletable[255-q][p] = p-r ; 36 | scaletable[255-p][255-q] = scaletable[255-q][255-p] = (255-q)-(p-r) ; 37 | } 38 | ok_scaletable = 1 ; 39 | } 40 | 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | check: 2 | ./dotest -k 3 | $(MAKE) clean 4 | test: check 5 | clean: 6 | for a in * ; do case $$a in \ 7 | README | Makefile | dotest | pngtype.pl ) ;; \ 8 | * ) [ -d $$a ] || rm $$a ;; esac ; done 9 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | This regression test requires perl, bash, and some programs from 2 | netpbm: pngtopnm, pnmdepth and pgmtoppm. 3 | 4 | The expected outputs are stored as PNG files, which compress better 5 | than just gzipped PxM, but the output from xcf2png is not compared 6 | byte-to-byte with the stored files, because different libpng and zlib 7 | versions may take different, but legitimate, decisions about IDAT 8 | chunk division and compression. Instead pixel comparisions are 9 | done with cmp(1) on PxM representations, which have less possibility 10 | for variations. 11 | 12 | The test of xcftopnm assumes that the layout of the ascii header 13 | in the output from xcftopnm matches byte-for-byte what netpbm produces. 14 | There is an undocumented -@ switch that does this, but if you have a 15 | wildly different version of netpbm you may need to fiddle with the 16 | implementation of -@ and/or insert filters in the test driver 17 | routines. 18 | 19 | 20 | The test asssumes that xcftools has been compiled with an 21 | iconv() library that can expand non-ASCII characters to 22 | approximating ASCII sequenced, possibly triggered by the 23 | '//TRANSLIT' convention of glibc. If this is not the case 24 | you have to do appropriate corrections when the 'AE=AE' layer 25 | is mentioned by the test script. 26 | 27 | 28 | There are yet no tests for correct reporting of errors. 29 | 30 | 31 | 32 | Note: display(1) from imagemagick 6.0.6.2 apparently does not display 33 | PNG files with grayscale+alpha correctly - the alpha channel is 34 | ignored. -------------------------------------------------------------------------------- /test/answer/Addition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Addition.png -------------------------------------------------------------------------------- /test/answer/Burn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Burn.png -------------------------------------------------------------------------------- /test/answer/Color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Color.png -------------------------------------------------------------------------------- /test/answer/DarkenOnly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/DarkenOnly.png -------------------------------------------------------------------------------- /test/answer/Difference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Difference.png -------------------------------------------------------------------------------- /test/answer/Divide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Divide.png -------------------------------------------------------------------------------- /test/answer/Dodge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Dodge.png -------------------------------------------------------------------------------- /test/answer/GrainExtract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/GrainExtract.png -------------------------------------------------------------------------------- /test/answer/GrainMerge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/GrainMerge.png -------------------------------------------------------------------------------- /test/answer/Hardlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Hardlight.png -------------------------------------------------------------------------------- /test/answer/Hue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Hue.png -------------------------------------------------------------------------------- /test/answer/LightenOnly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/LightenOnly.png -------------------------------------------------------------------------------- /test/answer/Multiply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Multiply.png -------------------------------------------------------------------------------- /test/answer/Overlay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Overlay.png -------------------------------------------------------------------------------- /test/answer/Saturation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Saturation.png -------------------------------------------------------------------------------- /test/answer/Screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Screen.png -------------------------------------------------------------------------------- /test/answer/Subtract.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Subtract.png -------------------------------------------------------------------------------- /test/answer/Value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/Value.png -------------------------------------------------------------------------------- /test/answer/burmid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/burmid.png -------------------------------------------------------------------------------- /test/answer/comptest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/comptest.png -------------------------------------------------------------------------------- /test/answer/comptestB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/comptestB.png -------------------------------------------------------------------------------- /test/answer/crisp1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/crisp1.png -------------------------------------------------------------------------------- /test/answer/crisp2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/crisp2.png -------------------------------------------------------------------------------- /test/answer/doodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/doodle.png -------------------------------------------------------------------------------- /test/answer/gray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/gray.png -------------------------------------------------------------------------------- /test/answer/huetest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/huetest.png -------------------------------------------------------------------------------- /test/answer/i255t.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/i255t.png -------------------------------------------------------------------------------- /test/answer/i255tt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/i255tt.png -------------------------------------------------------------------------------- /test/answer/index255.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/index255.png -------------------------------------------------------------------------------- /test/answer/index256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/index256.png -------------------------------------------------------------------------------- /test/answer/index4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/index4.png -------------------------------------------------------------------------------- /test/answer/indextest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/indextest.png -------------------------------------------------------------------------------- /test/answer/masknoalpha-b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/masknoalpha-b.png -------------------------------------------------------------------------------- /test/answer/masknoalpha-g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/masknoalpha-g.png -------------------------------------------------------------------------------- /test/answer/masknoalpha-r.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/masknoalpha-r.png -------------------------------------------------------------------------------- /test/answer/masknoalpha-w.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/masknoalpha-w.png -------------------------------------------------------------------------------- /test/answer/mid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/mid.png -------------------------------------------------------------------------------- /test/answer/misc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/misc1.png -------------------------------------------------------------------------------- /test/answer/modeA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/modeA.png -------------------------------------------------------------------------------- /test/answer/modeB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/modeB.png -------------------------------------------------------------------------------- /test/answer/mono.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/mono.png -------------------------------------------------------------------------------- /test/answer/mono1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/mono1.png -------------------------------------------------------------------------------- /test/answer/odoodle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/odoodle.png -------------------------------------------------------------------------------- /test/answer/tiletest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/tiletest.png -------------------------------------------------------------------------------- /test/answer/zlib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/answer/zlib.png -------------------------------------------------------------------------------- /test/pngtype.pl: -------------------------------------------------------------------------------- 1 | use warnings ; 2 | use strict ; 3 | 4 | binmode(STDIN); 5 | 6 | my $a ; 7 | read STDIN,$a,8 ; 8 | if( $a ne "\x89PNG\x0d\x0a\x1a\x0a" ) { 9 | die "Malformed PNG header\n" ; 10 | } 11 | sub bv($) { 12 | ord(substr($a,$_[0],1)) ; 13 | } 14 | sub wv($) { 15 | my $a = shift ; 16 | return (bv($a) << 24) + (bv($a+1) << 16) + (bv($a+2)<<8) + bv($a+3); 17 | } 18 | my %all ; 19 | while( !eof STDIN ) { 20 | read STDIN,$a,4 ; 21 | my $len = wv(0); 22 | read STDIN,$a,$len+8 ; 23 | my $type = substr($a,0,4) ; 24 | next if $type eq 'IDAT' ; 25 | last if $type eq 'IEND' ; 26 | if( $type eq 'IHDR' && $len == 13 ) { 27 | print wv(4),"x",wv(8),"x",bv(12),"\n" ; 28 | my $cmode = bv(13) ; 29 | print $cmode & 3 ? "color" : "gray" ; 30 | print "+index" if $cmode & 1 ; 31 | print "+alpha" if $cmode & 4 ; 32 | print "\nz",bv(14)," f",bv(15)," i",bv(16),"\n" ; 33 | next ; 34 | } 35 | my $aref = ($all{$type} ||= []) ; 36 | push @$aref, "$type($len)" ; 37 | { 38 | my $w = 16 ; 39 | $w = 24 if $type eq 'PLTE' ; 40 | $w = 8 if $type eq 'tRNS' ; 41 | for my $i ( 0 .. $len - 1 ) { 42 | push @$aref, sprintf("%s%02X", $i%$w ? " " : "\n ", bv($i+4) ) ; 43 | push @$aref, " " if 44 | $type eq 'PLTE' && 45 | $i%3 == 2 && 46 | ($i+1)%$w != 0 && 47 | $i != $len-1 ; 48 | } 49 | push @$aref, "\n" ; 50 | } 51 | } 52 | for my $k ( sort keys %all ) { 53 | print @{$all{$k}} ; 54 | } 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /test/source/badindexed0.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/badindexed0.xcf.gz -------------------------------------------------------------------------------- /test/source/comptest.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/comptest.xcf.gz -------------------------------------------------------------------------------- /test/source/huetest.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/huetest.xcf.gz -------------------------------------------------------------------------------- /test/source/i255.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/i255.xcf.gz -------------------------------------------------------------------------------- /test/source/i256.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/i256.xcf.gz -------------------------------------------------------------------------------- /test/source/indextest.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/indextest.xcf.gz -------------------------------------------------------------------------------- /test/source/masknoalpha.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/masknoalpha.xcf.gz -------------------------------------------------------------------------------- /test/source/mkbase.i: -------------------------------------------------------------------------------- 1 | /* -*- C -*- 2 | * This program is written by Henning Makholm, and is in the 3 | * public domain. 4 | */ 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | static void 11 | error(png_structp png_ptr, png_const_charp errormsg) 12 | { 13 | fprintf(stderr,"PNG error: %s\n",errormsg); 14 | exit(1); 15 | } 16 | 17 | 18 | int 19 | main(void) 20 | { 21 | png_structp libpng = NULL ; 22 | png_infop libpng2 = NULL ; 23 | unsigned char row[TEST_IMAGE_WIDTH*4] ; 24 | unsigned x,y ; 25 | int r,g,b,a ; 26 | 27 | libpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, 28 | png_voidp_NULL, 29 | error, 30 | png_error_ptr_NULL); 31 | if( !libpng ) 32 | error(libpng,"Couldn't initialize libpng library"); 33 | 34 | libpng2 = png_create_info_struct(libpng); 35 | if( !libpng2 ) 36 | error(libpng,"Couldn't create PNG info structure"); 37 | 38 | png_init_io(libpng,stdout); 39 | 40 | png_set_IHDR(libpng,libpng2,TEST_IMAGE_WIDTH,TEST_IMAGE_HEIGHT, 41 | 8, PNG_COLOR_TYPE_RGB_ALPHA, 42 | PNG_INTERLACE_NONE, 43 | PNG_COMPRESSION_TYPE_DEFAULT, 44 | PNG_FILTER_TYPE_DEFAULT); 45 | 46 | png_write_info(libpng,libpng2); 47 | 48 | for( y=0; y= 61 ) { 11 | *a = 0 ; 12 | return ; 13 | } 14 | if( y < 3 || y >= 61 || 15 | x < 6 || x >= 58 ) { 16 | *a = 255 ; 17 | *r=*g=*b= 255*(x>=32) ; 18 | return ; 19 | } 20 | x -= 6 ; 21 | if( x <= 17 ) { 22 | *a = x*15 ; 23 | *r = 255 ; 24 | *g = 0 ; 25 | *b = 17*7 ; 26 | return ; 27 | } 28 | *a = 255 ; 29 | x -= 17 ; 30 | if( x <= 17 ) { 31 | *r = 255 ; 32 | *g = x*15 ; 33 | *b = (17-x)*7 ; 34 | return ; 35 | } 36 | x -= 17 ; 37 | if( x <= 17 ) { 38 | *r = (17-x)*15 ; 39 | *g = (17-x)*15 ; 40 | *b = (x-1)*15 ; 41 | return ; 42 | } 43 | *r=255 ; 44 | *g=*b=0 ; 45 | } 46 | 47 | #include "mkbase.i" 48 | -------------------------------------------------------------------------------- /test/source/mktile0.pl: -------------------------------------------------------------------------------- 1 | $L = 64 ; 2 | print "P3 $L $L 255\n" ; 3 | for $y ( 0 .. $L-1 ) { 4 | for $x ( 0 .. $L-1 ) { 5 | $m = int($y / 4)*16 + int($x/4) ; 6 | if( $m < 216 ) { 7 | print( 51 * ($m % 6), " ", 8 | 51 * (int($m/6) % 6), " ", 9 | 51 * (int($m/36)), "\n" ); 10 | } else { 11 | $m = ($m-216) * 6 + 10 ; 12 | print( "$m $m $m\n" ); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/source/mktile1.c: -------------------------------------------------------------------------------- 1 | /* This program is written by Henning Makholm, and is in the 2 | * public domain. 3 | */ 4 | 5 | #define TEST_IMAGE_WIDTH 50 6 | #define TEST_IMAGE_HEIGHT 50 7 | 8 | #include 9 | #include 10 | 11 | void 12 | makepixel(int x,int y,int *r,int *g,int *b,int *a) { 13 | double yy = 2*(double)y/(TEST_IMAGE_HEIGHT-1) - 1 ; 14 | double xx = 2*(double)x/(TEST_IMAGE_WIDTH-1) - 1 ; 15 | double rad = sqrt(xx*xx+yy*yy) ; 16 | unsigned t = x + abs((y - TEST_IMAGE_HEIGHT/2)) ; 17 | t = t / 10 + ((600 + y - TEST_IMAGE_HEIGHT/2) / 10)*77 ; 18 | if( rad < 0.9 ) 19 | *a = 255 ; 20 | else if( rad < 1 ) 21 | *a = 190 ; 22 | else if( rad < 1.2 ) 23 | *a = 73 ; 24 | else 25 | *a = 0 ; 26 | 27 | t *= 3847822 ; 28 | t ^= 29938132 ; 29 | t %= 2093847 ; 30 | *r = 120 * ((t >> 3) % 3) + 3 ; 31 | *g = 120 * ((t >> 7) % 3) + 3 ; 32 | *b = 120 * ((t >> 10) % 3) + 3 ; 33 | } 34 | 35 | #include "mkbase.i" 36 | -------------------------------------------------------------------------------- /test/source/modetest.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/modetest.xcf.gz -------------------------------------------------------------------------------- /test/source/tiletest-128.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/tiletest-128.xcf.gz -------------------------------------------------------------------------------- /test/source/tiletest-61.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/tiletest-61.xcf.gz -------------------------------------------------------------------------------- /test/source/tiletest.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/tiletest.xcf.gz -------------------------------------------------------------------------------- /test/source/truncated.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/truncated.xcf -------------------------------------------------------------------------------- /test/source/wide-pointers.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/wide-pointers.xcf.gz -------------------------------------------------------------------------------- /test/source/zlib.xcf.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/j-jorge/xcftools/be488bd2e35a0c6794141411cb5d290950ba4345/test/source/zlib.xcf.gz -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | /* Generic support functions for Xcftools 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "xcftools.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | const char *progname = "$0" ; 26 | int verboseFlag = 0 ; 27 | 28 | 29 | static void __ATTRIBUTE__((noreturn)) 30 | vFatalGeneric(int status,const char *format,va_list args) 31 | { 32 | if( format ) { 33 | if( *format == '!' ) { 34 | vfprintf(stderr,format+1,args); 35 | fprintf(stderr,": %s\n",strerror(errno)); 36 | } else { 37 | vfprintf(stderr,format,args); 38 | fputc('\n',stderr); 39 | } 40 | } 41 | exit(status); 42 | } 43 | 44 | void 45 | FatalGeneric(int status,const char* format,...) 46 | { 47 | va_list v; va_start(v,format); 48 | if( format ) fprintf(stderr,"%s: ",progname); 49 | vFatalGeneric(status,format,v); 50 | } 51 | 52 | void 53 | FatalUnexpected(const char* format,...) 54 | { 55 | va_list v; va_start(v,format); 56 | fprintf(stderr,"%s: ",progname); 57 | vFatalGeneric(127,format,v) ; 58 | } 59 | 60 | void 61 | FatalBadXCF(const char* format,...) 62 | { 63 | va_list v; va_start(v,format); 64 | fprintf(stderr,"%s: %s:\n ",progname,_("Corrupted or malformed XCF file")); 65 | vFatalGeneric(125,format,v) ; 66 | } 67 | 68 | void 69 | xcfCheckspace(xcfptr_t addr,int spaceafter,const char *format,...) 70 | { 71 | if( xcf_length < spaceafter || addr > xcf_length - spaceafter ) { 72 | va_list v; va_start(v,format); 73 | fprintf(stderr,"%s: %s\n ",progname,_("Corrupted or truncated XCF file")); 74 | fprintf(stderr,"(0x%" PRIXPTR " bytes): ",(uintptr_t)xcf_length); 75 | vFatalGeneric(125,format,v) ; 76 | } 77 | } 78 | 79 | 80 | void 81 | FatalUnsupportedXCF(const char* format,...) 82 | { 83 | va_list v; va_start(v,format); 84 | fprintf(stderr,"%s: %s\n ",progname, 85 | _("The image contains features not understood by this program:")); 86 | vFatalGeneric(123,format,v) ; 87 | } 88 | 89 | void 90 | gpl_blurb(void) 91 | { 92 | fprintf(stderr,PACKAGE_STRING "\n"); 93 | fprintf(stderr, 94 | _("Type \"%s -h\" to get an option summary.\n"),progname); 95 | exit(1) ; 96 | } 97 | 98 | /* ******************************************************* */ 99 | 100 | void * 101 | xcfmalloc(size_t size) 102 | { 103 | void *ptr = malloc(size); 104 | if( !ptr ) 105 | FatalUnexpected(_("Out of memory")); 106 | return ptr ; 107 | } 108 | 109 | void 110 | xcffree(void *block) 111 | { 112 | if( xcf_file && 113 | (uint8_t*)block >= xcf_file && 114 | (uint8_t*)block < xcf_file + xcf_length ) 115 | ; 116 | else 117 | free(block); 118 | } 119 | 120 | /* ******************************************************* */ 121 | 122 | FILE * 123 | openout(const char *name) 124 | { 125 | FILE *newfile ; 126 | if( strcmp(name,"-") == 0 ) 127 | return stdout ; 128 | newfile = fopen(name,"wb") ; 129 | if( newfile == NULL ) 130 | FatalUnexpected(_("!Cannot create file %s"),name); 131 | return newfile ; 132 | } 133 | 134 | void 135 | closeout(FILE *f,const char *name) 136 | { 137 | if( f == NULL ) 138 | return ; 139 | if( fflush(f) == 0 ) { 140 | errno = 0 ; 141 | if( !ferror(f) ) { 142 | if( fclose(f) == 0 ) 143 | return ; 144 | } else if( errno == 0 ) { 145 | /* Attempt to coax a valid errno out of the standard library, 146 | * following an idea by Bruno Haible 147 | * http://lists.gnu.org/archive/html/bug-gnulib/2003-09/msg00157.html 148 | */ 149 | if( fputc('\0', f) != EOF && 150 | fflush(f) == 0 ) 151 | errno = EIO ; /* Argh, everything succeds. Just call it an I/O error */ 152 | } 153 | } 154 | FatalUnexpected(_("!Error writing file %s"),name); 155 | } 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /xcf-general.c: -------------------------------------------------------------------------------- 1 | /* Generic functions for reading XCF files 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "xcftools.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #ifdef HAVE_ICONV 25 | # include 26 | #elif !defined(ICONV_CONST) 27 | # define ICONV_CONST const 28 | #endif 29 | 30 | uint8_t *xcf_file = 0 ; 31 | xcfptr_t xcf_length ; 32 | int use_utf8 = 0 ; 33 | 34 | xcfptr_t 35 | xcfOffset(xcfptr_t addr,int spaceafter) 36 | { 37 | xcfptr_t apparent ; 38 | xcfCheckspace(addr,4,"(xcfOffset)"); 39 | apparent = xcfP(addr); 40 | xcfCheckspace(apparent,spaceafter, 41 | "Too large offset (%" PRIXPTR ") at position %" PRIXPTR, 42 | apparent,addr); 43 | return apparent ; 44 | } 45 | 46 | int 47 | xcfNextprop(xcfptr_t *master,xcfptr_t *body) 48 | { 49 | xcfptr_t ptr ; 50 | uint32_t length, total, minlength ; 51 | PropType type ; 52 | ptr = *master ; 53 | xcfCheckspace(ptr,8,"(property header)"); 54 | type = xcfL(ptr); 55 | length = xcfL(ptr+4); 56 | *body = ptr+8 ; 57 | 58 | switch(type) { 59 | case PROP_COLORMAP: 60 | { 61 | uint32_t ncolors ; 62 | xcfCheckspace(ptr+8,4,"(colormap length)"); 63 | ncolors = xcfL(ptr+8) ; 64 | if( ncolors > 256 ) 65 | FatalBadXCF("Colormap has %" PRIu32 " entries",ncolors); 66 | /* Surprise! Some older verion of the Gimp computed the wrong length 67 | * word, and the _reader_ always just reads three bytes per color 68 | * and ignores the length tag! Duplicate this so we too can read 69 | * the buggy XCF files. 70 | */ 71 | length = minlength = 4+3*ncolors; 72 | break; 73 | } 74 | case PROP_COMPRESSION: minlength = 1; break; 75 | case PROP_OPACITY: minlength = 4; break; 76 | case PROP_APPLY_MASK: minlength = 4; break; 77 | case PROP_OFFSETS: minlength = 8; break; 78 | case PROP_MODE: minlength = 4; break; 79 | default: minlength = 0; break; 80 | } 81 | if( length < minlength ) 82 | FatalBadXCF("Short %s property at %" PRIXPTR " (%" PRIu32 "<%" PRIu32 ")", 83 | showPropType(type),ptr,length,minlength); 84 | *master = ptr+8+length ; 85 | total = 8 + length + (type != PROP_END ? 8 : 0) ; 86 | if( total < length ) /* Check overwrap */ 87 | FatalBadXCF("Overlong property at %" PRIXPTR, ptr); 88 | xcfCheckspace(ptr,total,"Overlong property at %" PRIXPTR,ptr) ; 89 | return type ; 90 | } 91 | 92 | const char* 93 | xcfString(xcfptr_t ptr,xcfptr_t *after) 94 | { 95 | uint32_t length ; 96 | unsigned i ; 97 | ICONV_CONST char *utf8master ; 98 | 99 | xcfCheckspace(ptr,4,"(string length)"); 100 | length = xcfL(ptr) ; 101 | ptr += 4 ; 102 | xcfCheckspace(ptr,length,"(string)"); 103 | utf8master = (ICONV_CONST char*)(xcf_file+ptr) ; 104 | if( after ) *after = ptr + length ; 105 | if( length == 0 || utf8master[length-1] != 0 ) 106 | FatalBadXCF("String at %" PRIXPTR " not zero-terminated",ptr-4); 107 | length-- ; 108 | 109 | if( use_utf8 ) return utf8master ; 110 | 111 | /* We assume that the local character set includes ASCII... 112 | * Check if conversion is needed at all 113 | */ 114 | for( i=0 ; ; i++ ) { 115 | if( i == length ) 116 | return utf8master ; /* Only ASCII after all */ 117 | if( utf8master[i] == 0 ) 118 | FatalBadXCF("String at %" PRIXPTR " has embedded zeroes",ptr-4); 119 | if( (int8_t) utf8master[i] < 0 ) 120 | break ; 121 | } 122 | #ifdef HAVE_ICONV 123 | { 124 | size_t targetsize = length+1 ; 125 | int sloppy_translation = 0 ; 126 | iconv_t cd = iconv_open("//TRANSLIT","UTF-8"); 127 | if( cd == (iconv_t) -1 ) { 128 | cd = iconv_open("","UTF-8"); 129 | sloppy_translation = 1 ; 130 | } 131 | if( cd == (iconv_t) -1 ) 132 | iconv_close(cd) ; /* Give up; perhaps iconv doesn't know UTF-8 */ 133 | else 134 | while(1) { 135 | char *buffer = xcfmalloc(targetsize) ; 136 | ICONV_CONST char *inbuf = utf8master ; 137 | char *outbuf = buffer ; 138 | size_t incount = length ; 139 | size_t outcount = targetsize ; 140 | while(1) { /* Loop for systems without //ICONV support */ 141 | size_t result = iconv(cd,&inbuf,&incount,&outbuf,&outcount) ; 142 | if( result == (size_t)-1 && errno == EILSEQ && 143 | sloppy_translation && outcount > 0 ) { 144 | *outbuf++ = '?' ; 145 | outcount-- ; 146 | while( (int8_t)*inbuf < 0 ) inbuf++, incount-- ; 147 | continue ; 148 | } 149 | if( result != (size_t)-1 ) { 150 | if( outcount == 0 ) 151 | errno = E2BIG ; 152 | else { 153 | *outbuf = 0 ; 154 | iconv_close(cd) ; 155 | return buffer ; 156 | } 157 | } 158 | break ; 159 | } 160 | if( errno == EILSEQ || errno == EINVAL ) 161 | FatalBadXCF("Bad UTF-8 encoding '%s' at %" PRIXPTR, 162 | inbuf,(uintptr_t)((inbuf-utf8master)+ptr)); 163 | if( errno == E2BIG ) { 164 | targetsize += 1+incount ; 165 | xcffree(buffer) ; 166 | continue ; 167 | } 168 | FatalUnexpected("!iconv on layer name at %"PRIXPTR,ptr); 169 | } 170 | } 171 | #endif 172 | { 173 | static int warned = 0 ; 174 | if( !warned ) { 175 | fprintf(stderr,_("Warning: one or more layer names could not be\n" 176 | " translated to the local character set.\n")); 177 | warned = 1 ; 178 | } 179 | } 180 | return utf8master ; 181 | } 182 | 183 | /* ****************************************************************** */ 184 | 185 | void 186 | computeDimensions(struct tileDimensions *d) 187 | { 188 | // [ CVE-2019-5086 and CVE-2019-5087 ] 189 | // This part of code is the check to prevent integer overflow, see 190 | // CVE-2019-5086 and CVE-2019-5087 191 | 192 | if ((d->c.l + d->width)*4 > INT_MAX) { 193 | fprintf(stderr,("Width is too large (%ld)! Stopping execution...\n"), 194 | (d->c.l + d->width)); 195 | exit(EXIT_FAILURE); 196 | } 197 | 198 | if ((d->c.t + d->height)*4 > INT_MAX) { 199 | fprintf(stderr,("Height is too large (%ld)! Stopping execution...\n"), 200 | (d->c.t + d->height)); 201 | exit(EXIT_FAILURE); 202 | } 203 | 204 | // [ CVE-2019-5086 and CVE-2019-5087 ] 205 | 206 | d->c.r = d->c.l + d->width ; 207 | d->c.b = d->c.t + d->height ; 208 | d->tilesx = (d->width+TILE_WIDTH-1)/TILE_WIDTH ; 209 | d->tilesy = (d->height+TILE_HEIGHT-1)/TILE_HEIGHT ; 210 | d->ntiles = d->tilesx * d->tilesy ; 211 | } 212 | 213 | struct xcfImage XCF ; 214 | 215 | void 216 | getBasicXcfInfo(void) 217 | { 218 | xcfptr_t ptr, data, layerfile ; 219 | PropType type ; 220 | int i, j ; 221 | 222 | xcfCheckspace(0,14+7*4,"(very short)"); 223 | if( strcmp((char*)xcf_file,"gimp xcf file") == 0 ) 224 | XCF.version = 0 ; 225 | else if( xcf_file[13] == 0 && 226 | sscanf((char*)xcf_file,"gimp xcf v%d",&XCF.version) == 1 ) 227 | ; 228 | else 229 | FatalBadXCF(_("Not an XCF file at all (magic not recognized)")); 230 | 231 | if(!( XCF.version >= 0 && XCF.version <= 3 ) && 232 | !( XCF.version >= 7 && XCF.version <= 12 )) { 233 | fprintf(stderr, 234 | _("Warning: XCF version %d not supported (trying anyway...)\n"), 235 | XCF.version); 236 | } 237 | 238 | XCF.compression = COMPRESS_NONE ; 239 | XCF.colormapptr = 0 ; 240 | 241 | ptr = 14 ; 242 | XCF.width = xcfL(ptr); ptr += 4 ; 243 | XCF.height = xcfL(ptr); ptr += 4 ; 244 | XCF.type = xcfL(ptr); ptr += 4 ; 245 | XCF.pformat = GIMP_PRECISION_U8_NON_LINEAR; 246 | if( XCF.version >= 4 ) { 247 | XCF.pformat = xcfL(ptr); ptr += 4 ; 248 | } 249 | if( XCF.pformat != GIMP_PRECISION_U8_NON_LINEAR ) { 250 | fprintf(stderr, 251 | _("Warning: XCF non-unorm8-gamma pixels format not supported (trying anyway...)\n")); 252 | } 253 | while( (type = xcfNextprop(&ptr,&data)) != PROP_END ) { 254 | switch(type) { 255 | case PROP_COLORMAP: 256 | XCF.colormapptr = data ; 257 | break ; 258 | case PROP_COMPRESSION: 259 | XCF.compression = xcf_file[data] ; 260 | break ; 261 | default: 262 | /* Ignore unknown properties */ 263 | break ; 264 | } 265 | } 266 | 267 | layerfile = ptr ; 268 | for( XCF.numLayers = 0 ; xcfOffset(ptr,8*4) ; XCF.numLayers++, ptr+=xcfPsz ) 269 | ; 270 | XCF.layers = xcfmalloc(XCF.numLayers * sizeof(struct xcfLayer)) ; 271 | for( i = 0 ; i < XCF.numLayers ; i++ ) { 272 | struct xcfLayer *L = XCF.layers + i ; 273 | ptr = xcfP(layerfile+xcfPsz*(XCF.numLayers-1-i)) ; 274 | 275 | L->mode = GIMP_NORMAL_MODE ; 276 | L->opacity = 255 ; 277 | L->isVisible = 1 ; 278 | L->hasMask = 0 ; 279 | L->dim.width = xcfL(ptr); ptr+=4 ; 280 | L->dim.height = xcfL(ptr); ptr+=4 ; 281 | L->type = xcfL(ptr); ptr+=4 ; 282 | L->name = xcfString(ptr,&ptr); 283 | L->propptr = ptr ; 284 | 285 | L->isGroup = 0; 286 | L->pathLength = 0; 287 | L->path = NULL; 288 | 289 | while( (type = xcfNextprop(&ptr,&data)) != PROP_END ) { 290 | switch(type) { 291 | case PROP_OPACITY: 292 | L->opacity = xcfL(data); 293 | if( L->opacity > 255 ) 294 | L->opacity = 255 ; 295 | break ; 296 | case PROP_VISIBLE: 297 | L->isVisible = xcfL(data) != 0 ; 298 | break ; 299 | case PROP_APPLY_MASK: 300 | L->hasMask = xcfL(data) != 0 ; 301 | break ; 302 | case PROP_OFFSETS: 303 | L->dim.c.l = (int32_t)(xcfL(data )) ; 304 | L->dim.c.t = (int32_t)(xcfL(data+4)) ; 305 | break ; 306 | case PROP_MODE: 307 | L->mode = xcfL(data); 308 | break ; 309 | case PROP_GROUP_ITEM: 310 | L->isGroup = 1 ; 311 | break; 312 | case PROP_ITEM_PATH: 313 | L->pathLength = (ptr - data - 2) / 4 ; 314 | 315 | if ( L->pathLength != 0 ) { 316 | 317 | L->path = xcfmalloc( L->pathLength * sizeof(unsigned) ) ; 318 | 319 | for ( j = 0; j!=L->pathLength; j++ ) 320 | *(L->path + j) = (unsigned)xcfL(data + 4 * j); 321 | } 322 | break; 323 | default: 324 | /* Ignore unknown properties */ 325 | break ; 326 | } 327 | } 328 | xcfCheckspace(ptr,8,"(end of layer %s)",L->name); 329 | L->pixels.tileptrs = 0 ; 330 | L->pixels.hierarchy = xcfOffset(ptr ,4*3+xcfPsz*2); 331 | L->mask.tileptrs = 0 ; 332 | L->mask.hierarchy = xcfOffset(ptr+xcfPsz,4*3+xcfPsz*2); 333 | 334 | computeDimensions(&L->dim); 335 | } 336 | } 337 | 338 | -------------------------------------------------------------------------------- /xcf2png.10: -------------------------------------------------------------------------------- 1 | .\" Manual page for xcf2png 2 | .\" This file was written by Henning Makholm 3 | .\" It is hereby in the public domain. 4 | .\" 5 | .\" In jurisdictions that do not recognise grants of copyright to the 6 | .\" public domain: I, the author and (presumably, in those jurisdictions) 7 | .\" copyright holder, hereby permit anyone to distribute and use this code, 8 | .\" in source code or binary form, with or without modifications. This 9 | .\" permission is world-wide and irrevocable. 10 | .\" 11 | .\" Of course, I will not be liable for any errors or shortcomings in the 12 | .\" code, since I give it away without asking any compenstations. 13 | .\" 14 | .\" If you use or distribute this code, I would appreciate receiving 15 | .\" credit for writing it, in whichever way you find proper and customary. 16 | .TH xcf2png 1 2006-02-12 "Xcftools" "" 17 | .SH NAME 18 | xcf2png \- convert from GIMP xcf files to png format 19 | .ds p xcf2png 20 | .SH SYNOPSIS 21 | .B \*p 22 | [ 23 | .I options 24 | ] 25 | .I filename 26 | [ 27 | .I layer names 28 | ] 29 | .SH DESCRIPTION 30 | .B xcf2png 31 | is a command-line tool that converts image files in the XCF format used by 32 | .BR gimp (1) 33 | to the generic image format 34 | .BR png , 35 | flattening layers if necessary. It does not need to have 36 | the Gimp engine itself available. 37 | .SH GENERAL OPTIONS 38 | .so xcf2png.1i 39 | .P 40 | Several groups of options are mutually incompatible; in each group the 41 | one given last will win: 42 | .TP 4 43 | 1) 44 | .B \-A 45 | and 46 | .BR \-b . 47 | .TP 48 | 2) 49 | .B \-g 50 | and 51 | .B \-c . 52 | .TP 53 | 3) 54 | .B \-D 55 | and 56 | .BR \-G . 57 | .TP 58 | 4) 59 | .BR \-j , 60 | .BR \-z , 61 | and 62 | .BR \-Z . 63 | .TP 64 | 5) 65 | .B \-C 66 | and 67 | .BR \-O / \-S . 68 | .SH LAYER SPECIFICATIONS 69 | If no 70 | .I layer name 71 | is given on the command line, all of the visible layers in 72 | the XCF file are merged to produce the output image. 73 | It is also possible to specify the layers to merge explicitly, 74 | by giving their names as separate arguments after the 75 | input filename. In that case, the output will contain 76 | .I only 77 | the named layers. The layers will be merged in the order 78 | they appear on the command line, with the leftmost being 79 | "at the bottom" \- that is, the layer ordering in the XCF file 80 | will be ignored. 81 | .P 82 | The following options can be given 83 | .I after 84 | a layer name to override the global properties of the layer: 85 | .so xcf2png.1il 86 | .so exit.1i 87 | .SH BUGS AND LIMITATIONS 88 | .P 89 | When several partially transparent layers are merged, the pixel 90 | values are interpolated without gamma correction. (The Gimp also 91 | does it this way). Some slight rounding errors in the interpolation 92 | are inevitable; 93 | .B \*p 94 | sometimes has different rounding errors than the Gimp itself, 95 | especially when more than two layers are involved, or in case of 96 | some of the more exotic layer modes. 97 | These differences are usually not visible to the eye. 98 | .P 99 | Floating selections are currently not handled correctly. 100 | .P 101 | There are probably other bugs lurking in corner cases. If you discover 102 | one, please notify the author. 103 | 104 | .SH FILES 105 | .TP 8 106 | .B /etc/X11/rgb.txt 107 | .TP 8 108 | .B /usr/share/X11/rgb.txt 109 | .TP 8 110 | .B /usr/lib/X11/rgb.txt 111 | Color name database for 112 | .BR \-b . 113 | .SH AUTHOR 114 | .B \*p 115 | was written by Henning Makholm . 116 | .P 117 | .SH SEE ALSO 118 | .BR xcfinfo (1), 119 | .BR xcf2pnm (1) 120 | -------------------------------------------------------------------------------- /xcf2png.c: -------------------------------------------------------------------------------- 1 | /* Convert xcf files to png 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "xcftools.h" 20 | #include "flatten.h" 21 | #include "palette.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #if HAVE_GETOPT_H 28 | #include 29 | #else 30 | #include 31 | #endif 32 | #ifndef HAVE_GETOPT_LONG 33 | #define getopt_long(argc,argv,optstring,l1,l2) getopt(argc,argv,optstring) 34 | #endif 35 | 36 | #include "xcf2png.oi" 37 | 38 | static void 39 | usage(FILE *where) 40 | { 41 | fprintf(where,_("Usage: %s [options] filename.xcf[.gz] [layers]\n"), 42 | progname) ; 43 | fprintf(where,_("Options:\n")); 44 | opt_usage(where); 45 | if( where == stderr ) { 46 | exit(1); 47 | } 48 | } 49 | 50 | static struct FlattenSpec flatspec ; 51 | 52 | static FILE *outfile = NULL ; 53 | static png_structp libpng = NULL ; 54 | static png_infop libpng2 = NULL ; 55 | 56 | static void 57 | my_error_callback(png_structp png_ptr, png_const_charp errormsg) 58 | { 59 | FatalUnexpected(_("Libpng error '%s'"),errormsg); 60 | } 61 | 62 | #ifndef png_voidp_NULL 63 | #define png_voidp_NULL NULL 64 | #endif 65 | 66 | #ifndef png_error_ptr_NULL 67 | #define png_error_ptr_NULL NULL 68 | #endif 69 | 70 | static void 71 | init_output(void) 72 | { 73 | int bit_depth ; 74 | int color_type ; 75 | int invert_mono = 0 ; 76 | png_colorp pngpalette = NULL ; 77 | png_bytep ptrans = NULL ; 78 | 79 | outfile = openout(flatspec.output_filename); 80 | libpng = png_create_write_struct(PNG_LIBPNG_VER_STRING, 81 | png_voidp_NULL, 82 | my_error_callback, 83 | png_error_ptr_NULL); 84 | if( !libpng ) 85 | FatalUnexpected(_("Couldn't initialize libpng library")); 86 | 87 | libpng2 = png_create_info_struct(libpng); 88 | if( !libpng2 ) 89 | FatalUnexpected("Couldn't create PNG info structure"); 90 | 91 | png_init_io(libpng,outfile); 92 | 93 | bit_depth = 8; 94 | switch( flatspec.out_color_mode ) { 95 | case COLOR_GRAY: 96 | if( flatspec.default_pixel == PERHAPS_ALPHA_CHANNEL || 97 | flatspec.default_pixel == FORCE_ALPHA_CHANNEL ) 98 | color_type = PNG_COLOR_TYPE_GRAY_ALPHA ; 99 | else 100 | color_type = PNG_COLOR_TYPE_GRAY ; 101 | break ; 102 | case COLOR_RGB: 103 | if( flatspec.default_pixel == PERHAPS_ALPHA_CHANNEL || 104 | flatspec.default_pixel == FORCE_ALPHA_CHANNEL ) 105 | color_type = PNG_COLOR_TYPE_RGB_ALPHA ; 106 | else 107 | color_type = PNG_COLOR_TYPE_RGB ; 108 | break ; 109 | case COLOR_INDEXED: 110 | if( paletteSize == 2 && 111 | palette[0] == NEWALPHA(0,255) && 112 | palette[1] == NEWALPHA(-1,255) ) { 113 | color_type = PNG_COLOR_TYPE_GRAY ; 114 | bit_depth = 1 ; 115 | } else if( paletteSize == 2 && 116 | palette[0] == NEWALPHA(-1,255) && 117 | palette[1] == NEWALPHA(0,255) ) { 118 | color_type = PNG_COLOR_TYPE_GRAY ; 119 | bit_depth = 1 ; 120 | invert_mono = 1 ; 121 | } else { 122 | unsigned i ; 123 | int need_trans = flatspec.default_pixel == FORCE_ALPHA_CHANNEL ; 124 | color_type = PNG_COLOR_TYPE_PALETTE ; 125 | pngpalette = xcfmalloc(paletteSize*sizeof(png_color)) ; 126 | ptrans = xcfmalloc(paletteSize); 127 | for(i = 0; i> RED_SHIFT); 129 | pngpalette[i].green = 255 & (palette[i] >> GREEN_SHIFT); 130 | pngpalette[i].blue = 255 & (palette[i] >> BLUE_SHIFT); 131 | if( (ptrans[i] = ALPHA(palette[i])) != 255 ) 132 | need_trans = 1 ; 133 | } 134 | if( !need_trans ) { 135 | xcffree(ptrans); 136 | ptrans = NULL ; 137 | } 138 | if( paletteSize <= 2 ) 139 | bit_depth = 1 ; 140 | else if( paletteSize <= 4 ) 141 | bit_depth = 2 ; 142 | else if( paletteSize <= 16 ) 143 | bit_depth = 4 ; 144 | else 145 | bit_depth = 8; 146 | } 147 | break ; 148 | default: 149 | FatalUnexpected("This can't happen (unknown out_color_mode)"); 150 | } 151 | 152 | if( verboseFlag ) { 153 | fprintf(stderr,"Writing PNG: %s%s%s%s, %d bits", 154 | color_type & PNG_COLOR_MASK_COLOR ? _("color") : _("grayscale"), 155 | color_type & PNG_COLOR_MASK_PALETTE ? _("+palette") : "", 156 | color_type & PNG_COLOR_MASK_ALPHA ? _("+alpha") : "", 157 | ptrans || NULLALPHA(flatspec.default_pixel) 158 | ? _("+transparency") : "", 159 | bit_depth); 160 | if( pngpalette ) 161 | fprintf(stderr,_(" (%d colors)"),paletteSize); 162 | fprintf(stderr,"\n"); 163 | } 164 | 165 | png_set_IHDR(libpng,libpng2,flatspec.dim.width,flatspec.dim.height, 166 | bit_depth, color_type, 167 | PNG_INTERLACE_NONE, 168 | PNG_COMPRESSION_TYPE_DEFAULT, 169 | PNG_FILTER_TYPE_DEFAULT); 170 | 171 | if( invert_mono ) 172 | png_set_invert_mono(libpng); 173 | 174 | if( pngpalette ) 175 | png_set_PLTE(libpng,libpng2,pngpalette,paletteSize); 176 | if( ptrans ) 177 | png_set_tRNS(libpng,libpng2,ptrans,paletteSize,NULL); 178 | else if ( !pngpalette && 179 | NULLALPHA(flatspec.default_pixel) ) { 180 | static png_color_16 trans ; 181 | trans.gray = 182 | trans.red = 255 & (flatspec.default_pixel >> RED_SHIFT) ; 183 | trans.green = 255 & (flatspec.default_pixel >> GREEN_SHIFT) ; 184 | trans.blue = 255 & (flatspec.default_pixel >> BLUE_SHIFT) ; 185 | png_set_tRNS(libpng,libpng2,NULL,0,&trans); 186 | } 187 | 188 | /* png_set_text here */ 189 | 190 | png_write_info(libpng,libpng2); 191 | 192 | if( bit_depth < 8 ) 193 | png_set_packing(libpng); 194 | 195 | switch( color_type ) { 196 | case PNG_COLOR_TYPE_RGB: 197 | case PNG_COLOR_TYPE_RGBA: 198 | #if (BLUE_SHIFT < RED_SHIFT) == !defined(WORDS_BIGENDIAN) 199 | png_set_bgr(libpng); 200 | #endif 201 | if( color_type == PNG_COLOR_TYPE_RGB ) 202 | #if (ALPHA_SHIFT < RED_SHIFT) == !defined(WORDS_BIGENDIAN) 203 | png_set_filler(libpng,0,PNG_FILLER_BEFORE); 204 | else 205 | png_set_swap_alpha(libpng); 206 | #else 207 | png_set_filler(libpng,0,PNG_FILLER_AFTER); 208 | #endif 209 | break ; 210 | case PNG_COLOR_TYPE_GRAY: 211 | { 212 | // only supported with more than 8 bits, otherwise emit error: png_set_filler is invalid for low bit depth gray output' 213 | if (bit_depth >= 8) png_set_filler(libpng,0,PNG_FILLER_AFTER); 214 | break ; 215 | } 216 | case PNG_COLOR_TYPE_GRAY_ALPHA: 217 | case PNG_COLOR_TYPE_PALETTE: 218 | break ; 219 | default: 220 | FatalUnexpected("This can't happen (unexpected png color_type)"); 221 | } 222 | } 223 | 224 | 225 | static void 226 | raw_callback(unsigned num, rgba *pixels) { 227 | if( libpng == NULL ) { 228 | init_output() ; 229 | } 230 | png_write_row(libpng,(png_bytep)pixels); 231 | xcffree(pixels); 232 | } 233 | 234 | static void 235 | graying_callback(unsigned num, rgba *pixels) { 236 | png_bytep fillptr = (uint8_t *)pixels ; 237 | unsigned i ; 238 | for( i = 0 ; i < num ; i++ ) { 239 | rgba pixel = pixels[i] ; 240 | int g = degrayPixel(pixel) ; 241 | if( g == -1 ) 242 | FatalGeneric(103, 243 | _("Grayscale output selected, but colored pixel(s) found")); 244 | *fillptr++ = g ; 245 | *fillptr++ = ALPHA(pixel) ; 246 | } 247 | raw_callback(num,pixels); 248 | } 249 | 250 | static void 251 | optimistic_palette_callback(unsigned num,rgba *pixels) { 252 | unsigned prev_size = paletteSize ; 253 | if( !palettify_row(pixels,num) || paletteSize != prev_size ) 254 | FatalUnexpected("Oops! Somehow the precomputed palette does not suffice " 255 | "after all..."); 256 | raw_callback(num,pixels); 257 | } 258 | 259 | static enum out_color_mode 260 | guessIndexed(struct FlattenSpec *spec,rgba *allPixels[]) 261 | { 262 | if( allPixels == NULL ) { 263 | if (spec->gimpish_indexed && colormapLength ) { 264 | unsigned i ; 265 | init_palette_hash(); 266 | for( i=0; idefault_pixel) ? 269 | spec->default_pixel : 0 ) >= 0 ) 270 | return COLOR_INDEXED ; 271 | } 272 | } else { 273 | init_palette_hash() ; 274 | if( palettify_rows(allPixels,spec->dim.width,spec->dim.height) ) { 275 | /* Might grayscale sometimes be preferred? No, that is what 276 | * -g is for! */ 277 | return COLOR_INDEXED ; 278 | } 279 | } 280 | return COLOR_BY_CONTENTS ; 281 | } 282 | 283 | static lineCallback 284 | selectCallback(void) 285 | { 286 | switch( flatspec.out_color_mode ) { 287 | default: 288 | case COLOR_RGB: return &raw_callback ; 289 | case COLOR_GRAY: return &graying_callback ; 290 | case COLOR_INDEXED: 291 | if( flatspec.process_in_memory ) 292 | return &raw_callback ; 293 | else 294 | return &optimistic_palette_callback ; 295 | } 296 | } 297 | 298 | /* findUnusedColor() will prefer to find a gray pixel */ 299 | static rgba 300 | findUnusedColor(rgba *pixels[],unsigned width,unsigned height) 301 | { 302 | size_t freqtab[256] ; 303 | unsigned x,y ; 304 | unsigned i,j ; 305 | rgba sofar ; 306 | 307 | for( i=0; i<256; i++ ) 308 | freqtab[i] = 0 ; 309 | for( y=0; y> RED_SHIFT)] ++ ; 313 | j = 0 ; 314 | for( i=0; i<256; i++ ) { 315 | if( freqtab[i] == 0 ) { 316 | return ((rgba)i << RED_SHIFT) + 317 | ((rgba)i << GREEN_SHIFT) + 318 | ((rgba)i << BLUE_SHIFT) + 319 | ((rgba)255 << ALPHA_SHIFT) ; 320 | } 321 | if( freqtab[i] < freqtab[j] ) { 322 | j = i ; 323 | } 324 | } 325 | sofar = ((rgba)255<> GREEN_SHIFT)] ++ ; 334 | j = 0 ; 335 | for( i=0; i<256; i++ ) { 336 | if( freqtab[i] == 0 ) { 337 | return sofar + ((rgba)i << GREEN_SHIFT); 338 | } 339 | if( freqtab[i] < freqtab[j] ) { 340 | j = i ; 341 | } 342 | } 343 | sofar += (rgba)j << GREEN_SHIFT ; 344 | 345 | for( i=0; i<256; i++ ) 346 | freqtab[i] = 0 ; 347 | for( y=0; y> BLUE_SHIFT)] ++ ; 354 | for( i=0; i<256; i++ ) { 355 | if( freqtab[i] == 0 ) { 356 | return sofar + ((rgba)i << BLUE_SHIFT); 357 | } 358 | } 359 | 360 | return 0 ; 361 | } 362 | 363 | int 364 | main(int argc,char **argv) 365 | { 366 | int option ; 367 | const char *unzipper = NULL ; 368 | const char *infile = NULL ; 369 | 370 | setlocale(LC_ALL,""); 371 | progname = argv[0] ; 372 | nls_init(); 373 | 374 | if( argc <= 1 ) gpl_blurb() ; 375 | 376 | init_flatspec(&flatspec) ; 377 | while( (option=getopt_long(argc,argv,"-"OPTSTRING,longopts,NULL)) >= 0 ) 378 | switch(option) { 379 | #define OPTION(char,long,desc,man) case char: 380 | #include "options.i" 381 | case 1: 382 | if( infile ) 383 | add_layer_request(&flatspec,optarg); 384 | else 385 | infile = optarg ; 386 | break ; 387 | case '?': 388 | usage(stderr); 389 | default: 390 | FatalUnexpected("Getopt(_long) unexpectedly returned '%c'",option); 391 | } 392 | if( infile == NULL ) { 393 | usage(stderr); 394 | } 395 | 396 | read_or_mmap_xcf(infile,unzipper); 397 | getBasicXcfInfo() ; 398 | initColormap(); 399 | 400 | complete_flatspec(&flatspec,guessIndexed); 401 | if( flatspec.process_in_memory ) { 402 | rgba **allPixels = flattenAll(&flatspec); 403 | 404 | analyse_colormode(&flatspec,allPixels,guessIndexed); 405 | 406 | /* See if we can do alpha compaction. 407 | */ 408 | if( flatspec.partial_transparency_mode != ALLOW_PARTIAL_TRANSPARENCY && 409 | !FULLALPHA(flatspec.default_pixel) && 410 | flatspec.out_color_mode != COLOR_INDEXED ) { 411 | rgba unused = findUnusedColor(allPixels, 412 | flatspec.dim.width, 413 | flatspec.dim.height); 414 | if( unused && (flatspec.out_color_mode == COLOR_RGB || 415 | degrayPixel(unused) >= 0) ) { 416 | unsigned x,y ; 417 | unused = NEWALPHA(unused,0) ; 418 | for( y=0; y 3 | .\" It is hereby in the public domain. 4 | .\" 5 | .\" In jurisdictions that do not recognise grants of copyright to the 6 | .\" public domain: I, the author and (presumably, in those jurisdictions) 7 | .\" copyright holder, hereby permit anyone to distribute and use this code, 8 | .\" in source code or binary form, with or without modifications. This 9 | .\" permission is world-wide and irrevocable. 10 | .\" 11 | .\" Of course, I will not be liable for any errors or shortcomings in the 12 | .\" code, since I give it away without asking any compenstations. 13 | .\" 14 | .\" If you use or distribute this code, I would appreciate receiving 15 | .\" credit for writing it, in whichever way you find proper and customary. 16 | .TH xcf2pnm 1 2006-02-12 "Xcftools" "" 17 | .SH NAME 18 | xcf2pnm \- convert from GIMP xcf files to ppm/pgm/pbm format 19 | .ds p xcf2pnm 20 | .SH SYNOPSIS 21 | .B \*p 22 | [ 23 | .I options 24 | ] 25 | .I filename 26 | [ 27 | .I layer names 28 | ] 29 | .SH DESCRIPTION 30 | .B xcf2pnm 31 | is a command-line tool that converts image files in the XCF format used by 32 | .BR gimp (1) 33 | to the generic image formats 34 | .BR pbm (5), 35 | .BR pgm (5), 36 | and 37 | .BR ppm (5), 38 | flattening layers if necessary. It does not need to have 39 | the Gimp engine itself available. 40 | .SH GENERAL OPTIONS 41 | .so xcf2pnm.1i 42 | .P 43 | Several groups of options are mutually incompatible; in each group the 44 | one given last will win: 45 | .TP 4 46 | 1) 47 | .B \-A 48 | and 49 | .BR \-b . 50 | .TP 51 | 2) 52 | .BR \-c , 53 | .BR \-g , 54 | .BR \-m , 55 | and 56 | .BR \-n . 57 | .TP 58 | 3) 59 | .B \-D 60 | and 61 | .BR \-G . 62 | .TP 63 | 4) 64 | .BR \-j , 65 | .BR \-z , 66 | and 67 | .BR \-Z . 68 | .TP 69 | 5) 70 | .B \-C 71 | and 72 | .BR \-O / \-S . 73 | .SH LAYER SPECIFICATIONS 74 | If no 75 | .I layer name 76 | is given on the command line, all of the visible layers in 77 | the XCF file are merged to produce the output image. 78 | It is also possible to specify the layers to merge explicitly, 79 | by giving their names as separate arguments after the 80 | input filename. In that case, the output will contain 81 | .I only 82 | the named layers. The layers will be merged in the order 83 | they appear on the command line, with the leftmost being 84 | "at the bottom" \- that is, the layer ordering in the XCF file 85 | will be ignored. 86 | .P 87 | The following options can be given 88 | .I after 89 | a layer name to override the global properties of the layer: 90 | .so xcf2pnm.1il 91 | .so exit.1i 92 | .SH EXAMPLES 93 | .IP 94 | .B xcf2pnm -b white foo.xcf > foo.ppm 95 | .IP 96 | .B xcf2pnm -a footrans.pgm -o foo.ppm foo.xcf Layer1 Layer2 97 | .P 98 | To test whether the flattened image has any transparency, use 99 | .IP 100 | .B xcf2pnm foo.xcf > /dev/null 101 | .P 102 | To test whether the flattened image has 103 | .I partially 104 | transparent pixels, use 105 | .IP 106 | .B xcf2pnm -b white -G > /dev/null 107 | .SH BUGS AND LIMITATIONS 108 | .P 109 | When several partially transparent layers are merged, the pixel 110 | values are interpolated without gamma correction. (The Gimp also 111 | does it this way). Some slight rounding errors in the interpolation 112 | are inevitable; 113 | .B \*p 114 | sometimes has different rounding errors than the Gimp itself, 115 | especially when more than two layers are involved, or in case of 116 | some of the more exotic layer modes. 117 | These differences are usually not visible to the eye. 118 | .P 119 | Floating selections are currently not handled correctly. 120 | .P 121 | There are probably other bugs lurking in corner cases. If you discover 122 | one, please notify the author. 123 | 124 | .SH FILES 125 | .TP 8 126 | .B /etc/X11/rgb.txt 127 | .TP 8 128 | .B /usr/share/X11/rgb.txt 129 | .TP 8 130 | .B /usr/lib/X11/rgb.txt 131 | Color name database for 132 | .BR \-b . 133 | .SH AUTHOR 134 | .B \*p 135 | was written by Henning Makholm . 136 | .P 137 | .SH SEE ALSO 138 | .BR xcfinfo (1), 139 | .BR xcf2png (1) 140 | -------------------------------------------------------------------------------- /xcf2pnm.c: -------------------------------------------------------------------------------- 1 | /* Convert xcf files to ppm 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "xcftools.h" 20 | #include "flatten.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #if HAVE_GETOPT_H 26 | #include 27 | #else 28 | #include 29 | #endif 30 | #ifndef HAVE_GETOPT_LONG 31 | #define getopt_long(argc,argv,optstring,l1,l2) getopt(argc,argv,optstring) 32 | #endif 33 | 34 | #include "xcf2pnm.oi" 35 | 36 | static void 37 | usage(FILE *where) 38 | { 39 | fprintf(where,_("Usage: %s [options] filename.xcf[.gz] [layers]\n"), 40 | progname) ; 41 | fprintf(where,_("Options:\n")); 42 | opt_usage(where); 43 | if( where == stderr ) { 44 | exit(1); 45 | } 46 | } 47 | 48 | static int suppress_byline ; 49 | static struct FlattenSpec flatspec ; 50 | static FILE *outfile = NULL ; 51 | static FILE *transfile = NULL ; 52 | 53 | static void 54 | start_writing(FILE **f,int version) 55 | { 56 | const char *format[] = {"(format zero)", 57 | "PBM-ascii", 58 | "PGM-ascii", 59 | "PPM-ascii", 60 | "PBM", 61 | "PGM", 62 | "PPM" }; 63 | 64 | if( verboseFlag ) 65 | fprintf(stderr,f == &outfile ? _("Writing converted image as %s\n") 66 | : _("Writing transparency map as %s\n"), 67 | format[version]); 68 | 69 | *f = openout( f == &outfile ? flatspec.output_filename 70 | : flatspec.transmap_filename ); 71 | fprintf(*f,"P%d",version); 72 | if( suppress_byline ) 73 | ; 74 | else if( f == &outfile ) 75 | fprintf(*f,_(" # Converted by xcf2pnm %s"),PACKAGE_VERSION); 76 | else 77 | fprintf(*f,_(" # Transparency map by xcf2pnm %s"),PACKAGE_VERSION); 78 | fprintf(*f,"\n%d %d\n%s", 79 | flatspec.dim.width, 80 | flatspec.dim.height, 81 | version == 4 ? "" : "255\n"); 82 | } 83 | 84 | int 85 | put_pbm_row(FILE *file,unsigned num,rgba *pixels,rgba mask) { 86 | unsigned out ; 87 | unsigned i ; 88 | int bitsleft = 8 ; 89 | out = 0 ; 90 | for( i=0; i> RED_SHIFT) & 0xFF , outfile ); 143 | putc( (pixels[i] >> GREEN_SHIFT) & 0xFF , outfile ); 144 | putc( (pixels[i] >> BLUE_SHIFT) & 0xFF , outfile ); 145 | } 146 | callback_common(num,pixels); 147 | } 148 | 149 | static void 150 | pgm_callback(unsigned num,rgba *pixels) 151 | { 152 | unsigned i ; 153 | if( outfile == NULL ) start_writing(&outfile,5); 154 | for( i=0; i < num; i++ ) { 155 | int gray = degrayPixel(pixels[i]) ; 156 | if( gray == -1 ) 157 | FatalGeneric(103, 158 | _("Grayscale output selected, but colored pixel(s) found")); 159 | putc( gray, outfile ); 160 | } 161 | callback_common(num,pixels); 162 | } 163 | 164 | static void 165 | pbm_callback(unsigned num,rgba *pixels) 166 | { 167 | if( outfile == NULL ) start_writing(&outfile,4); 168 | if( !put_pbm_row(outfile,num,pixels, 169 | ((rgba)255 << RED_SHIFT) + 170 | ((rgba)255 << GREEN_SHIFT) + 171 | ((rgba)255 << BLUE_SHIFT)) ) 172 | FatalGeneric(103,_("Monochrome output selected, but not all pixels " 173 | "are black or white")); 174 | callback_common(num,pixels); 175 | } 176 | 177 | static enum out_color_mode 178 | guess_color_mode(const char *string) 179 | { 180 | if( strlen(string) >= 3 ) { 181 | string += strlen(string)-3 ; 182 | if( strcmp(string,"ppm")==0 ) return COLOR_RGB ; 183 | if( strcmp(string,"pgm")==0 ) return COLOR_GRAY ; 184 | if( strcmp(string,"pbm")==0 ) return COLOR_MONO ; 185 | } 186 | return COLOR_BY_FILENAME ; 187 | } 188 | 189 | static lineCallback 190 | selectCallback(void) 191 | { 192 | if( flatspec.transmap_filename && ALPHA(flatspec.default_pixel) >= 128 ) 193 | FatalGeneric(101,_("The -a option was given, " 194 | "but the image has no transparency")); 195 | 196 | switch( flatspec.out_color_mode ) { 197 | default: 198 | case COLOR_RGB: return &ppm_callback ; 199 | case COLOR_GRAY: return &pgm_callback ; 200 | case COLOR_MONO: return &pbm_callback ; 201 | } 202 | } 203 | 204 | int 205 | main(int argc,char **argv) 206 | { 207 | int option ; 208 | const char *unzipper = NULL ; 209 | const char *infile = NULL ; 210 | 211 | setlocale(LC_ALL,""); 212 | progname = argv[0] ; 213 | nls_init(); 214 | 215 | if( argc <= 1 ) gpl_blurb() ; 216 | 217 | init_flatspec(&flatspec) ; 218 | flatspec.out_color_mode = COLOR_BY_FILENAME ; 219 | while( (option=getopt_long(argc,argv,"-@#"OPTSTRING,longopts,NULL)) >= 0 ) 220 | switch(option) { 221 | #define OPTION(char,long,desc,man) case char: 222 | #include "options.i" 223 | case 1: 224 | if( infile ) 225 | add_layer_request(&flatspec,optarg); 226 | else 227 | infile = optarg ; 228 | break ; 229 | case '?': 230 | usage(stderr); 231 | case '@': 232 | /* Non-documented option for build-time test */ 233 | suppress_byline = 1 ; 234 | break ; 235 | case '#': 236 | /* Non-documented option for xcfview */ 237 | flatspec.default_pixel = CHECKERED_BACKGROUND ; 238 | break ; 239 | default: 240 | FatalUnexpected("Getopt(_long) unexpectedly returned '%c'",option); 241 | } 242 | if( infile == NULL ) { 243 | usage(stderr); 244 | } 245 | 246 | if( flatspec.out_color_mode == COLOR_BY_FILENAME && 247 | strlen(flatspec.output_filename) > 4 && 248 | flatspec.output_filename[strlen(flatspec.output_filename)-4] == '.' ) 249 | flatspec.out_color_mode = guess_color_mode(flatspec.output_filename); 250 | 251 | /* If the output filename was not enough cue, see if we're running 252 | * through a symlink/hardlink that gives the required output format 253 | */ 254 | if( flatspec.out_color_mode == COLOR_BY_FILENAME && 255 | strlen(progname) > 3 ) 256 | flatspec.out_color_mode = guess_color_mode(progname); 257 | 258 | if( flatspec.out_color_mode == COLOR_BY_FILENAME ) 259 | flatspec.out_color_mode = COLOR_BY_CONTENTS ; 260 | 261 | read_or_mmap_xcf(infile,unzipper); 262 | getBasicXcfInfo() ; 263 | initColormap(); 264 | 265 | complete_flatspec(&flatspec,NULL); 266 | if( flatspec.process_in_memory ) { 267 | rgba **allPixels = flattenAll(&flatspec); 268 | analyse_colormode(&flatspec,allPixels,NULL); 269 | shipoutWithCallback(&flatspec,allPixels,selectCallback()); 270 | } else { 271 | flattenIncrementally(&flatspec,selectCallback()); 272 | } 273 | closeout(outfile,flatspec.output_filename) ; 274 | closeout(transfile,flatspec.transmap_filename) ; 275 | return 0 ; 276 | } 277 | -------------------------------------------------------------------------------- /xcfinfo.10: -------------------------------------------------------------------------------- 1 | .\" Manual page for xcfinfo 2 | .\" This file was written by Henning Makholm 3 | .\" It is hereby in the public domain. 4 | .\" 5 | .\" In jurisdictions that do not recognise grants of copyright to the 6 | .\" public domain: I, the author and (presumably, in those jurisdictions) 7 | .\" copyright holder, hereby permit anyone to distribute and use this code, 8 | .\" in source code or binary form, with or without modifications. This 9 | .\" permission is world-wide and irrevocable. 10 | .\" 11 | .\" Of course, I will not be liable for any errors or shortcomings in the 12 | .\" code, since I give it away without asking any compenstations. 13 | .\" 14 | .\" If you use or distribute this code, I would appreciate receiving 15 | .\" credit for writing it, in whichever way you find proper and customary. 16 | .TH xcfinfo 1 2006-02-12 "Xcftools" "" 17 | .SH NAME 18 | xcfinfo \- display information about GIMP xcf files 19 | .ds p xcfinfo 20 | .SH SYNOPSIS 21 | .B \*p 22 | [ 23 | .I options 24 | ] 25 | .I filename 26 | .SH DESCRIPTION 27 | .B xcfinfo 28 | is a command-line tool that displays information about the contents of 29 | image files in the XCF format used by 30 | .BR gimp (1), 31 | particularly about the layers in the image. 32 | .SH OPTIONS 33 | .so xcfinfo.1i 34 | .SH OUTPUT 35 | Information about the image is displayed on standard output in a fixed format. 36 | The first line contains general information about the XCF file: 37 | .TP 3 38 | \- 39 | The file format version 40 | .TP 41 | \- 42 | The canvas size 43 | .TP 44 | \- 45 | The image mode (color, grayscale, or indexed) 46 | .TP 47 | \- 48 | The numer of layers 49 | .TP 50 | \- 51 | The internal compression algorithm 52 | .P 53 | Following this line there is a line for each layer: 54 | .TP 3 55 | 1) 56 | The character 57 | .B + 58 | if the layer is visible and 59 | .B \- 60 | if it is not 61 | .TP 62 | 2) 63 | The size and offset of the layer 64 | .TP 65 | 3) 66 | The pixel format of the layer, including whether the 67 | layer has an alpha channel. 68 | .TP 69 | 4) 70 | The layer mode, as well as the opacity if not 100%, and 71 | .B /mask 72 | if the layer has an active layer mask. 73 | .TP 74 | 5) 75 | The name of the layer. 76 | .so exit.1i 77 | .SH AUTHOR 78 | .B \*p 79 | was written by Henning Makholm . 80 | .P 81 | .SH SEE ALSO 82 | .BR xcf2pnm (1), 83 | .BR xcf2png (1) 84 | -------------------------------------------------------------------------------- /xcfinfo.c: -------------------------------------------------------------------------------- 1 | /* A program that extracts metadata from an XCF file 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #include "xcftools.h" 20 | #include 21 | #include 22 | #include 23 | #if HAVE_GETOPT_H 24 | #include 25 | #else 26 | #include 27 | #endif 28 | #ifndef HAVE_GETOPT_LONG 29 | #define getopt_long(argc,argv,optstring,l1,l2) getopt(argc,argv,optstring) 30 | #endif 31 | 32 | #include "xcfinfo.oi" 33 | 34 | static void 35 | usage(FILE *where) 36 | { 37 | fprintf(where,_("Usage: %s [options] filename.xcf[.gz]\n"),progname) ; 38 | fprintf(where,_("Options:\n")); 39 | opt_usage(where) ; 40 | if( where == stderr ) { 41 | exit(1); 42 | } 43 | } 44 | 45 | static void 46 | printLayerPath 47 | ( unsigned layerIndex, const char* pathSeparator ) 48 | { 49 | int depth = XCF.layers[layerIndex].pathLength ; 50 | int i = layerIndex; 51 | 52 | if ( depth != 0 ) { 53 | do { 54 | i++; 55 | } while ( XCF.layers[i].pathLength != depth - 1 ); 56 | 57 | printLayerPath( i, pathSeparator ) ; 58 | printf( "%s%s", pathSeparator, XCF.layers[i].name ); 59 | } 60 | } 61 | 62 | int 63 | main(int argc,char **argv) 64 | { 65 | int i ; 66 | int option ; 67 | const char *unzipper = NULL ; 68 | const char *infile = NULL ; 69 | const char *pathSeparator = "|"; 70 | 71 | setlocale(LC_ALL,""); 72 | progname = argv[0] ; 73 | nls_init(); 74 | 75 | if( argc <= 1 ) gpl_blurb() ; 76 | 77 | while( (option=getopt_long(argc,argv,"-"OPTSTRING,longopts,NULL)) >= 0 ) 78 | switch(option) { 79 | #define OPTION(char,long,desc,man) case char: 80 | #include "options.i" 81 | case 1: 82 | if( infile ) { 83 | FatalGeneric 84 | (20,_("Only one XCF file per command line, please")); 85 | } else { 86 | infile = optarg ; 87 | break ; 88 | } 89 | case '?': 90 | usage(stderr); 91 | default: 92 | FatalUnexpected("Getopt(_long) unexpectedly returned '%c'",option); 93 | } 94 | if( infile == NULL ) { 95 | usage(stderr); 96 | } 97 | 98 | read_or_mmap_xcf(infile,unzipper); 99 | getBasicXcfInfo() ; 100 | printf(_("Version %d, %dx%d %s, %d layers, compressed %s\n"), 101 | XCF.version,XCF.width,XCF.height, 102 | _(showGimpImageBaseType(XCF.type)), 103 | XCF.numLayers, 104 | _(showXcfCompressionType(XCF.compression))); 105 | for( i = XCF.numLayers ; i-- ; ) { 106 | printf("%c %dx%d%+d%+d %s %s", 107 | XCF.layers[i].isVisible ? '+' : '-', 108 | XCF.layers[i].dim.width, XCF.layers[i].dim.height, 109 | XCF.layers[i].dim.c.l, XCF.layers[i].dim.c.t, 110 | _(showGimpImageType(XCF.layers[i].type)), 111 | _(showGimpLayerModeEffects(XCF.layers[i].mode))); 112 | if( XCF.layers[i].opacity < 255 ) 113 | printf("/%02d%%",XCF.layers[i].opacity * 100 / 255); 114 | if( XCF.layers[i].hasMask ) 115 | printf(_("/mask")); 116 | if( XCF.layers[i].isGroup ) 117 | printf(_("/group")); 118 | 119 | printf( " " ); 120 | 121 | if ( XCF.version > 2 ) { 122 | printLayerPath( i, pathSeparator ); 123 | printf( "%s", pathSeparator ); 124 | } 125 | 126 | printf("%s\n",XCF.layers[i].name); 127 | } 128 | 129 | return 0 ; 130 | } 131 | -------------------------------------------------------------------------------- /xcftools.h: -------------------------------------------------------------------------------- 1 | /* Generic functions and macros for reading XCF files 2 | * 3 | * This file was written by Henning Makholm 4 | * It is hereby in the public domain. 5 | * 6 | * In jurisdictions that do not recognise grants of copyright to the 7 | * public domain: I, the author and (presumably, in those jurisdictions) 8 | * copyright holder, hereby permit anyone to distribute and use this code, 9 | * in source code or binary form, with or without modifications. This 10 | * permission is world-wide and irrevocable. 11 | * 12 | * Of course, I will not be liable for any errors or shortcomings in the 13 | * code, since I give it away without asking any compenstations. 14 | * 15 | * If you use or distribute this code, I would appreciate receiving 16 | * credit for writing it, in whichever way you find proper and customary. 17 | */ 18 | 19 | #ifndef XCFTOOLS_H 20 | #define XCFTOOLS_H 21 | 22 | #include "config.h" 23 | #include "enums.h" 24 | #include 25 | #include 26 | 27 | #if defined(HAVE_GETTEXT) && defined(ENABLE_NLS) 28 | #include 29 | #define _(s) gettext(s) 30 | void nls_init(void); 31 | #else 32 | #define _(s) (s) 33 | #define nls_init() (void)0 34 | #endif 35 | #define N_(s) (s) 36 | 37 | #if HAVE_INTTYPES_H 38 | # define __STDC_FORMAT_MACROS 39 | # include 40 | #else 41 | /* These legacy fall-backs will probably work on every system 42 | * that does not supply a inttypes.h ... */ 43 | typedef unsigned char uint8_t ; 44 | typedef unsigned long int uint32_t, uintptr_t ; 45 | typedef signed char int8_t ; 46 | typedef signed long int int32_t ; 47 | # define PRIX32 "lX" 48 | # define PRIu32 "lu" 49 | # define PRIXPTR "lX" 50 | #endif 51 | 52 | typedef uintptr_t xcfptr_t ; 53 | 54 | #if __GNUC__ 55 | # define __ATTRIBUTE__ __attribute__ 56 | #else 57 | # define __ATTRIBUTE__(x) 58 | #endif 59 | 60 | #if HAVE_NETINET_IN_H 61 | # include 62 | #elif HAVE_ARPA_INET_H 63 | # include 64 | #elif WORDS_BIGENDIAN 65 | # define ntohl(x) (x) 66 | #else 67 | static inline uint32_t ntohl(uint32_t a) { 68 | return (a << 24) + ((a & 0xFF00) << 8) + ((a >> 8) & 0xFF00) + (a >> 24) ; 69 | } 70 | #endif 71 | 72 | #ifndef HAVE_STRCASECMP 73 | #define strcasecmp strcmp 74 | #endif 75 | 76 | /* Read a single word value from the XCF file */ 77 | 78 | /* Use + instead of | because that allows LEA instructions */ 79 | #define xcfBE(a) ( ((uint32_t)xcf_file[(a) ] << 24) + \ 80 | ((uint32_t)xcf_file[(a)+1] << 16) + \ 81 | ((uint32_t)xcf_file[(a)+2] << 8 ) + \ 82 | ((uint32_t)xcf_file[(a)+3] ) ) 83 | #define xcfLE(a) ( ((uint32_t)xcf_file[(a) ] ) + \ 84 | ((uint32_t)xcf_file[(a)+1] << 8 ) + \ 85 | ((uint32_t)xcf_file[(a)+2] << 16) + \ 86 | ((uint32_t)xcf_file[(a)+3] << 24) ) 87 | 88 | #if CAN_DO_UNALIGNED_WORDS 89 | # define xcfL(a) ntohl(*(uint32_t *)(xcf_file + (a))) 90 | #else 91 | # define xcfL(a) ((a) & 3 ? xcfBE(a) : ntohl(*(uint32_t *)(xcf_file + (a)))) 92 | #endif 93 | 94 | /* Similarly, for doubleword values */ 95 | 96 | #define xcfLBE(a) ( ((uint64_t)xcf_file[(a) ] << 56) + \ 97 | ((uint64_t)xcf_file[(a)+1] << 48) + \ 98 | ((uint64_t)xcf_file[(a)+2] << 40) + \ 99 | ((uint64_t)xcf_file[(a)+1] << 32) + \ 100 | ((uint64_t)xcf_file[(a)+2] << 24) + \ 101 | ((uint64_t)xcf_file[(a)+1] << 16) + \ 102 | ((uint64_t)xcf_file[(a)+2] << 8 ) + \ 103 | ((uint64_t)xcf_file[(a)+3] ) ) 104 | #define xcfLLE(a) ( ((uint64_t)xcf_file[(a) ] ) + \ 105 | ((uint64_t)xcf_file[(a)+1] << 8 ) + \ 106 | ((uint64_t)xcf_file[(a)+2] << 16) + \ 107 | ((uint64_t)xcf_file[(a)+1] << 24 ) + \ 108 | ((uint64_t)xcf_file[(a)+2] << 32) + \ 109 | ((uint64_t)xcf_file[(a)+1] << 40) + \ 110 | ((uint64_t)xcf_file[(a)+2] << 48) + \ 111 | ((uint64_t)xcf_file[(a)+3] << 56) ) 112 | 113 | #if CAN_DO_UNALIGNED_WORDS 114 | # define xcfLL(a) be64toh(*(uint64_t *)(xcf_file + (a))) 115 | #else 116 | # define xcfLL(a) ((a) & 7 ? xcfLBE(a) : be64toh(*(uint64_t *)(xcf_file + (a)))) 117 | #endif 118 | 119 | /* Simiarly, for pointer values */ 120 | 121 | #define xcfP(a) (XCF.version >= 11 ? xcfLL(a) : xcfL(a)) 122 | #define xcfPsz (XCF.version >= 11 ? 8 : 4) 123 | 124 | /* ****************************************************************** */ 125 | 126 | /* The following are exported from am OS-specific source file; 127 | * io-unix.c on unixish systems. 128 | */ 129 | void read_or_mmap_xcf(const char* filename, const char *unzipper); 130 | void free_or_close_xcf(void); 131 | 132 | /* ****************************************************************** */ 133 | /* utils.c */ 134 | 135 | extern const char *progname ; 136 | extern int verboseFlag ; 137 | 138 | void *xcfmalloc(size_t size); 139 | void xcffree(void*); 140 | 141 | void FatalGeneric(int status,const char* format,...) 142 | __ATTRIBUTE__((format(printf,2,3),noreturn)) ; 143 | void FatalUnexpected(const char* format,...) 144 | __ATTRIBUTE__((format(printf,1,2),noreturn)) ; 145 | void FatalBadXCF(const char* format,...) 146 | __ATTRIBUTE__((format(printf,1,2),noreturn)) ; 147 | void FatalUnsupportedXCF(const char* format,...) 148 | __ATTRIBUTE__((format(printf,1,2),noreturn)) ; 149 | 150 | void gpl_blurb(void) __ATTRIBUTE__((noreturn)); 151 | 152 | FILE* openout(const char*); 153 | void closeout(FILE *,const char*); 154 | 155 | struct rect { 156 | int64_t t, b, l, r ; 157 | }; 158 | 159 | #define isSubrect(A,B) \ 160 | ((A).l >= (B).l && (A).r <= (B).r && (A).t >= (B).t && (A).b <= (B).b) 161 | #define disjointRects(A,B) \ 162 | ((A).l >= (B).r || (A).r <= (B).l || (A).t >= (B).b || (A).b <= (B).t) 163 | 164 | /* ****************************************************************** */ 165 | /* xcf-general.c */ 166 | 167 | extern uint8_t *xcf_file ; 168 | extern size_t xcf_length ; 169 | extern int use_utf8 ; 170 | 171 | void xcfCheckspace(xcfptr_t addr,int spaceafter, const char *format,...) 172 | __ATTRIBUTE__((format(printf,3,4))); 173 | xcfptr_t xcfOffset(xcfptr_t addr,int spaceafter); 174 | 175 | int xcfNextprop(xcfptr_t *master,xcfptr_t *body); 176 | const char* xcfString(xcfptr_t ptr,xcfptr_t *after); 177 | 178 | /* These are hardcoded in the Gimp sources: */ 179 | #define TILE_SHIFT 6 180 | #define TILE_WIDTH (1<> TILE_SHIFT) 190 | 191 | struct tileDimensions { 192 | struct rect c ; 193 | unsigned width, height ; 194 | unsigned tilesx, tilesy ; 195 | unsigned ntiles ; 196 | }; 197 | /* computeDimensions assumes that width, height, c.l, and c.t are set */ 198 | void computeDimensions(struct tileDimensions *); 199 | 200 | struct xcfTiles { 201 | const struct _convertParams *params ; 202 | xcfptr_t *tileptrs ; 203 | xcfptr_t hierarchy ; 204 | }; 205 | 206 | struct xcfLayer { 207 | struct tileDimensions dim ; 208 | const char *name ; 209 | GimpLayerModeEffects mode ; 210 | GimpImageType type ; 211 | unsigned int opacity ; 212 | int isVisible, hasMask ; 213 | xcfptr_t propptr ; 214 | struct xcfTiles pixels ; 215 | struct xcfTiles mask ; 216 | int isGroup ; 217 | unsigned pathLength ; 218 | unsigned *path ; 219 | }; 220 | 221 | extern struct xcfImage { 222 | int version ; 223 | unsigned width, height ; 224 | GimpImageBaseType type ; 225 | GimpPrecision pformat ; 226 | XcfCompressionType compression ; 227 | int numLayers ; 228 | struct xcfLayer *layers ; 229 | xcfptr_t colormapptr ; 230 | } XCF ; 231 | 232 | void getBasicXcfInfo(void); 233 | 234 | #endif /* XCFTOOLS_H */ 235 | -------------------------------------------------------------------------------- /xcftools.spec: -------------------------------------------------------------------------------- 1 | # This script was contributed by Marcus Alanen. 2 | # 3 | # Henning Makholm, the xcftools author, have not had occasion to test 4 | # it, so use at your own peril. In particular, note that there is a 5 | # hard-coded version number just a few lines in. I make no promises 6 | # that I'll remember to update it for versions 1.0.7 - caveat emptor! 7 | 8 | ############################################################################# 9 | # Variables 10 | ############################################################################# 11 | %define name xcftools 12 | %define version 1.0.7 13 | %define release 1 14 | 15 | ############################################################################# 16 | # Preamble. This contains general information about the package. 17 | ############################################################################# 18 | Summary : xcftools 19 | Name : %{name} 20 | Version : %{version} 21 | Release : %{release} 22 | License : Public Domain 23 | Group : Development/Tools 24 | Source : xcftools-%version.tar.gz 25 | Packager : Marcus Alanen 26 | 27 | BuildRoot : %{_tmppath}/%{name}-buildroot 28 | Prefix : /usr 29 | Requires : glibc 30 | 31 | ############################################################################# 32 | # A description of the project 33 | ############################################################################# 34 | %description 35 | xcftools is a set of tools for extracting information from GIMP's xcf 36 | files. 37 | 38 | ############################################################################# 39 | # Preparations for the install. We don't need to do anything special here, 40 | # so we let the %setup-macro take care of creating a directory and unpacking 41 | # the sources. 42 | ############################################################################# 43 | %prep 44 | rm -rf $RPM_BUILD_ROOT 45 | %setup 46 | %patch0 -p1 47 | 48 | ############################################################################# 49 | # Build the project 50 | ############################################################################# 51 | %build 52 | ./configure --prefix=/usr && make DESTDIR=$RPM_BUILD_ROOT 53 | 54 | ############################################################################# 55 | # Install the software 56 | ############################################################################# 57 | %install 58 | mkdir $RPM_BUILD_ROOT/usr || true 59 | mkdir $RPM_BUILD_ROOT/usr/share || true 60 | mkdir $RPM_BUILD_ROOT/usr/share/man || true 61 | mkdir $RPM_BUILD_ROOT/usr/share/man/man1/ || true 62 | 63 | make install DESTDIR=$RPM_BUILD_ROOT 64 | 65 | cd $RPM_BUILD_ROOT 66 | 67 | function getfiles() { 68 | # Change /usr/bin to ./usr/bin 69 | dir=$(echo $1 | sed -e 's|.|\.\/|;') 70 | find $dir -type d -print | sed 's,^\.,\%attr(-\,root\,root) \%dir ,' 71 | 72 | find $dir -type f -print | sed -e 's,^\.,\%attr(-\,root\,root) ,' \ 73 | -e '/\/etc\//s|^|%config|' \ 74 | -e '/\/config\//s|^|%config|' 75 | 76 | find $dir -type l -print | sed 's,^\.,\%attr(-\,root\,root) ,' 77 | } 78 | 79 | all=$RPM_BUILD_DIR/filelist.%{name} 80 | 81 | getfiles %{prefix} | grep -v /man/ > $all 82 | 83 | ############################################################################# 84 | # Files to be included in the package. 85 | ############################################################################# 86 | %files -f ../filelist.%{name} 87 | %defattr(-,root,root,0755) 88 | %{_mandir}/*/* 89 | 90 | ############################################################################# 91 | # Cleaning up stuff. 92 | ############################################################################# 93 | %clean 94 | make clean 95 | rm -rf $RPM_BUILD_ROOT 96 | 97 | -------------------------------------------------------------------------------- /xcfview.10: -------------------------------------------------------------------------------- 1 | .\" Manual page for xcfview 2 | .\" This file was written by Henning Makholm 3 | .\" It is hereby in the public domain. 4 | .\" 5 | .\" In jurisdictions that do not recognise grants of copyright to the 6 | .\" public domain: I, the author and (presumably, in those jurisdictions) 7 | .\" copyright holder, hereby permit anyone to distribute and use this code, 8 | .\" in source code or binary form, with or without modifications. This 9 | .\" permission is world-wide and irrevocable. 10 | .\" 11 | .\" Of course, I will not be liable for any errors or shortcomings in the 12 | .\" code, since I give it away without asking any compenstations. 13 | .\" 14 | .\" If you use or distribute this code, I would appreciate receiving 15 | .\" credit for writing it, in whichever way you find proper and customary. 16 | .TH xcf2pnm 1 2006-02-12 "Xcftools" "" 17 | .SH NAME 18 | xcfview \- display GIMP xcf files 19 | .ds p xcfview 20 | .SH SYNOPSIS 21 | .B \*p 22 | [ 23 | .I options 24 | ] 25 | .I filename 26 | [ 27 | .I layer names 28 | ] 29 | .SH DESCRIPTION 30 | .B xcfview 31 | is a wrapper script that uses 32 | .BR xcf2png (1) 33 | or 34 | .BR xcf2pnm (1) 35 | (q.v.) to flatten an XCF image and then displays the flattened 36 | image using a PNG or PPM viewer found using the 37 | .BR mailcap (5) 38 | database. 39 | .SH OPTIONS 40 | Every command-line parameter to 41 | .B xcfview 42 | will be passed through to the underlying 43 | .B xcf2png 44 | or 45 | .B xcf2pnm 46 | command. Because it is not certain which converter will be used, 47 | the options given should be ones that make sense for both of these: 48 | .so xcfview.1i 49 | .SH EXIT STATUS 50 | The exit status is 0 in case of success. A nonzero exit status may 51 | either be that of the 52 | .BI xcf2 foo 53 | converter or that of the image viewer. 54 | .SH AUTHOR 55 | .B \*p 56 | was written by Henning Makholm . 57 | .P 58 | Parts of the script originate from the 59 | .BR run-mailcap (1) 60 | script by Brian White . 61 | .SH SEE ALSO 62 | .BR xcf2pnm (1), 63 | .BR xcf2png (1) 64 | -------------------------------------------------------------------------------- /xcfview.in: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # 3 | # xcfview: a wrapper script that uses xcftools and an external viewer 4 | # to display XCF images. The external viewer is found through the 5 | # mailcap(5) database (q.v.). 6 | # 7 | # Written by Henning Makholm 8 | # Derived from the run-mailcap script by Brian White 9 | # 10 | # This script has been placed in the public domain (by both authors) 11 | # 12 | # We cannot use run-mailcap as-is because we can supply the flattened 13 | # image either as PNG and PPM, and we need to find the highest-ranked 14 | # viewer that can handle _one_ of these two. If everything else is equal 15 | # we try to prefer a PNG viewer such that transparency is handled properly. 16 | # 17 | 18 | use strict ; 19 | use warnings ; 20 | 21 | my $debug=0; 22 | my $quotedsemi = "\001" ; 23 | my $quotedprct = "\002" ; 24 | 25 | sub ReadMailcap { 26 | my($file) = @_; 27 | my $line = ""; 28 | 29 | return unless -r $file; 30 | 31 | print STDERR " - Reading mailcap file \"$file\"...\n" if $debug; 32 | open(MAILCAP,"<$file") || die "Error: could not read \"$file\" -- $!\n"; 33 | my @mailcap ; 34 | 35 | while () { 36 | chomp; 37 | s/^\s+// if $line; 38 | $line .= $_; 39 | next unless $line; 40 | if ($line =~ m/^\s*\#/) { 41 | $line = ""; 42 | next; 43 | } 44 | if ($line =~ m/\\$/) { 45 | $line =~ s/\\$//; 46 | } else { 47 | $line =~ s/\\;/$quotedsemi/go; 48 | $line =~ s/\\%/$quotedprct/go; 49 | push @mailcap,$line; 50 | $line = ""; 51 | } 52 | } 53 | close MAILCAP; 54 | 55 | return @mailcap ; 56 | } 57 | 58 | sub TempFile { 59 | my($match) = @_; 60 | my($cmd,$head,$tail,$tmpfile); 61 | 62 | ($head,$tail) = split(/%s/,$1,2) 63 | if ($match =~ m/nametemplate=(.*?)\s*($|;)/); 64 | 65 | $cmd = "tempfile --mode=600"; 66 | $cmd .= " --prefix $head" if $head; 67 | $cmd .= " --suffix $tail" if $tail; 68 | 69 | $tmpfile = `$cmd`; 70 | chomp($tmpfile); 71 | 72 | return $tmpfile; 73 | } 74 | 75 | my ($useline,$usecomm,$useprogram,$usetype,@converter) ; 76 | foreach my $mailcap ( $ENV{MAILCAPS} ? split(/:/,$ENV{MAILCAPS}) : 77 | ( "$ENV{HOME}/.mailcap", 78 | qw( /etc/mailcap 79 | /usr/local/etc/mailcap 80 | /usr/share/etc/mailcap 81 | /usr/etc/mailcap 82 | ) ) ) { 83 | foreach ( ReadMailcap($mailcap) ) { 84 | my ($type,$comm,$program,$rest) 85 | = m"^image/(png|x-portable-pixmap)\s*;\s*((\S*).*?)\s*($|;.*)" 86 | or next ; 87 | print STDERR " - checking $mailcap entry \"$_\"\n" if $debug; 88 | next if $rest =~ /;\s*needsterminal\s*($|;)/ ; 89 | next if $rest =~ /;\s*copiousoutput\s*($|;)/ ; 90 | if( $rest =~ m/;\s*test=(.*?)\s*($|;)/ ) { 91 | my $test; 92 | print STDERR " - running test: $1 " if $debug; 93 | $test = system "$1 >/dev/null 2>&1"; 94 | $test >>= 8; 95 | print STDERR " (result=$test=",($test!=0?"false":"true"),")\n" 96 | if $debug; 97 | next if $test ; 98 | } 99 | # If we get down here, we have a possible hit. 100 | if( $type ne 'png' ) { 101 | # Save for later; if there is a PNG definition for the same 102 | # command, we will prefer PNG 103 | ($useline,$usecomm,$useprogram,$usetype,@converter) 104 | = ($rest,$comm,$program,$type,"xcf2pnm","-c","'-#'") 105 | unless @converter ; 106 | next ; 107 | } else { 108 | # use this definition _unless_ we have already seen and saved 109 | # a definition for a _different_ program (which must have been PPM) 110 | ($useline,$usecomm,$useprogram,$usetype,@converter) 111 | = ($rest,$comm,$program,$type,"xcf2png") 112 | unless @converter && $comm eq $useprogram ; 113 | last ; 114 | } 115 | } 116 | last if @converter ; 117 | } 118 | 119 | unless( @converter ) { 120 | print STDERR "$0: No appropriate way to display PPM or PNG images in mailcap\n" ; 121 | exit 1 ; 122 | } 123 | 124 | sub finishcomm() { 125 | $usecomm =~ s!([^%])%t!$1$usetype!g; 126 | $usecomm =~ s!%{(.*?)}!$_="'$ENV{$1}'";s/\`//g;$_!ge; 127 | $usecomm =~ s!\\(.)!$1!g; 128 | $usecomm =~ s!\'\'!\'!g; 129 | $usecomm =~ s!$quotedsemi!;!go; 130 | $usecomm =~ s!$quotedprct!%!go; 131 | } 132 | 133 | # quote arguments for converter 134 | for( @ARGV ) { 135 | next if m{^[-a-z0-9,.:/@%^+=_]+$}i ; 136 | s/'/\\'/ ; 137 | $_ = "'$_'" ; 138 | } 139 | 140 | if( $usecomm =~ /[^%]%s/ ) { 141 | my $tempfile = TempFile($useline); 142 | $usecomm =~ s/([^%])%s/$1$tempfile/g ; 143 | finishcomm() ; 144 | my $retcode = 0 ; 145 | for my $comm ( join(" ",@converter,"-o",$tempfile,@ARGV), 146 | $usecomm ) { 147 | print STDERR " - executing: $comm\n" if $debug ; 148 | my $res = system $comm; 149 | $res = int($res/256); 150 | if ($res != 0) { 151 | print STDERR "Warning: program returned non-zero exit code \#$res\n"; 152 | $retcode = $res; 153 | last ; 154 | } 155 | } 156 | unlink $tempfile ; 157 | exit $retcode ; 158 | } else { 159 | finishcomm() ; 160 | exec( join(@converter," ",@ARGV) . " | " . $usecomm ) 161 | or print STDERR "Couldn't exec pipeline: $!\n" ; 162 | exit 1 ; 163 | } 164 | --------------------------------------------------------------------------------