summaryrefslogtreecommitdiffstats
path: root/kernel/kls_xcf/xcf2pnm
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 17:43:19 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-02-24 17:43:19 +0000
commit0292059f4a16434600564cfa3f0ad2309a508a54 (patch)
treed95953cd53011917c4df679b96aedca39401b54f /kernel/kls_xcf/xcf2pnm
downloadlibksquirrel-0292059f4a16434600564cfa3f0ad2309a508a54.tar.gz
libksquirrel-0292059f4a16434600564cfa3f0ad2309a508a54.zip
Added libksquirrel for KDE3
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/libraries/libksquirrel@1095624 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kernel/kls_xcf/xcf2pnm')
-rw-r--r--kernel/kls_xcf/xcf2pnm/Makefile.am5
-rw-r--r--kernel/kls_xcf/xcf2pnm/enums.c116
-rw-r--r--kernel/kls_xcf/xcf2pnm/enums.h98
-rw-r--r--kernel/kls_xcf/xcf2pnm/flatspec.c370
-rw-r--r--kernel/kls_xcf/xcf2pnm/flatten.c689
-rw-r--r--kernel/kls_xcf/xcf2pnm/flatten.h77
-rw-r--r--kernel/kls_xcf/xcf2pnm/io-unix.c176
-rw-r--r--kernel/kls_xcf/xcf2pnm/options.i410
-rw-r--r--kernel/kls_xcf/xcf2pnm/pixels.c487
-rw-r--r--kernel/kls_xcf/xcf2pnm/pixels.h128
-rw-r--r--kernel/kls_xcf/xcf2pnm/scaletab.c42
-rw-r--r--kernel/kls_xcf/xcf2pnm/table.c263
-rw-r--r--kernel/kls_xcf/xcf2pnm/utils.c164
-rw-r--r--kernel/kls_xcf/xcf2pnm/xcf-general.c287
-rw-r--r--kernel/kls_xcf/xcf2pnm/xcf2pnm.c269
-rw-r--r--kernel/kls_xcf/xcf2pnm/xcf2pnm.oi41
-rw-r--r--kernel/kls_xcf/xcf2pnm/xcftools.h182
17 files changed, 3804 insertions, 0 deletions
diff --git a/kernel/kls_xcf/xcf2pnm/Makefile.am b/kernel/kls_xcf/xcf2pnm/Makefile.am
new file mode 100644
index 0000000..c81ca26
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/Makefile.am
@@ -0,0 +1,5 @@
+bin_PROGRAMS = ksquirrel-libs-xcf2pnm
+
+ksquirrel_libs_xcf2pnm_SOURCES = enums.c flatspec.c flatten.c io-unix.c pixels.c scaletab.c table.c utils.c xcf2pnm.c xcf-general.c
+
+EXTRA_DIST = xcf2pnm.oi \ No newline at end of file
diff --git a/kernel/kls_xcf/xcf2pnm/enums.c b/kernel/kls_xcf/xcf2pnm/enums.c
new file mode 100644
index 0000000..88f68e7
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/enums.c
@@ -0,0 +1,116 @@
+/* Autogenerated from enums.h */
+#include "enums.h"
+#define N_
+#include <stdio.h>
+const char*
+showGimpLayerModeEffects(GimpLayerModeEffects x)
+{
+ static char buf[35];
+ switch(x) {
+ case GIMP_NORMAL_MODE: return N_("Normal");
+ case GIMP_DISSOLVE_MODE: return N_("Dissolve");
+ case GIMP_BEHIND_MODE: return N_("Behind");
+ case GIMP_MULTIPLY_MODE: return N_("Multiply");
+ case GIMP_SCREEN_MODE: return N_("Screen");
+ case GIMP_OVERLAY_MODE: return N_("Overlay");
+ case GIMP_DIFFERENCE_MODE: return N_("Difference");
+ case GIMP_ADDITION_MODE: return N_("Addition");
+ case GIMP_SUBTRACT_MODE: return N_("Subtract");
+ case GIMP_DARKEN_ONLY_MODE: return N_("DarkenOnly");
+ case GIMP_LIGHTEN_ONLY_MODE: return N_("LightenOnly");
+ case GIMP_HUE_MODE: return N_("Hue");
+ case GIMP_SATURATION_MODE: return N_("Saturation");
+ case GIMP_COLOR_MODE: return N_("Color");
+ case GIMP_VALUE_MODE: return N_("Value");
+ case GIMP_DIVIDE_MODE: return N_("Divide");
+ case GIMP_DODGE_MODE: return N_("Dodge");
+ case GIMP_BURN_MODE: return N_("Burn");
+ case GIMP_HARDLIGHT_MODE: return N_("Hardlight");
+ case GIMP_SOFTLIGHT_MODE: return N_("Softlight");
+ case GIMP_GRAIN_EXTRACT_MODE: return N_("GrainExtract");
+ case GIMP_GRAIN_MERGE_MODE: return N_("GrainMerge");
+ case GIMP_COLOR_ERASE_MODE: return N_("ColorErase");
+ case GIMP_ERASE_MODE: return N_("Erase");
+ case GIMP_REPLACE_MODE: return N_("Replace");
+ case GIMP_ANTI_ERASE_MODE: return N_("AntiErase");
+ case GIMP_NORMAL_NOPARTIAL_MODE: return N_("NormalNopartial");
+ default: sprintf(buf,"(GimpLayerModeEffects:%d)",(int)x);
+ return buf;
+ }
+}
+const char*
+showGimpImageBaseType(GimpImageBaseType x)
+{
+ static char buf[32];
+ switch(x) {
+ case GIMP_RGB: return N_("RGB color");
+ case GIMP_GRAY: return N_("Grayscale");
+ case GIMP_INDEXED: return N_("Indexed color");
+ default: sprintf(buf,"(GimpImageBaseType:%d)",(int)x);
+ return buf;
+ }
+}
+const char*
+showGimpImageType(GimpImageType x)
+{
+ static char buf[28];
+ switch(x) {
+ case GIMP_RGB_IMAGE: return N_("RGB");
+ case GIMP_RGBA_IMAGE: return N_("RGB-alpha");
+ case GIMP_GRAY_IMAGE: return N_("Grayscale");
+ case GIMP_GRAYA_IMAGE: return N_("Grayscale-alpha");
+ case GIMP_INDEXED_IMAGE: return N_("Indexed");
+ case GIMP_INDEXEDA_IMAGE: return N_("Indexed-alpha");
+ default: sprintf(buf,"(GimpImageType:%d)",(int)x);
+ return buf;
+ }
+}
+const char*
+showPropType(PropType x)
+{
+ static char buf[23];
+ switch(x) {
+ case PROP_END: return ("End");
+ case PROP_COLORMAP: return ("Colormap");
+ case PROP_ACTIVE_LAYER: return ("ActiveLayer");
+ case PROP_ACTIVE_CHANNEL: return ("ActiveChannel");
+ case PROP_SELECTION: return ("Selection");
+ case PROP_FLOATING_SELECTION: return ("FloatingSelection");
+ case PROP_OPACITY: return ("Opacity");
+ case PROP_MODE: return ("Mode");
+ case PROP_VISIBLE: return ("Visible");
+ case PROP_LINKED: return ("Linked");
+ case PROP_PRESERVE_TRANSPARENCY: return ("PreserveTransparency");
+ case PROP_APPLY_MASK: return ("ApplyMask");
+ case PROP_EDIT_MASK: return ("EditMask");
+ case PROP_SHOW_MASK: return ("ShowMask");
+ case PROP_SHOW_MASKED: return ("ShowMasked");
+ case PROP_OFFSETS: return ("Offsets");
+ case PROP_COLOR: return ("Color");
+ case PROP_COMPRESSION: return ("Compression");
+ case PROP_GUIDES: return ("Guides");
+ case PROP_RESOLUTION: return ("Resolution");
+ case PROP_TATTOO: return ("Tattoo");
+ case PROP_PARASITES: return ("Parasites");
+ case PROP_UNIT: return ("Unit");
+ case PROP_PATHS: return ("Paths");
+ case PROP_USER_UNIT: return ("UserUnit");
+ case PROP_VECTORS: return ("Vectors");
+ case PROP_TEXT_LAYER_FLAGS: return ("TextLayerFlags");
+ default: sprintf(buf,"(PropType:%d)",(int)x);
+ return buf;
+ }
+}
+const char*
+showXcfCompressionType(XcfCompressionType x)
+{
+ static char buf[33];
+ switch(x) {
+ case COMPRESS_NONE: return N_("None");
+ case COMPRESS_RLE: return N_("RLE");
+ case COMPRESS_ZLIB: return N_("Zlib");
+ case COMPRESS_FRACTAL: return N_("Fractal");
+ default: sprintf(buf,"(XcfCompressionType:%d)",(int)x);
+ return buf;
+ }
+}
diff --git a/kernel/kls_xcf/xcf2pnm/enums.h b/kernel/kls_xcf/xcf2pnm/enums.h
new file mode 100644
index 0000000..81746ef
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/enums.h
@@ -0,0 +1,98 @@
+/* Extracted from
+ * gimp/base-enums.h
+ * gimp/gimpbaseenums.h
+ * gimp/xcf-private.h
+ * by mkenumsh.pl
+ */
+typedef enum
+{
+ GIMP_NORMAL_MODE,
+ GIMP_DISSOLVE_MODE,
+ GIMP_BEHIND_MODE,
+ GIMP_MULTIPLY_MODE,
+ GIMP_SCREEN_MODE,
+ GIMP_OVERLAY_MODE,
+ GIMP_DIFFERENCE_MODE,
+ GIMP_ADDITION_MODE,
+ GIMP_SUBTRACT_MODE,
+ GIMP_DARKEN_ONLY_MODE,
+ GIMP_LIGHTEN_ONLY_MODE,
+ GIMP_HUE_MODE,
+ GIMP_SATURATION_MODE,
+ GIMP_COLOR_MODE,
+ GIMP_VALUE_MODE,
+ GIMP_DIVIDE_MODE,
+ GIMP_DODGE_MODE,
+ GIMP_BURN_MODE,
+ GIMP_HARDLIGHT_MODE,
+ GIMP_SOFTLIGHT_MODE,
+ GIMP_GRAIN_EXTRACT_MODE,
+ GIMP_GRAIN_MERGE_MODE,
+ GIMP_COLOR_ERASE_MODE,
+ GIMP_ERASE_MODE, /*< pdb-skip, skip >*/
+ GIMP_REPLACE_MODE, /*< pdb-skip, skip >*/
+ GIMP_ANTI_ERASE_MODE /*< pdb-skip, skip >*/
+ ,GIMP_NORMAL_NOPARTIAL_MODE=-1
+} GimpLayerModeEffects;
+const char *showGimpLayerModeEffects(GimpLayerModeEffects);
+#define GimpLayerModeEffects_LAST GIMP_ANTI_ERASE_MODE
+typedef enum
+{
+ GIMP_RGB, /*< desc="RGB color" >*/
+ GIMP_GRAY, /*< desc="Grayscale" >*/
+ GIMP_INDEXED /*< desc="Indexed color" >*/
+} GimpImageBaseType;
+const char *showGimpImageBaseType(GimpImageBaseType);
+#define GimpImageBaseType_LAST GIMP_INDEXED
+typedef enum
+{
+ GIMP_RGB_IMAGE, /*< desc="RGB" >*/
+ GIMP_RGBA_IMAGE, /*< desc="RGB-alpha" >*/
+ GIMP_GRAY_IMAGE, /*< desc="Grayscale" >*/
+ GIMP_GRAYA_IMAGE, /*< desc="Grayscale-alpha" >*/
+ GIMP_INDEXED_IMAGE, /*< desc="Indexed" >*/
+ GIMP_INDEXEDA_IMAGE /*< desc="Indexed-alpha" >*/
+} GimpImageType;
+const char *showGimpImageType(GimpImageType);
+#define GimpImageType_LAST GIMP_INDEXEDA_IMAGE
+typedef enum
+{
+ PROP_END = 0,
+ PROP_COLORMAP = 1,
+ PROP_ACTIVE_LAYER = 2,
+ PROP_ACTIVE_CHANNEL = 3,
+ PROP_SELECTION = 4,
+ PROP_FLOATING_SELECTION = 5,
+ PROP_OPACITY = 6,
+ PROP_MODE = 7,
+ PROP_VISIBLE = 8,
+ PROP_LINKED = 9,
+ PROP_PRESERVE_TRANSPARENCY = 10,
+ PROP_APPLY_MASK = 11,
+ PROP_EDIT_MASK = 12,
+ PROP_SHOW_MASK = 13,
+ PROP_SHOW_MASKED = 14,
+ PROP_OFFSETS = 15,
+ PROP_COLOR = 16,
+ PROP_COMPRESSION = 17,
+ PROP_GUIDES = 18,
+ PROP_RESOLUTION = 19,
+ PROP_TATTOO = 20,
+ PROP_PARASITES = 21,
+ PROP_UNIT = 22,
+ PROP_PATHS = 23,
+ PROP_USER_UNIT = 24,
+ PROP_VECTORS = 25,
+ PROP_TEXT_LAYER_FLAGS = 26
+} PropType;
+const char *showPropType(PropType);
+#define PropType_LAST PROP_TEXT_LAYER_FLAGS
+typedef enum
+{
+ COMPRESS_NONE = 0,
+ COMPRESS_RLE = 1,
+ COMPRESS_ZLIB = 2, /* unused */
+ COMPRESS_FRACTAL = 3 /* unused */
+} XcfCompressionType;
+const char *showXcfCompressionType(XcfCompressionType);
+#define XcfCompressionType_LAST COMPRESS_FRACTAL
diff --git a/kernel/kls_xcf/xcf2pnm/flatspec.c b/kernel/kls_xcf/xcf2pnm/flatspec.c
new file mode 100644
index 0000000..75827ff
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/flatspec.c
@@ -0,0 +1,370 @@
+/* Flattening selections function for xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xcftools.h"
+#include "flatten.h"
+#include <string.h>
+#include <stdlib.h>
+
+void
+init_flatspec(struct FlattenSpec *spec)
+{
+ spec->window_mode = USE_CANVAS ;
+ spec->default_pixel = PERHAPS_ALPHA_CHANNEL ;
+ spec->numLayers = 0 ;
+ spec->layers = NULL ;
+ spec->transmap_filename = NULL ;
+ spec->output_filename = "-" ;
+ spec->out_color_mode = COLOR_BY_CONTENTS ;
+ spec->partial_transparency_mode = ALLOW_PARTIAL_TRANSPARENCY ;
+ spec->process_in_memory = 0 ;
+ spec->gimpish_indexed = 1 ;
+}
+
+void
+add_layer_request(struct FlattenSpec *spec, const char *layer)
+{
+ spec->layers = realloc(spec->layers,
+ sizeof(struct xcfLayer) * (1+spec->numLayers));
+ if( spec->layers == NULL )
+ FatalUnexpected(_("Out of memory"));
+ spec->layers[spec->numLayers].name = layer ;
+ spec->layers[spec->numLayers].mode = (GimpLayerModeEffects)-1 ;
+ spec->layers[spec->numLayers].opacity = 9999 ;
+ spec->layers[spec->numLayers].hasMask = -1 ;
+ spec->numLayers++ ;
+}
+
+struct xcfLayer *
+lastlayerspec(struct FlattenSpec *spec,const char *option)
+{
+ if( spec->numLayers == 0 )
+ FatalGeneric(20,_("The %s option must follow a layer name on the "
+ "command line"),option);
+ return spec->layers + (spec->numLayers-1) ;
+}
+
+static int
+typeHasTransparency(GimpImageType type)
+{
+ switch( type ) {
+ case GIMP_RGB_IMAGE:
+ case GIMP_GRAY_IMAGE:
+ case GIMP_INDEXED_IMAGE:
+ return 0 ;
+ case GIMP_RGBA_IMAGE:
+ case GIMP_GRAYA_IMAGE:
+ case GIMP_INDEXEDA_IMAGE:
+ return 1 ;
+ }
+ return 1 ;
+}
+
+static enum out_color_mode
+color_by_layers(struct FlattenSpec *spec)
+{
+ int colormap_is_colored = 0 ;
+ enum out_color_mode grayish = COLOR_MONO ;
+ int i ;
+
+ if( spec->default_pixel == CHECKERED_BACKGROUND )
+ grayish = COLOR_GRAY ;
+ else if( degrayPixel(spec->default_pixel) < 0 )
+ return COLOR_RGB ;
+ for( i=0; i<colormapLength; i++ ) {
+ if( colormap[i] == NEWALPHA(0,0) || colormap[i] == NEWALPHA(-1,0) )
+ continue ;
+ if( degrayPixel(colormap[i]) == -1 ) {
+ colormap_is_colored = 1 ;
+ break ;
+ } else {
+ grayish = COLOR_GRAY ;
+ }
+ }
+ for( i=0; i<spec->numLayers; i++ )
+ switch( spec->layers[i].type ) {
+ case GIMP_RGB_IMAGE:
+ case GIMP_RGBA_IMAGE:
+ return COLOR_RGB ;
+ case GIMP_GRAY_IMAGE:
+ case GIMP_GRAYA_IMAGE:
+ grayish = COLOR_GRAY ;
+ break ;
+ case GIMP_INDEXED_IMAGE:
+ case GIMP_INDEXEDA_IMAGE:
+ if( colormap_is_colored ) return COLOR_RGB ;
+ break ;
+ }
+ return grayish ;
+}
+
+void
+complete_flatspec(struct FlattenSpec *spec, guesser guess_callback)
+{
+ unsigned i ;
+ int anyPartial ;
+
+ /* Find the layers to convert.
+ */
+ if( spec->numLayers == 0 ) {
+ spec->layers = XCF.layers ;
+ spec->numLayers = XCF.numLayers ;
+ } else {
+ for( i=0; i<spec->numLayers; i++ ) {
+ GimpLayerModeEffects mode ;
+ int opacity, hasMask ;
+ unsigned j ;
+
+ for( j=0; ; j++ ) {
+ if( j == XCF.numLayers )
+ FatalGeneric(22,_("The image has no layer called '%s'"),
+ spec->layers[i].name);
+ if( strcmp(spec->layers[i].name,XCF.layers[j].name) == 0 )
+ break ;
+ }
+ mode = spec->layers[i].mode == (GimpLayerModeEffects)-1 ?
+ XCF.layers[j].mode : spec->layers[i].mode ;
+ opacity = spec->layers[i].opacity == 9999 ?
+ XCF.layers[j].opacity : spec->layers[i].opacity ;
+ hasMask = spec->layers[i].hasMask == -1 ?
+ XCF.layers[j].hasMask : spec->layers[i].hasMask ;
+ if( hasMask && !XCF.layers[j].hasMask &&
+ XCF.layers[j].mask.hierarchy == 0 )
+ FatalGeneric(22,_("Layer '%s' has no layer mask to enable"),
+ spec->layers[i].name);
+ spec->layers[i] = XCF.layers[j] ;
+ spec->layers[i].mode = mode ;
+ spec->layers[i].opacity = opacity ;
+ spec->layers[i].hasMask = hasMask ;
+ spec->layers[i].isVisible = 1 ;
+ }
+ }
+
+ /* Force the mode of the lowest visible layer to be Normal or Dissolve.
+ * That may not be logical, but the Gimp does it
+ */
+ for( i=0; i < spec->numLayers; i++ ) {
+ if( spec->layers[i].isVisible ) {
+ if( spec->layers[i].mode != GIMP_DISSOLVE_MODE )
+ spec->layers[i].mode = GIMP_NORMAL_MODE ;
+ break ;
+ }
+ }
+
+ /* Mimic the Gimp's behavior on indexed layers */
+ if( XCF.type == GIMP_INDEXED && spec->gimpish_indexed ) {
+ for( i=0; i<spec->numLayers; i++ )
+ if( spec->layers[i].mode != GIMP_DISSOLVE_MODE )
+ spec->layers[i].mode = GIMP_NORMAL_NOPARTIAL_MODE ;
+ } else
+ spec->gimpish_indexed = 0 ;
+
+ /* compute dimensions of the window */
+ if( spec->window_mode == AUTOCROP ) {
+ int first = 1 ;
+ for( i=0; i<spec->numLayers; i++ )
+ if( spec->layers[i].isVisible ) {
+ computeDimensions(&spec->layers[i].dim) ;
+ if( first ) {
+ spec->dim = spec->layers[i].dim ;
+ first = 0 ;
+ } else {
+ if( spec->dim.c.l < spec->layers[i].dim.c.l )
+ spec->dim.c.l = spec->layers[i].dim.c.l ;
+ if( spec->dim.c.r > spec->layers[i].dim.c.r )
+ spec->dim.c.r = spec->layers[i].dim.c.r ;
+ if( spec->dim.c.t < spec->layers[i].dim.c.t )
+ spec->dim.c.t = spec->layers[i].dim.c.t ;
+ if( spec->dim.c.b > spec->layers[i].dim.c.b )
+ spec->dim.c.b = spec->layers[i].dim.c.b ;
+ }
+ }
+ if( first ) {
+ spec->window_mode = USE_CANVAS ;
+ } else {
+ spec->dim.width = spec->dim.c.r - spec->dim.c.l ;
+ spec->dim.height = spec->dim.c.b - spec->dim.c.t ;
+ }
+ }
+ if( spec->window_mode != AUTOCROP ) {
+ if( (spec->window_mode & MANUAL_OFFSET) == 0 )
+ spec->dim.c.t = spec->dim.c.l = 0 ;
+ if( (spec->window_mode & MANUAL_CROP) == 0 ) {
+ spec->dim.height = XCF.height ;
+ spec->dim.width = XCF.width ;
+ }
+ }
+ computeDimensions(&spec->dim);
+
+ /* Turn off layers that we don't hit at all */
+ for( i=0; i<spec->numLayers; i++ )
+ if( spec->layers[i].isVisible &&
+ disjointRects(spec->dim.c,spec->layers[i].dim.c) )
+ spec->layers[i].isVisible = 0 ;
+
+ /* See if there is a completely covering layer somewhere in the stack */
+ /* Also check if partial transparency is possible */
+ anyPartial = 0 ;
+ for( i=spec->numLayers; i-- ; ) {
+ if( !spec->layers[i].isVisible )
+ continue ;
+ if( typeHasTransparency(spec->layers[i].type) ) {
+ if( spec->layers[i].mode == GIMP_NORMAL_MODE )
+ anyPartial = 1;
+ } else if( isSubrect(spec->dim.c,spec->layers[i].dim.c) &&
+ (spec->layers[i].mode == GIMP_NORMAL_MODE ||
+ spec->layers[i].mode == GIMP_NORMAL_NOPARTIAL_MODE ||
+ spec->layers[i].mode == GIMP_DISSOLVE_MODE) ) {
+ /* This layer fills out the entire image.
+ * Turn off anly lower layers, and note that we cannot have
+ * transparency at all.
+ */
+ while(i) spec->layers[--i].isVisible = 0 ;
+ if( spec->default_pixel != FORCE_ALPHA_CHANNEL )
+ spec->default_pixel = NEWALPHA(colormap[0],255);
+ anyPartial = 0 ;
+ break ;
+ }
+ }
+ if( spec->partial_transparency_mode == ALLOW_PARTIAL_TRANSPARENCY &&
+ (!anyPartial || ALPHA(spec->default_pixel) >= 128) )
+ spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ;
+
+ /* Initialize layers and print overview if we're verbose */
+ for( i=spec->numLayers; i--; )
+ if( spec->layers[i].isVisible ) {
+ initLayer(&spec->layers[i]) ;
+ if( verboseFlag ) {
+ fprintf(stderr,"%dx%d%+d%+d %s %s",
+ spec->layers[i].dim.width, spec->layers[i].dim.height,
+ spec->layers[i].dim.c.l - spec->dim.c.l,
+ spec->layers[i].dim.c.t - spec->dim.c.t,
+ _(showGimpImageType(spec->layers[i].type)),
+ _(showGimpLayerModeEffects(spec->layers[i].mode)));
+ if( spec->layers[i].opacity < 255 )
+ fprintf(stderr,"/%02d%%",spec->layers[i].opacity * 100 / 255);
+ if( XCF.layers[i].hasMask )
+ fprintf(stderr,_("/mask"));
+ fprintf(stderr," %s\n",spec->layers[i].name);
+ }
+ }
+
+ /* Resolve color mode unless we wait until we have the entire image */
+ if( spec->out_color_mode == COLOR_BY_CONTENTS &&
+ !spec->process_in_memory ) {
+ if( guess_callback )
+ spec->out_color_mode = guess_callback(spec,NULL);
+ if( spec->out_color_mode == COLOR_BY_CONTENTS )
+ spec->out_color_mode = color_by_layers(spec) ;
+ }
+}
+
+void
+analyse_colormode(struct FlattenSpec *spec,rgba **allPixels,
+ guesser guess_callback)
+{
+ unsigned x,y ;
+ int status ;
+ /* 8 - looking for any transparency
+ * 4 - looking for partially transparent pixels
+ * 2 - looking for pixels other than black and white
+ * 1 - looking for colored pixels
+ */
+ int known_absent = 0 ;
+ int assume_present = 0 ;
+
+ if( spec->out_color_mode == COLOR_BY_CONTENTS && guess_callback )
+ spec->out_color_mode = guess_callback(spec,allPixels) ;
+
+ if( spec->out_color_mode == COLOR_RGB ) assume_present |= 3 ;
+ if( spec->out_color_mode == COLOR_INDEXED ) assume_present |= 3 ;
+ if( spec->out_color_mode == COLOR_GRAY ) assume_present |= 2 ;
+ switch( color_by_layers(spec) ) {
+ case COLOR_GRAY: known_absent |= 1 ; break ;
+ case COLOR_MONO: known_absent |= 3 ; break ;
+ default: break ;
+ }
+ if( spec->partial_transparency_mode == DISSOLVE_PARTIAL_TRANSPARENCY ||
+ spec->partial_transparency_mode == PARTIAL_TRANSPARENCY_IMPOSSIBLE )
+ known_absent |= 4 ;
+ if( ALPHA(spec->default_pixel) >= 128 ) known_absent |= 12 ;
+ else if( spec->default_pixel == FORCE_ALPHA_CHANNEL ) assume_present |= 8 ;
+
+ status = 15 - (known_absent | assume_present) ;
+
+ for( y=0; status && y<spec->dim.height; y++ ) {
+ rgba *row = allPixels[y] ;
+ if( (status & 3) != 0 ) {
+ /* We're still interested in color */
+ for( x=0; status && x<spec->dim.width; x++ ) {
+ if( NULLALPHA(row[x]) )
+ status &= ~8 ;
+ else {
+ rgba full = row[x] | (255 << ALPHA_SHIFT) ;
+ if( !FULLALPHA(row[x]) ) status &= ~12 ;
+ if( full == NEWALPHA(0,255) || full == NEWALPHA(-1,255) )
+ /* Black or white */ ;
+ else if( degrayPixel(row[x]) != -1 )
+ status &= ~2 ; /* gray */
+ else
+ status &= ~3 ; /* color */
+ }
+ }
+ } else {
+ /* Not interested in color */
+ for( x=0; status && x<spec->dim.width; x++ ) {
+ if( NULLALPHA(row[x]) )
+ status &= ~8 ;
+ else if( !FULLALPHA(row[x]) )
+ status &= ~12 ;
+ }
+ }
+ }
+
+ status |= known_absent ;
+
+ switch( spec->out_color_mode ) {
+ case COLOR_INDEXED: /* The caller takes responsibility */
+ case COLOR_RGB: /* Everything is fine. */
+ break ;
+ case COLOR_GRAY:
+ if( (status & 1) == 0 )
+ FatalGeneric(103,
+ _("Grayscale output selected, but colored pixel(s) found"));
+ break ;
+ case COLOR_MONO:
+ if( (status & 2) == 0 )
+ FatalGeneric(103,_("Monochrome output selected, but not all pixels "
+ "are black or white"));
+ break ;
+ case COLOR_BY_FILENAME: /* Should not happen ... */
+ case COLOR_BY_CONTENTS:
+ if( (status & 1) == 0 )
+ spec->out_color_mode = COLOR_RGB ;
+ else if( (status & 2) == 0 )
+ spec->out_color_mode = COLOR_GRAY ;
+ else
+ spec->out_color_mode = COLOR_MONO ;
+ break ;
+ }
+
+ if( (status & 12) == 12 ) /* No transparency found */
+ spec->default_pixel = NEWALPHA(colormap[0],255);
+ else if( (status & 12) == 4 )
+ spec->partial_transparency_mode = PARTIAL_TRANSPARENCY_IMPOSSIBLE ;
+}
diff --git a/kernel/kls_xcf/xcf2pnm/flatten.c b/kernel/kls_xcf/xcf2pnm/flatten.c
new file mode 100644
index 0000000..c564ddd
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/flatten.c
@@ -0,0 +1,689 @@
+/* Flattning functions for xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xcftools.h"
+#include "flatten.h"
+#include "pixels.h"
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+static rgba __ATTRIBUTE__((noinline,const))
+composite_one(rgba bot,rgba top)
+{
+ unsigned tfrac, alpha ;
+
+ tfrac = ALPHA(top) ;
+ alpha = 255 ;
+ if( !FULLALPHA(bot) ) {
+ alpha = 255 ^ scaletable[255-ALPHA(bot)][255-ALPHA(top)] ;
+ /* This peculiar combination of ^ and - makes the GCC code
+ * generator for i386 particularly happy.
+ */
+ tfrac = (256*ALPHA(top) - 1) / alpha ;
+ /* Tfrac is the fraction of the coposited pixel's covered area
+ * that comes from the top pixel.
+ * For mathematical accuracy we ought to scale by 255 and
+ * subtract alpha/2, but this is faster, and never misses the
+ * true value by more than one 1/255. This effect is completely
+ * overshadowed by the linear interpolation in the first place.
+ * (I.e. gamma is ignored when combining intensities).
+ * [In any case, complete fairness is not possible: if the
+ * bottom pixel had alpha=170 and the top has alpha=102,
+ * each should contribute equally to the color of the
+ * resulting alpha=204 pixel, which is not possible in general]
+ * Subtracting one helps the topfrac never be 256, which would
+ * be bad.
+ * On the other hand it means that we would get tfrac=-1 if the
+ * top pixel is completely transparent, and we get a division
+ * by zero if _both_ pixels are fully transparent. These cases
+ * must be handled by all callers.
+ * More snooping in the Gimp sources reveal that it uses
+ * floating-point for its equivalent of tfrac when the
+ * bottom layer has an alpha channel. (alphify() macro
+ * in paint-funcs.c). What gives?
+ */
+ }
+ return (alpha << ALPHA_SHIFT)
+ + ((uint32_t)scaletable[ tfrac ][255&(top>>RED_SHIFT )] << RED_SHIFT )
+ + ((uint32_t)scaletable[ tfrac ][255&(top>>GREEN_SHIFT)] << GREEN_SHIFT )
+ + ((uint32_t)scaletable[ tfrac ][255&(top>>BLUE_SHIFT )] << BLUE_SHIFT )
+ + ((uint32_t)scaletable[255^tfrac][255&(bot>>RED_SHIFT )] << RED_SHIFT )
+ + ((uint32_t)scaletable[255^tfrac][255&(bot>>GREEN_SHIFT)] << GREEN_SHIFT )
+ + ((uint32_t)scaletable[255^tfrac][255&(bot>>BLUE_SHIFT )] << BLUE_SHIFT )
+ ;
+}
+
+/* merge_normal() takes ownership of bot.
+ * merge_normal() will share ownership of top.
+ * Return: may be shared.
+ */
+static struct Tile * __ATTRIBUTE__((noinline))
+merge_normal(struct Tile *bot, struct Tile *top)
+{
+ unsigned i ;
+ assertTileCompatibility(bot,top);
+
+ /* See if there is an easy winner */
+ if( (bot->summary & TILESUMMARY_ALLNULL) ||
+ (top->summary & TILESUMMARY_ALLFULL) ) {
+ freeTile(bot);
+ return top ;
+ }
+ if( top->summary & TILESUMMARY_ALLNULL ) {
+ freeTile(top);
+ return bot ;
+ }
+
+ /* Try hard to make top win */
+ for( i=0; ; i++ ) {
+ if( i == top->count ) {
+ freeTile(bot);
+ return top ;
+ }
+ if( !(NULLALPHA(bot->pixels[i]) || FULLALPHA(top->pixels[i])) )
+ break ;
+ }
+
+ INIT_SCALETABLE_IF( !(top->summary & TILESUMMARY_CRISP) );
+
+ /* Otherwise bot wins, but is forever changed ... */
+ if( (top->summary & TILESUMMARY_ALLNULL) == 0 ) {
+ unsigned i ;
+ invalidateSummary(bot,0);
+ for( i=0 ; i < top->count ; i++ ) {
+ if( !NULLALPHA(top->pixels[i]) ) {
+ if( FULLALPHA(top->pixels[i]) || NULLALPHA(bot->pixels[i]) )
+ bot->pixels[i] = top->pixels[i] ;
+ else
+ bot->pixels[i] = composite_one(bot->pixels[i],top->pixels[i]);
+ }
+ }
+ }
+ freeTile(top);
+ return bot ;
+}
+
+#define exotic_combinator static inline unsigned __ATTRIBUTE__((const))
+
+
+
+exotic_combinator
+ucombine_ADDITION(uint8_t bot,uint8_t top)
+{
+ return bot+top > 255 ? 255 : bot+top ;
+}
+
+exotic_combinator
+ucombine_SUBTRACT(uint8_t bot,uint8_t top)
+{
+ return top>bot ? 0 : bot-top ;
+}
+
+exotic_combinator
+ucombine_LIGHTEN_ONLY(uint8_t bot,uint8_t top)
+{
+ return top > bot ? top : bot ;
+}
+
+exotic_combinator
+ucombine_DARKEN_ONLY(uint8_t bot,uint8_t top)
+{
+ return top < bot ? top : bot ;
+}
+
+exotic_combinator
+ucombine_DIFFERENCE(uint8_t bot,uint8_t top)
+{
+ return top > bot ? top-bot : bot-top ;
+}
+
+exotic_combinator
+ucombine_MULTIPLY(uint8_t bot,uint8_t top)
+{
+ return scaletable[bot][top] ;
+}
+
+exotic_combinator
+ucombine_DIVIDE(uint8_t bot,uint8_t top)
+{
+ int result = (int)bot*256 / (1+top) ;
+ return result >= 256 ? 255 : result ;
+}
+
+exotic_combinator
+ucombine_SCREEN(uint8_t bot,uint8_t top)
+{
+ /* An inverted version of "multiply" */
+ return 255 ^ scaletable[255-bot][255-top] ;
+}
+
+exotic_combinator
+ucombine_OVERLAY(uint8_t bot,uint8_t top)
+{
+ return scaletable[bot][bot] +
+ 2*scaletable[top][scaletable[bot][255-bot]] ;
+ /* This strange formula is equivalent to
+ * (1-top)*(bot^2) + top*(1-(1-top)^2)
+ * that is, the top value is used to interpolate between
+ * the self-multiply and the self-screen of the bottom.
+ */
+ /* Note: This is exactly what the "Soft light" effect also
+ * does, though with different code in the Gimp.
+ */
+}
+
+exotic_combinator
+ucombine_DODGE(uint8_t bot,uint8_t top)
+{
+ return ucombine_DIVIDE(bot,255-top);
+}
+
+exotic_combinator
+ucombine_BURN(uint8_t bot,uint8_t top)
+{
+ return 255 - ucombine_DIVIDE(255-bot,top);
+}
+
+exotic_combinator
+ucombine_HARDLIGHT(uint8_t bot,uint8_t top)
+{
+ if( top >= 128 )
+ return 255 ^ scaletable[255-bot][2*(255-top)] ;
+ else
+ return scaletable[bot][2*top];
+ /* The code that implements "hardlight" in Gimp 2.2.10 has some
+ * rounding errors, but this is undoubtedly what is meant.
+ */
+}
+
+exotic_combinator
+ucombine_GRAIN_EXTRACT(uint8_t bot,uint8_t top)
+{
+ int temp = (int)bot - (int)top + 128 ;
+ return temp < 0 ? 0 : temp >= 256 ? 255 : temp ;
+}
+
+exotic_combinator
+ucombine_GRAIN_MERGE(uint8_t bot,uint8_t top)
+{
+ int temp = (int)bot + (int)top - 128 ;
+ return temp < 0 ? 0 : temp >= 256 ? 255 : temp ;
+}
+
+struct HSV {
+ enum { HUE_RED_GREEN_BLUE,HUE_RED_BLUE_GREEN,HUE_BLUE_RED_GREEN,
+ HUE_BLUE_GREEN_RED,HUE_GREEN_BLUE_RED,HUE_GREEN_RED_BLUE } hue;
+ unsigned ch1, ch2, ch3 ;
+};
+
+static void
+RGBtoHSV(rgba rgb,struct HSV *hsv)
+{
+ unsigned RED = (uint8_t)(rgb >> RED_SHIFT);
+ unsigned GREEN = (uint8_t)(rgb >> GREEN_SHIFT);
+ unsigned BLUE = (uint8_t)(rgb >> BLUE_SHIFT) ;
+ #define HEXTANT(b,m,t) hsv->ch1 = b, hsv->ch2 = m, hsv->ch3 = t, \
+ hsv->hue = HUE_ ## b ## _ ## m ## _ ## t
+ if( GREEN <= RED )
+ if( BLUE <= RED )
+ if( GREEN <= BLUE )
+ HEXTANT(GREEN,BLUE,RED);
+ else
+ HEXTANT(BLUE,GREEN,RED);
+ else
+ HEXTANT(GREEN,RED,BLUE);
+ else if( BLUE <= RED )
+ HEXTANT(BLUE,RED,GREEN);
+ else if( BLUE <= GREEN )
+ HEXTANT(RED,BLUE,GREEN);
+ else
+ HEXTANT(RED,GREEN,BLUE);
+ #undef HEXTANT
+}
+
+/* merge_exotic() destructively updates bot.
+ * merge_exotic() reads but does not free top.
+ */
+static void __ATTRIBUTE__((noinline))
+merge_exotic(struct Tile *bot, const struct Tile *top,
+ GimpLayerModeEffects mode)
+{
+ unsigned i ;
+ assertTileCompatibility(bot,top);
+ if( (bot->summary & TILESUMMARY_ALLNULL) != 0 ) return ;
+ if( (top->summary & TILESUMMARY_ALLNULL) != 0 ) return ;
+ assert( bot->refcount == 1 );
+ /* The transparency status of bot never changes */
+
+ INIT_SCALETABLE_IF(1);
+
+ for( i=0; i < top->count ; i++ ) {
+ uint32_t RED, GREEN, BLUE ;
+ if( NULLALPHA(bot->pixels[i]) || NULLALPHA(top->pixels[i]) )
+ continue ;
+#define UNIFORM(mode) case GIMP_ ## mode ## _MODE: \
+ RED = ucombine_ ## mode (bot->pixels[i]>>RED_SHIFT , \
+ top->pixels[i]>>RED_SHIFT ); \
+ GREEN = ucombine_ ## mode (bot->pixels[i]>>GREEN_SHIFT, \
+ top->pixels[i]>>GREEN_SHIFT); \
+ BLUE = ucombine_ ## mode (bot->pixels[i]>>BLUE_SHIFT , \
+ top->pixels[i]>>BLUE_SHIFT ); \
+ break ;
+ switch( mode ) {
+ case GIMP_NORMAL_MODE:
+ case GIMP_DISSOLVE_MODE:
+ FatalUnexpected("Normal and Dissolve mode can't happen here!");
+ UNIFORM(ADDITION);
+ UNIFORM(SUBTRACT);
+ UNIFORM(LIGHTEN_ONLY);
+ UNIFORM(DARKEN_ONLY);
+ UNIFORM(DIFFERENCE);
+ UNIFORM(MULTIPLY);
+ UNIFORM(DIVIDE);
+ UNIFORM(SCREEN);
+ case GIMP_SOFTLIGHT_MODE: /* A synonym for "overlay"! */
+ UNIFORM(OVERLAY);
+ UNIFORM(DODGE);
+ UNIFORM(BURN);
+ UNIFORM(HARDLIGHT);
+ UNIFORM(GRAIN_EXTRACT);
+ UNIFORM(GRAIN_MERGE);
+ case GIMP_HUE_MODE:
+ case GIMP_SATURATION_MODE:
+ case GIMP_VALUE_MODE:
+ case GIMP_COLOR_MODE:
+ {
+ static struct HSV hsvTop, hsvBot ;
+ RGBtoHSV(top->pixels[i],&hsvTop);
+ if( mode == GIMP_HUE_MODE && hsvTop.ch1 == hsvTop.ch3 )
+ continue ;
+ RGBtoHSV(bot->pixels[i],&hsvBot);
+ if( mode == GIMP_VALUE_MODE ) {
+ if( hsvBot.ch3 ) {
+ hsvBot.ch1 = (hsvBot.ch1*hsvTop.ch3 + hsvBot.ch3/2) / hsvBot.ch3;
+ hsvBot.ch2 = (hsvBot.ch2*hsvTop.ch3 + hsvBot.ch3/2) / hsvBot.ch3;
+ hsvBot.ch3 = hsvTop.ch3 ;
+ } else {
+ hsvBot.ch1 = hsvBot.ch2 = hsvBot.ch3 = hsvTop.ch3 ;
+ }
+ } else {
+ unsigned mfNum, mfDenom ;
+ if( mode == GIMP_HUE_MODE || mode == GIMP_COLOR_MODE ) {
+ mfNum = hsvTop.ch2-hsvTop.ch1 ;
+ mfDenom = hsvTop.ch3-hsvTop.ch1 ;
+ hsvBot.hue = hsvTop.hue ;
+ } else {
+ mfNum = hsvBot.ch2-hsvBot.ch1 ;
+ mfDenom = hsvBot.ch3-hsvBot.ch1 ;
+ }
+ if( mode == GIMP_SATURATION_MODE ) {
+ if( hsvTop.ch3 == 0 )
+ hsvBot.ch1 = hsvBot.ch3 ; /* Black has no saturation */
+ else
+ hsvBot.ch1 = (hsvTop.ch1*hsvBot.ch3 + hsvTop.ch3/2) / hsvTop.ch3;
+ } else if( mode == GIMP_COLOR_MODE ) {
+ /* GIMP_COLOR_MODE works in HSL space instead of HSV. We must
+ * transfer H and S, keeping the L = ch1+ch3 of the bottom pixel,
+ * but the S we transfer works differently from the S in HSV.
+ */
+ unsigned L = hsvTop.ch1 + hsvTop.ch3 ;
+ unsigned sNum = hsvTop.ch3 - hsvTop.ch1 ;
+ unsigned sDenom = L < 256 ? L : 510-L ;
+ if( sDenom == 0 ) sDenom = 1 ; /* sNum will be 0 */
+ L = hsvBot.ch1 + hsvBot.ch3 ;
+ if( L < 256 ) {
+ /* Ideally we want to compute L/2 * (1-sNum/sDenom)
+ * But shuffle this a bit so we can use integer arithmetic.
+ * The "-1" in the rounding prevents us from ending up with
+ * ch1 > ch3.
+ */
+ hsvBot.ch1 = (L*(sDenom-sNum)+sDenom-1)/(2*sDenom);
+ hsvBot.ch3 = L - hsvBot.ch1 ;
+ } else {
+ /* Here our goal is 255 - (510-L)/2 * (1-sNum/sDenom) */
+ hsvBot.ch3 = 255 - ((510-L)*(sDenom-sNum)+sDenom-1)/(2*sDenom);
+ hsvBot.ch1 = L - hsvBot.ch3 ;
+ }
+ assert(hsvBot.ch3 <= 255);
+ assert(hsvBot.ch3 >= hsvBot.ch1);
+ }
+ if( mfDenom == 0 )
+ hsvBot.ch2 = hsvBot.ch1 ;
+ else
+ hsvBot.ch2 = hsvBot.ch1 +
+ (mfNum*(hsvBot.ch3-hsvBot.ch1) + mfDenom/2) / mfDenom ;
+ }
+ switch( hsvBot.hue ) {
+ #define HEXTANT(b,m,t) case HUE_ ## b ## _ ## m ## _ ## t : \
+ b = hsvBot.ch1; m = hsvBot.ch2; t = hsvBot.ch3; break;
+ HEXTANT(RED,GREEN,BLUE);
+ HEXTANT(RED,BLUE,GREEN);
+ HEXTANT(BLUE,RED,GREEN);
+ HEXTANT(BLUE,GREEN,RED);
+ HEXTANT(GREEN,BLUE,RED);
+ HEXTANT(GREEN,RED,BLUE);
+ #undef HEXTANT
+ }
+ break ;
+ }
+ default:
+ FatalUnsupportedXCF(_("'%s' layer mode"),
+ _(showGimpLayerModeEffects(mode)));
+ }
+ if( FULLALPHA(bot->pixels[i] & top->pixels[i]) )
+ bot->pixels[i] = (bot->pixels[i] & (255 << ALPHA_SHIFT)) +
+ (RED << RED_SHIFT) +
+ (GREEN << GREEN_SHIFT) +
+ (BLUE << BLUE_SHIFT) ;
+ else {
+ rgba bp = bot->pixels[i] ;
+ /* In a sane world, the alpha of the top pixel would simply be
+ * used to interpolate linearly between the bottom pixel's base
+ * color and the effect-computed color.
+ * But no! What the Gimp actually does is empirically
+ * described by the following (which borrows code from
+ * composite_one() that makes no theoretical sense here):
+ */
+ unsigned tfrac = ALPHA(top->pixels[i]) ;
+ if( !FULLALPHA(bp) ) {
+ unsigned pseudotop = (tfrac < ALPHA(bp) ? tfrac : ALPHA(bp));
+ unsigned alpha = 255 ^ scaletable[255-ALPHA(bp)][255-pseudotop] ;
+ tfrac = (256*pseudotop - 1) / alpha ;
+ }
+ bot->pixels[i] = (bp & (255 << ALPHA_SHIFT)) +
+ ((rgba)scaletable[ tfrac ][ RED ] << RED_SHIFT ) +
+ ((rgba)scaletable[ tfrac ][ GREEN ] << GREEN_SHIFT) +
+ ((rgba)scaletable[ tfrac ][ BLUE ] << BLUE_SHIFT ) +
+ ((rgba)scaletable[255^tfrac][255&(bp>>RED_SHIFT )] << RED_SHIFT ) +
+ ((rgba)scaletable[255^tfrac][255&(bp>>GREEN_SHIFT)] << GREEN_SHIFT) +
+ ((rgba)scaletable[255^tfrac][255&(bp>>BLUE_SHIFT )] << BLUE_SHIFT ) ;
+ }
+ }
+ return ;
+}
+
+static void
+dissolveTile(struct Tile *tile)
+{
+ unsigned i ;
+ summary_t summary ;
+ assert( tile->refcount == 1 );
+ if( (tile->summary & TILESUMMARY_CRISP) )
+ return ;
+ summary = TILESUMMARY_UPTODATE + TILESUMMARY_ALLNULL
+ + TILESUMMARY_ALLFULL + TILESUMMARY_CRISP ;
+ for( i = 0 ; i < tile->count ; i++ ) {
+ if( FULLALPHA(tile->pixels[i]) )
+ summary &= ~TILESUMMARY_ALLNULL ;
+ else if ( NULLALPHA(tile->pixels[i]) )
+ summary &= ~TILESUMMARY_ALLFULL ;
+ else if( ALPHA(tile->pixels[i]) > rand() % 0xFF ) {
+ tile->pixels[i] |= 255 << ALPHA_SHIFT ;
+ summary &= ~TILESUMMARY_ALLNULL ;
+ } else {
+ tile->pixels[i] = 0 ;
+ summary &= ~TILESUMMARY_ALLFULL ;
+ }
+ }
+ tile->summary = summary ;
+}
+
+static void
+roundAlpha(struct Tile *tile)
+{
+ unsigned i ;
+ summary_t summary ;
+ assert( tile->refcount == 1 );
+ if( (tile->summary & TILESUMMARY_CRISP) )
+ return ;
+ summary = TILESUMMARY_UPTODATE + TILESUMMARY_ALLNULL
+ + TILESUMMARY_ALLFULL + TILESUMMARY_CRISP ;
+ for( i = 0 ; i < tile->count ; i++ ) {
+ if( ALPHA(tile->pixels[i]) >= 128 ) {
+ tile->pixels[i] |= 255 << ALPHA_SHIFT ;
+ summary &= ~TILESUMMARY_ALLNULL ;
+ } else {
+ tile->pixels[i] = 0 ;
+ summary &= ~TILESUMMARY_ALLFULL ;
+ }
+ }
+ tile->summary = summary ;
+}
+
+/* flattenTopdown() shares ownership of top.
+ * The return value may be a shared tile.
+ */
+static struct Tile *
+flattenTopdown(struct FlattenSpec *spec, struct Tile *top,
+ unsigned nlayers, const struct rect *where)
+{
+ struct Tile *tile;
+
+ while( nlayers-- ) {
+ if( tileSummary(top) & TILESUMMARY_ALLFULL )
+ return top ;
+ if( !spec->layers[nlayers].isVisible )
+ continue ;
+
+ tile = getLayerTile(&spec->layers[nlayers],where);
+
+ if( tile->summary & TILESUMMARY_ALLNULL )
+ continue ; /* Simulate a tail call */
+
+ switch( spec->layers[nlayers].mode ) {
+ case GIMP_NORMAL_NOPARTIAL_MODE:
+ roundAlpha(tile) ;
+ /* fall through */
+ if(0) {
+ case GIMP_DISSOLVE_MODE:
+ dissolveTile(tile);
+ /* fall through */
+ }
+ case GIMP_NORMAL_MODE:
+ top = merge_normal(tile,top);
+ break ;
+ default:
+ {
+ struct Tile *below, *above ;
+ unsigned i ;
+ if( !(top->summary & TILESUMMARY_ALLNULL) ) {
+ rgba tile_or = 0 ;
+ invalidateSummary(tile,0);
+ for( i=0; i<top->count; i++ )
+ if( FULLALPHA(top->pixels[i]) )
+ tile->pixels[i] = 0 ;
+ else
+ tile_or |= tile->pixels[i] ;
+ /* If the tile only has pixels that will be covered by 'top' anyway,
+ * forget it anyway.
+ */
+ if( ALPHA(tile_or) == 0 ) {
+ freeTile(tile);
+ break ; /* from the switch, which will continue the while */
+ }
+ }
+ /* Create a dummy top for the layers below this */
+ if( top->summary & TILESUMMARY_CRISP ) {
+ above = forkTile(top);
+ } else {
+ summary_t summary = TILESUMMARY_ALLNULL ;
+ above = newTile(*where);
+ for( i=0; i<top->count; i++ )
+ if( FULLALPHA(top->pixels[i]) ) {
+ above->pixels[i] = -1 ;
+ summary = 0 ;
+ } else
+ above->pixels[i] = 0 ;
+ above->summary = TILESUMMARY_UPTODATE + TILESUMMARY_CRISP + summary;
+ }
+ below = flattenTopdown(spec, above, nlayers, where);
+ if( below->refcount > 1 ) {
+ assert( below == top );
+ /* This can only happen if 'below' is a copy of 'top'
+ * THROUGH 'above', which in turn means that none of all
+ * this is visible after all. So just free it and return 'top'.
+ */
+ freeTile(below);
+ return top ;
+ }
+ merge_exotic(below,tile,spec->layers[nlayers].mode);
+ freeTile(tile);
+ top = merge_normal(below,top);
+ return top ;
+ }
+ }
+ }
+ return top ;
+}
+
+static void
+addBackground(struct FlattenSpec *spec, struct Tile *tile, unsigned ncols)
+{
+ unsigned i ;
+
+ if( tileSummary(tile) & TILESUMMARY_ALLFULL )
+ return ;
+
+ switch( spec->partial_transparency_mode ) {
+ case FORBID_PARTIAL_TRANSPARENCY:
+ if( !(tileSummary(tile) & TILESUMMARY_CRISP) )
+ FatalGeneric(102,_("Flattened image has partially transparent pixels"));
+ break ;
+ case DISSOLVE_PARTIAL_TRANSPARENCY:
+ dissolveTile(tile);
+ break ;
+ case ALLOW_PARTIAL_TRANSPARENCY:
+ case PARTIAL_TRANSPARENCY_IMPOSSIBLE:
+ break ;
+ }
+
+ if( spec->default_pixel == CHECKERED_BACKGROUND ) {
+ INIT_SCALETABLE_IF( !(tile->summary & TILESUMMARY_CRISP ) );
+ for( i=0; i<tile->count; i++ )
+ if( !FULLALPHA(tile->pixels[i]) ) {
+ rgba fillwith = ((i/ncols)^(i%ncols))&8 ? 0x66 : 0x99 ;
+ fillwith = graytable[fillwith] + (255 << ALPHA_SHIFT) ;
+ if( NULLALPHA(tile->pixels[i]) )
+ tile->pixels[i] = fillwith ;
+ else
+ tile->pixels[i] = composite_one(fillwith,tile->pixels[i]);
+ }
+ tile->summary = TILESUMMARY_UPTODATE +
+ TILESUMMARY_ALLFULL + TILESUMMARY_CRISP ;
+ return ;
+ }
+ if( !FULLALPHA(spec->default_pixel) ) return ;
+ if( tileSummary(tile) & TILESUMMARY_ALLNULL ) {
+ fillTile(tile,spec->default_pixel);
+ } else {
+ INIT_SCALETABLE_IF( !(tile->summary & TILESUMMARY_CRISP) );
+ for( i=0; i<tile->count; i++ )
+ if( NULLALPHA(tile->pixels[i]) )
+ tile->pixels[i] = spec->default_pixel ;
+ else if( FULLALPHA(tile->pixels[i]) )
+ ;
+ else
+ tile->pixels[i] = composite_one(spec->default_pixel,tile->pixels[i]);
+
+ tile->summary = TILESUMMARY_UPTODATE +
+ TILESUMMARY_ALLFULL + TILESUMMARY_CRISP ;
+ }
+}
+
+void
+flattenIncrementally(struct FlattenSpec *spec,lineCallback callback)
+{
+ rgba *rows[TILE_HEIGHT] ;
+ unsigned i, y, nrows, ncols ;
+ struct rect where ;
+ struct Tile *tile ;
+ static struct Tile toptile ;
+
+ toptile.count = TILE_HEIGHT * TILE_WIDTH ;
+ fillTile(&toptile,0);
+
+ for( where.t = spec->dim.c.t; where.t < spec->dim.c.b; where.t=where.b ) {
+ where.b = (where.t+TILE_HEIGHT) - where.t % TILE_HEIGHT ;
+ if( where.b > spec->dim.c.b ) where.b = spec->dim.c.b ;
+ nrows = where.b - where.t ;
+ for( y = 0; y < nrows ; y++ )
+ rows[y] = xcfmalloc(4*(spec->dim.c.r-spec->dim.c.l));
+
+ for( where.l = spec->dim.c.l; where.l < spec->dim.c.r; where.l=where.r ) {
+ where.r = (where.l+TILE_WIDTH) - where.l % TILE_WIDTH ;
+ if( where.r > spec->dim.c.r ) where.r = spec->dim.c.r ;
+ ncols = where.r - where.l ;
+
+ toptile.count = ncols * nrows ;
+ toptile.refcount = 2 ; /* For bug checking */
+ assert( toptile.summary == TILESUMMARY_UPTODATE +
+ TILESUMMARY_ALLNULL + TILESUMMARY_CRISP );
+ tile = flattenTopdown(spec,&toptile,spec->numLayers,&where) ;
+ toptile.refcount-- ; /* addBackground may change destructively */
+ addBackground(spec,tile,ncols);
+
+ for( i = 0 ; i < tile->count ; i++ )
+ if( NULLALPHA(tile->pixels[i]) )
+ tile->pixels[i] = 0 ;
+ for( y = 0 ; y < nrows ; y++ )
+ memcpy(rows[y] + (where.l - spec->dim.c.l),
+ tile->pixels + y * ncols, ncols*4);
+
+ if( tile == &toptile ) {
+ fillTile(&toptile,0);
+ } else {
+ freeTile(tile);
+ }
+ }
+ for( y = 0 ; y < nrows ; y++ )
+ callback(spec->dim.width,rows[y]);
+ }
+}
+
+static rgba **collectPointer ;
+
+static void
+collector(unsigned num,rgba *row)
+{
+ *collectPointer++ = row ;
+}
+
+rgba **
+flattenAll(struct FlattenSpec *spec)
+{
+ rgba **rows = xcfmalloc(spec->dim.height * sizeof(rgba*));
+ if( verboseFlag )
+ fprintf(stderr,_("Flattening image ..."));
+ collectPointer = rows ;
+ flattenIncrementally(spec,collector);
+ if( verboseFlag )
+ fprintf(stderr,"\n");
+ return rows ;
+}
+
+void
+shipoutWithCallback(struct FlattenSpec *spec, rgba **pixels,
+ lineCallback callback)
+{
+ unsigned i ;
+ for( i = 0; i < spec->dim.height; i++ ) {
+ callback(spec->dim.width,pixels[i]);
+ }
+ xcffree(pixels);
+}
diff --git a/kernel/kls_xcf/xcf2pnm/flatten.h b/kernel/kls_xcf/xcf2pnm/flatten.h
new file mode 100644
index 0000000..c252175
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/flatten.h
@@ -0,0 +1,77 @@
+/* Flattning functions for xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef FLATTEN_H
+#define FLATTEN_H
+
+#include "xcftools.h"
+#include "pixels.h"
+
+#define PERHAPS_ALPHA_CHANNEL (NEWALPHA(0,1))
+#define FORCE_ALPHA_CHANNEL (NEWALPHA(0,2))
+#define CHECKERED_BACKGROUND (NEWALPHA(0,200))
+struct FlattenSpec {
+ struct tileDimensions dim ;
+ rgba default_pixel ;
+ int numLayers ;
+ struct xcfLayer *layers ;
+
+ const char * transmap_filename ;
+ const char * output_filename ;
+ enum out_color_mode {
+ COLOR_BY_FILENAME,
+ COLOR_BY_CONTENTS,
+ COLOR_INDEXED,
+ COLOR_RGB,
+ COLOR_GRAY,
+ COLOR_MONO
+ } out_color_mode ;
+ enum { ALLOW_PARTIAL_TRANSPARENCY,
+ DISSOLVE_PARTIAL_TRANSPARENCY,
+ FORBID_PARTIAL_TRANSPARENCY,
+ PARTIAL_TRANSPARENCY_IMPOSSIBLE
+ } partial_transparency_mode ;
+ enum { USE_CANVAS = 0,
+ MANUAL_OFFSET = 1,
+ MANUAL_CROP = 2,
+ AUTOCROP = 4 } window_mode ;
+ int process_in_memory ;
+ int gimpish_indexed ;
+};
+
+/* From flatspec.c */
+
+void init_flatspec(struct FlattenSpec *);
+
+void add_layer_request(struct FlattenSpec *,const char *name);
+struct xcfLayer *lastlayerspec(struct FlattenSpec *,const char *option);
+
+typedef enum out_color_mode (*guesser) (struct FlattenSpec *,rgba **);
+
+/* Call this after processing options, and after opening the XCF file */
+void complete_flatspec(struct FlattenSpec *,guesser);
+void analyse_colormode(struct FlattenSpec *,rgba **allPixels,guesser);
+
+/* From flatten.c */
+
+typedef void (*lineCallback)(unsigned num,rgba *pixels);
+void flattenIncrementally(struct FlattenSpec *,lineCallback);
+rgba **flattenAll(struct FlattenSpec*);
+void shipoutWithCallback(struct FlattenSpec *,rgba **pixels,lineCallback);
+
+#endif /* FLATTEN_H */
diff --git a/kernel/kls_xcf/xcf2pnm/io-unix.c b/kernel/kls_xcf/xcf2pnm/io-unix.c
new file mode 100644
index 0000000..38dc4e4
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/io-unix.c
@@ -0,0 +1,176 @@
+/* OS-specific IO functions for xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xcftools.h"
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#if HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+static FILE *xcfstream = 0 ;
+
+void
+free_or_close_xcf(void)
+{
+ if( xcf_file ) {
+ if( xcfstream ) {
+ munmap(xcf_file,xcf_length) ;
+ fclose(xcfstream);
+ xcf_file = 0 ;
+ xcfstream = 0 ;
+ } else {
+ free(xcf_file) ;
+ xcf_file = 0 ;
+ }
+ }
+}
+
+void
+read_or_mmap_xcf(const char *filename,const char *unzipper)
+{
+ struct stat statbuf ;
+
+ free_or_close_xcf() ;
+
+ if( strcmp(filename,"-") != 0 ) {
+ if( access(filename,R_OK) != 0 )
+ FatalGeneric(21,"!%s",filename);
+ }
+
+ if( !unzipper ) {
+ const char *pc ;
+ pc = filename + strlen(filename) ;
+ if( pc-filename > 2 && strcmp(pc-2,"gz") == 0 )
+ unzipper = "zcat" ;
+ else if ( pc-filename > 3 && strcmp(pc-3,"bz2") == 0 )
+ unzipper = "bzcat" ;
+ else
+ unzipper = "" ;
+ } else if( strcmp(unzipper,"cat") == 0 )
+ unzipper = "" ;
+
+ if( *unzipper ) {
+ int pid, status, outfd ;
+#if HAVE_MMAP
+ xcfstream = tmpfile() ;
+ if( !xcfstream )
+ FatalUnexpected(_("!Cannot create temporary unzipped file"));
+ outfd = fileno(xcfstream) ;
+#else
+ int fh[2] ;
+ if( pipe(fh) < 0 )
+ FatalUnexpected("!Cannot create pipe for %s",unzipper);
+ xcfstream = fdopen(fh[1],"rb") ;
+ if( !xcfstream )
+ FatalUnexpected("!Cannot fdopen() unzipper pipe");
+ outfd = fh[0] ;
+#endif
+ if( (pid = fork()) == 0 ) {
+ /* We're the child */
+ if( dup2(outfd,1) < 0 ) {
+ perror("Cannot dup2 in unzip process");
+ exit(127) ;
+ }
+ fclose(xcfstream) ;
+ execlp(unzipper,unzipper,filename,NULL) ;
+ fprintf(stderr,_("Cannot execute "));
+ perror(unzipper);
+ exit(126) ;
+ }
+#if HAVE_MMAP
+ while( wait(&status) != pid )
+ ;
+ if( WIFEXITED(status) ) {
+ status = WEXITSTATUS(status) ;
+ if( status > 0 ) {
+ fclose(xcfstream) ;
+ xcfstream = 0 ;
+ FatalGeneric(status,NULL);
+ }
+ } else {
+ fclose(xcfstream) ;
+ xcfstream = 0 ;
+ FatalGeneric(126,_("%s terminated abnormally"),unzipper);
+ }
+#else
+ close(fh[0]) ;
+#endif
+ } else if( strcmp(filename,"-") == 0 ) {
+ xcfstream = fdopen(dup(0),"rb") ;
+ if( !xcfstream )
+ FatalUnexpected("!Cannot dup stdin for input") ;
+ } else {
+ xcfstream = fopen(filename,"rb") ;
+ if( !xcfstream )
+ FatalGeneric(21,_("!Cannot open %s"),filename);
+ }
+ /* OK, now we have an open stream ... */
+ if( fstat(fileno(xcfstream),&statbuf) == 0 &&
+ (statbuf.st_mode & S_IFMT) == S_IFREG ) {
+ xcf_length = statbuf.st_size ;
+#if HAVE_MMAP
+ xcf_file = mmap(0,xcf_length,PROT_READ,MAP_SHARED,fileno(xcfstream),0);
+ if( xcf_file != (void*)-1 )
+ return ;
+ if( errno != ENODEV ) {
+ int saved = errno ;
+ fclose(xcfstream) ;
+ xcf_file = 0 ;
+ errno = saved ;
+ FatalUnexpected("!Could not mmap input");
+ }
+#endif
+ xcf_file = malloc(xcf_length);
+ if( xcf_file == 0 )
+ FatalUnexpected(_("Out of memory for xcf data"));
+ if( fread(xcf_file,1,xcf_length,xcfstream) != xcf_length ) {
+ if( feof(xcfstream) )
+ FatalUnexpected(_("XCF file shrunk while reading it"));
+ else
+ FatalUnexpected(_("!Could not read xcf data"));
+ }
+ fclose(xcfstream) ;
+ xcfstream = 0 ;
+ } else {
+ size_t blocksize = 0x80000 ; /* 512 KB */
+ xcf_length = 0 ;
+ xcf_file = 0 ;
+ while(1) {
+ xcf_file = realloc(xcf_file,blocksize) ;
+ if( xcf_file == 0 )
+ FatalUnexpected(_("Out of memory for xcf data"));
+ size_t actual = fread(xcf_file+xcf_length,1,blocksize-xcf_length,
+ xcfstream) ;
+ xcf_length += actual ;
+ if( feof(xcfstream) )
+ break ;
+ if( xcf_length < blocksize ) {
+ FatalUnexpected(_("!Could not read xcf data")) ;
+ }
+ blocksize += (blocksize >> 1) & ~(size_t)0x3FFF ; /* 16 KB granularity */
+ }
+ fclose(xcfstream) ;
+ xcfstream = 0 ;
+ }
+}
diff --git a/kernel/kls_xcf/xcf2pnm/options.i b/kernel/kls_xcf/xcf2pnm/options.i
new file mode 100644
index 0000000..f891767
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/options.i
@@ -0,0 +1,410 @@
+/* Option processing for xcftools -*- C -*-
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+OPTIONGROUP(1i,General options);
+
+OPTION('h',--help,show this message,
+ (Print an option summery to standard output and exit with a
+ return code of 0.
+ ));
+exit(0);
+
+OPTION('V',--version,show version,
+ (Print the version numer of
+ .B xcftools
+ to standard output and exit with a return code of 0.
+ ));
+printf(OPTI_TARGET " - " PACKAGE_STRING "\n");
+exit(0);
+
+OPTION('v',--verbose,show progress messages,
+ (Print progress messages about the conversion to standard error.
+ ));
+verboseFlag = 1 ;
+break ;
+
+OPTION('j',--bzip,input is bzip2 compressed,
+ (Equivalent to
+ .BR "\-Z bzcat" .
+ Default if the filename ends with
+ .BR bz2 .
+ ));
+unzipper = "bzcat" ;
+break ;
+
+OPTION('z',--gzip,input is gzip compressed,
+ (Equivalent to
+ .BR "\-Z zcat" .
+ Default if the filename ends with
+ .BR gz .
+ ));
+unzipper = "zcat" ;
+break ;
+
+OPTION('Z',--unpack,(command) use 'command' to decompress input,
+ (Specify a command that the input file is filtered through
+ before being interpreted as an XCF file. The command is invoked as
+ .I command filename
+ and must produce output to its standard output.
+ Note that it is not possible to specify arguments as part of
+ .IR command .
+ An uncompressor is selected automatically if the filename ends
+ with
+ .B gz
+ or
+ .BR bz2 ;
+ to suppress this, use
+ .B \-Z cat
+ (which is implemented without actually starting a
+ .BR cat (1)
+ process).
+ ));
+unzipper = optarg ;
+break ;
+
+#ifdef XCF2FOO
+
+OPTION('o',--output,(filename) name output file,
+ (Write the converted picture to
+ .I filename
+ instead of to standard output.
+ ));
+flatspec.output_filename = optarg ;
+break ;
+
+#ifdef XCF2PNM
+OPTION('a',--alpha,(filename) write transparency map,
+ (Output a transparency mask for the flattened image to
+ .I filename
+ as a
+ .BR pgm (5)
+ file, in addition to the ordinary output.
+ If the flattened image is completely opaque, this will produce an
+ error message and exit status 101;
+ use
+ .B \-A
+ to suppress this.
+ ));
+flatspec.transmap_filename = optarg ;
+break ;
+#endif
+
+OPTION('b',--background,(color) select background color,
+ (Use this color for transparent pixels in the image.
+ The color can be given as
+ .B #rrggbb
+ or
+ .B #rgb
+ hexadecimal values,
+ or as an X11 color name
+ (which will only work if a color name database can be found
+ in one of a number of standard locations).
+ ));
+{
+ unsigned r,g,b ;
+ unsigned long hex ;
+ int met = 0 ;
+ if( *optarg == '#' )
+ sscanf(optarg+1,"%lx%n",&hex,&met);
+ if( met == 3 && strlen(optarg) == 4 ) {
+ r = ((hex >> 8) & 0xF) * 0x11 ;
+ g = ((hex >> 4) & 0xF) * 0x11 ;
+ b = ((hex >> 0) & 0xF) * 0x11 ;
+ } else if( met == 6 && strlen(optarg) == 7 ) {
+ r = ((hex >> 16) & 0xFF) ;
+ g = ((hex >> 8) & 0xFF) ;
+ b = ((hex >> 0) & 0xFF) ;
+ } else if( strcasecmp(optarg,"black") == 0 )
+ r = g = b = 0 ;
+ else if( strcasecmp(optarg,"white") == 0 )
+ r = g = b = 255 ;
+ else {
+ const char *filenames[] = { "/etc/X11/rgb.txt",
+ "/usr/lib/X11/rgb.txt",
+ "/usr/share/X11/rgb.txt",
+ NULL };
+ const char **fnp ;
+ r = (unsigned)-1 ;
+ int any = 0 ;
+ for( fnp = filenames; r == (unsigned)-1 && fnp && *fnp; fnp++ ) {
+ FILE *colortable = fopen(*fnp,"rt");
+ if( colortable ) {
+ any = 1 ;
+ int clen ;
+ char colorbuf[80] ;
+ do {
+ if( !fgets(colorbuf,sizeof colorbuf,colortable) ) {
+ r = (unsigned)-1 ;
+ break ;
+ }
+ clen = strlen(colorbuf);
+ while( clen && isspace(colorbuf[clen-1]) )
+ clen-- ;
+ colorbuf[clen] = '\0' ;
+ clen = 0 ;
+ sscanf(colorbuf," %u %u %u %n",&r,&g,&b,&clen);
+ } while( clen == 0 || strcasecmp(colorbuf+clen,optarg) != 0 );
+ fclose(colortable) ;
+ }
+ }
+ if( !any ) {
+ fprintf(stderr,_("Could not find X11 color database\n"));
+ }
+ }
+ if( r == (unsigned)-1 )
+ FatalGeneric(20,_("Unknown background color '%s'"),optarg);
+ flatspec.default_pixel = ((rgba)255 << ALPHA_SHIFT)
+ + ((rgba)r << RED_SHIFT)
+ + ((rgba)g << GREEN_SHIFT)
+ + ((rgba)b << BLUE_SHIFT);
+ break ;
+}
+
+OPTION('A',--force-alpha,force alpha channel in output,
+ (Invent a trivial alpha channel even if the flattened image is
+ completely opaque.
+ ));
+flatspec.default_pixel = FORCE_ALPHA_CHANNEL ;
+break ;
+
+OPTION('c',--color --colour,select color output,
+ (Force the output to use RGB color space even if it there are
+ more compact alternatives.
+#ifdef XCF2PNM
+ This will be selected automatically if the output file''s name
+ ends with
+ .BR .ppm .
+#endif
+ ));
+flatspec.out_color_mode = COLOR_RGB ;
+break ;
+
+OPTION('g',--gray --grey,select grayscale output,
+ (Force the output to be a grayscale image even if it may be monochrome.
+ If any colored pixels are encountered, exit with status 103.
+ This will be selected automatically if the output file''s name
+ ends with
+ .BR .pgm .
+ ));
+flatspec.out_color_mode = COLOR_GRAY ;
+break ;
+
+#ifdef XCF2PNM
+OPTION('m',--mono,select monochrome output,
+ (Force the output to be a monochrome image.
+ If any colors except black and white are encountered, exit with
+ status 103.
+ This will be selected automatically if the output file''s name
+ ends with
+ .BR .pbm .
+ ));
+flatspec.out_color_mode = COLOR_MONO ;
+break ;
+#endif
+
+#ifdef XCF2PNM
+OPTION('n',--pnm,select -c/-g/-m by image contents,
+ (Suppress the automatic choice of
+ .BR \-c ,
+ .BR \-g ,
+ or
+ .BR \-m
+ based on output filename, and instead select the output format
+ based on image contents.
+ This is the default if the filename is not recognized, and
+ when writing to stdout.
+ ));
+flatspec.out_color_mode = COLOR_BY_CONTENTS ;
+break ;
+#endif
+
+OPTION('T',--truecolor,treat indexed images as RGB for flattening,
+ (Use standard RGB compositing for flattening indexed layers.
+ Without this option,
+ .B \*p
+ will mimic the Gimp''s current strategy of rounding each
+ alpha value to either full transparency or full opacity,
+ and interpret all layer modes as
+ .BR Normal .
+ ));
+flatspec.gimpish_indexed = 0 ;
+break ;
+
+OPTION('G',--for-gif,disallow partial transparency,
+ (Assert that the flattened image will have no partial transparency
+ (allowing a more compact representation of the alpha output).
+ Exit with status 102 if the flattened image has any partial
+ transparency.
+ If
+ .B \-b
+ is also given, this tests whether there there is partial
+ transparency before applying the background color.
+ ));
+flatspec.partial_transparency_mode = FORBID_PARTIAL_TRANSPARENCY ;
+break ;
+
+OPTION('D',--dissolve,dissolve partial transparency,
+ (Do a "dissolve" step to eliminate partial transparency after
+ flattening.
+ If
+ .B \-b
+ is also given, this happens before the background color is applied.
+ ));
+flatspec.partial_transparency_mode = DISSOLVE_PARTIAL_TRANSPARENCY ;
+break ;
+
+OPTION('f',--full-image,flatten to memory; then analyse,
+ (First flatten the entire image to a memory buffer before writing
+ output. Then analyse the image to decide on the details of the
+ output format (e.g., whether a grayscale output is sufficient).
+ Without this option, the program flattens only a singe row of "tiles"
+ (height 64) at a time.
+ ));
+flatspec.process_in_memory = 1 ;
+break ;
+
+OPTION('S',--size,(w"x"h) crop image while converting,
+ (Crop the converted image to width \fIw\fP and height \fIh\fP.
+ ));
+{
+ unsigned w,h ;
+ int n = 0 ;
+ sscanf(optarg,"%ux%u%n",&w,&h,&n) ;
+ if( n && n == strlen(optarg) ) {
+ if( flatspec.window_mode == AUTOCROP ) flatspec.window_mode = USE_CANVAS ;
+ flatspec.window_mode |= MANUAL_CROP ;
+ flatspec.dim.width = w ;
+ flatspec.dim.height = h ;
+ } else
+ FatalGeneric(20,_("-S option must have an argument of the form wxh"));
+ break ;
+}
+
+OPTION('O',--offset,(x","y) translate converted part of image,
+ (Offset the converted part of the image from the top-left corner
+ of the XCF canvas. Usually used with
+ .BR \-S .
+ ));
+{
+ int x,y ;
+ int n = 0 ;
+ sscanf(optarg,"%d,%d%n",&x,&y,&n) ;
+ if( n && n == strlen(optarg) ) {
+ if( flatspec.window_mode == AUTOCROP ) flatspec.window_mode = USE_CANVAS ;
+ flatspec.window_mode |= MANUAL_OFFSET ;
+ flatspec.dim.c.l = x ;
+ flatspec.dim.c.t = y ;
+ } else
+ FatalGeneric(20,_("-O option must have an argument of the form x,y"));
+ break ;
+}
+
+OPTION('C',--autocrop,autocrop to visible layer boundaries,
+ (Crop and offset the converted part of the image to just include
+ the boundaries of the visible (or selected) layers.
+ (Note that the
+ .I contents
+ of the layers is not taken into account when autocropping).
+ .IP
+ In the absence of options that specify otherwise, the converted
+ image will cover the entire XCF canvas.
+ ));
+flatspec.window_mode = AUTOCROP ;
+break ;
+
+#ifndef XCFVIEW
+OPTIONGROUP(1il,Layer-selection options);
+#endif
+
+OPTION(300,--mode,(mode) set layer mode,
+ (Set the layer mode (e.g.,
+ .B Normal
+ or
+ .BR Multiply ).
+ ));
+{
+ GimpLayerModeEffects m ;
+ #ifdef ENABLE_NLS
+ for( m = 0; m < GimpLayerModeEffects_LAST; m++ )
+ if( strcmp(optarg,_(showGimpLayerModeEffects(m))) == 0 )
+ goto found_localized ;
+ #endif
+
+ for( m = 0; strcmp(optarg,showGimpLayerModeEffects(m)) != 0 ; m++ ) {
+ if( m > GimpLayerModeEffects_LAST )
+ FatalGeneric(20,_("Layer mode '%s' is unknown"),optarg);
+ }
+ found_localized:
+ lastlayerspec(&flatspec,"--mode")->mode = m ;
+ break ;
+}
+
+OPTION(301,--percent,(n) set opacity in percent,
+ (Set the opacity on a scale from 0 to 100
+ (as in the Gimp user interface).
+ ));
+{
+ unsigned pct ;
+ int n ;
+ sscanf(optarg,"%u%n",&pct,&n) ;
+ if( n != strlen(optarg) || pct > 100 )
+ FatalGeneric(20,_("The argument to --percent is not a percentage"));
+ lastlayerspec(&flatspec,"--percent")->opacity = pct * 255 / 100 ;
+ break ;
+}
+
+OPTION(302,--opacity,(n) set opacity in 1/255 units,
+ (Set the opacity on a scale from 0 to 255 (as used internally)
+ ));
+{
+ unsigned alpha ;
+ int n ;
+ sscanf(optarg,"%u%n",&alpha,&n) ;
+ if( n != strlen(optarg) || alpha > 255 )
+ FatalGeneric(20,_("The argument to --opacity is not a number "
+ "between 0 and 255"));
+ lastlayerspec(&flatspec,"--percent")->opacity = alpha ;
+ break ;
+}
+
+OPTION(303,--mask,enable layer mask,
+ (Enable the layer mask.
+ ));
+lastlayerspec(&flatspec,"--mask")->hasMask = 1 ;
+break ;
+
+OPTION(304,--nomask,disable layer mask,
+ (Disable the layer mask.
+ ));
+lastlayerspec(&flatspec,"--nomask")->hasMask = 0 ;
+break ;
+
+#endif /* XCF2FOO */
+
+OPTIONGROUP(1i,)
+
+#if HAVE_ICONV
+OPTION('u',--utf8,use UTF-8 for layer names,
+ (Use the raw UTF-8 representation from the XCF file to compare
+ and display layer names.
+ Ordinarily, layer names will be converted to the character set
+ of the current locale.
+ ));
+use_utf8 = 1 ;
+break ;
+#endif
diff --git a/kernel/kls_xcf/xcf2pnm/pixels.c b/kernel/kls_xcf/xcf2pnm/pixels.c
new file mode 100644
index 0000000..65891f9
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/pixels.c
@@ -0,0 +1,487 @@
+/* Pixel and tile functions for xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define DEBUG
+#include "xcftools.h"
+#include "pixels.h"
+#include <assert.h>
+#include <string.h>
+
+rgba colormap[256] ;
+unsigned colormapLength=0 ;
+
+int
+degrayPixel(rgba pixel)
+{
+ if( ((pixel >> RED_SHIFT) & 255) == ((pixel >> GREEN_SHIFT) & 255) &&
+ ((pixel >> RED_SHIFT) & 255) == ((pixel >> BLUE_SHIFT) & 255) )
+ return (pixel >> RED_SHIFT) & 255 ;
+ return -1 ;
+}
+
+/* ****************************************************************** */
+
+typedef const struct _convertParams {
+ int bpp ;
+ int shift[4] ;
+ uint32_t base_pixel ;
+ const rgba *lookup ;
+} convertParams ;
+#define RGB_SHIFT RED_SHIFT, GREEN_SHIFT, BLUE_SHIFT
+#define OPAQUE (255 << ALPHA_SHIFT)
+static convertParams convertRGB = { 3, {RGB_SHIFT}, OPAQUE, 0 };
+static convertParams convertRGBA = { 4, {RGB_SHIFT, ALPHA_SHIFT}, 0,0 };
+static convertParams convertGRAY = { 1, {-1}, OPAQUE, graytable };
+static convertParams convertGRAYA = { 2, {-1,ALPHA_SHIFT}, 0, graytable };
+static convertParams convertINDEXED = { 1, {-1}, OPAQUE, colormap };
+static convertParams convertINDEXEDA = { 2, {-1,ALPHA_SHIFT}, 0, colormap };
+
+static convertParams convertColormap = { 3, {RGB_SHIFT}, 0, 0 };
+static convertParams convertChannel = { 1, {ALPHA_SHIFT}, 0, 0 };
+
+/* ****************************************************************** */
+
+static inline int
+tileDirectoryOneLevel(struct tileDimensions *dim,uint32_t ptr)
+{
+ if( ptr == 0 )
+ return 0 ;
+ if( xcfL(ptr ) != dim->c.r - dim->c.l ||
+ xcfL(ptr+4) != dim->c.b - dim->c.t )
+ FatalBadXCF("Drawable size mismatch at %" PRIX32, ptr);
+ return ptr += 8 ;
+}
+
+static void
+initTileDirectory(struct tileDimensions *dim,struct xcfTiles *tiles,
+ const char *type)
+{
+ uint32_t ptr ;
+ uint32_t data ;
+
+ ptr = tiles->hierarchy ;
+ tiles->hierarchy = 0 ;
+ if( (ptr = tileDirectoryOneLevel(dim,ptr)) == 0 ) return ;
+ if( tiles->params == &convertChannel ) {
+ /* A layer mask is a channel.
+ * Skip a name and a property list.
+ */
+ xcfString(ptr,&ptr);
+ while( xcfNextprop(&ptr,&data) != PROP_END )
+ ;
+ ptr = xcfOffset(ptr,4*4);
+ if( (ptr = tileDirectoryOneLevel(dim,ptr)) == 0 ) return ;
+ }
+ /* The XCF format has a dummy "hierarchy" level which was
+ * once meant to mean something, but never happened. It contains
+ * the bpp value and a list of "level" pointers; but only the
+ * first level actually contains data.
+ */
+ data = xcfL(ptr) ;
+ if( xcfL(ptr) != tiles->params->bpp )
+ FatalBadXCF("%"PRIu32" bytes per pixel for %s drawable",xcfL(ptr),type);
+ ptr = xcfOffset(ptr+4,3*4) ;
+ if( (ptr = tileDirectoryOneLevel(dim,ptr)) == 0 ) return ;
+
+ xcfCheckspace(ptr,dim->ntiles*4+4,"Tile directory at %" PRIX32,ptr);
+ if( xcfL(ptr + dim->ntiles*4) != 0 )
+ FatalBadXCF("Wrong sized tile directory at %" PRIX32,ptr);
+#define REUSE_RAW_DATA tiles->tileptrs = (uint32_t*)(xcf_file + ptr)
+#if defined(WORDS_BIGENDIAN) && defined(CAN_DO_UNALIGNED_WORDS)
+ REUSE_RAW_DATA;
+#else
+# if defined(WORDS_BIGENDIAN)
+ if( (ptr&3) == 0 ) REUSE_RAW_DATA; else
+# endif
+ {
+ unsigned i ;
+ tiles->tileptrs = xcfmalloc(dim->ntiles * sizeof(uint32_t)) ;
+ for( i = 0 ; i < dim->ntiles ; i++ )
+ tiles->tileptrs[i] = xcfL(ptr+i*4);
+ }
+#endif
+}
+
+void
+initLayer(struct xcfLayer *layer) {
+ if( layer->dim.ntiles == 0 ||
+ (layer->pixels.hierarchy == 0 && layer->mask.hierarchy == 0) )
+ return ;
+ switch(layer->type) {
+#define DEF(X) case GIMP_##X##_IMAGE: layer->pixels.params = &convert##X; break
+ DEF(RGB);
+ DEF(RGBA);
+ DEF(GRAY);
+ DEF(GRAYA);
+ DEF(INDEXED);
+ DEF(INDEXEDA);
+ default:
+ FatalUnsupportedXCF(_("Layer type %s"),_(showGimpImageType(layer->type)));
+ }
+ initTileDirectory(&layer->dim,&layer->pixels,
+ _(showGimpImageType(layer->type)));
+ layer->mask.params = &convertChannel ;
+ initTileDirectory(&layer->dim,&layer->mask,"layer mask");
+}
+static void copyStraightPixels(rgba *dest,unsigned npixels,
+ uint32_t ptr,convertParams *params);
+void
+initColormap(void) {
+ uint32_t ncolors ;
+ if( XCF.colormapptr == 0 ) {
+ colormapLength = 0 ;
+ return ;
+ }
+ ncolors = xcfL(XCF.colormapptr) ;
+ if( ncolors > 256 )
+ FatalUnsupportedXCF(_("Color map has more than 256 entries"));
+ copyStraightPixels(colormap,ncolors,XCF.colormapptr+4,&convertColormap);
+ colormapLength = ncolors ;
+#ifdef xDEBUG
+ {
+ unsigned j ;
+ fprintf(stderr,"Colormap decoding OK\n");
+ for( j = 0 ; j < ncolors ; j++ ) {
+ if( j % 8 == 0 ) fprintf(stderr,"\n");
+ fprintf(stderr," %08x",colormap[j]);
+ }
+ fprintf(stderr,"\n");
+ }
+#endif
+}
+
+/* ****************************************************************** */
+
+struct Tile *
+newTile(struct rect r)
+{
+ unsigned npixels = (unsigned)(r.b-r.t) * (unsigned)(r.r-r.l) ;
+ struct Tile *data
+ = xcfmalloc(sizeof(struct Tile) -
+ sizeof(rgba)*(TILE_HEIGHT*TILE_WIDTH - npixels)) ;
+ data->count = npixels ;
+ data->refcount = 1 ;
+ data->summary = 0 ;
+ return data ;
+}
+
+struct Tile *
+forkTile(struct Tile* tile)
+{
+ if( ++tile->refcount <= 0 )
+ FatalUnsupportedXCF(_("Unbelievably many layers?\n"
+ "More likely to be a bug in %s"),progname);
+ return tile ;
+}
+
+void
+freeTile(struct Tile* tile)
+{
+ if( --tile->refcount == 0 )
+ xcffree(tile) ;
+}
+
+summary_t
+tileSummary(struct Tile *tile)
+{
+ unsigned i ;
+ summary_t summary ;
+ if( (tile->summary & TILESUMMARY_UPTODATE) != 0 )
+ return tile->summary ;
+ summary = TILESUMMARY_ALLNULL + TILESUMMARY_ALLFULL + TILESUMMARY_CRISP ;
+ for( i=0; summary && i<tile->count; i++ ) {
+ if( FULLALPHA(tile->pixels[i]) )
+ summary &= ~TILESUMMARY_ALLNULL ;
+ else if( NULLALPHA(tile->pixels[i]) )
+ summary &= ~TILESUMMARY_ALLFULL ;
+ else
+ summary = 0 ;
+ }
+ summary += TILESUMMARY_UPTODATE ;
+ tile->summary = summary ;
+ return summary ;
+}
+
+void
+fillTile(struct Tile *tile,rgba data)
+{
+ unsigned i ;
+ for( i = 0 ; i < tile->count ; i++ )
+ tile->pixels[i] = data ;
+ if( FULLALPHA(data) )
+ tile->summary = TILESUMMARY_UPTODATE+TILESUMMARY_ALLFULL+TILESUMMARY_CRISP;
+ else if (NULLALPHA(data) )
+ tile->summary = TILESUMMARY_UPTODATE+TILESUMMARY_ALLNULL+TILESUMMARY_CRISP;
+ else
+ tile->summary = TILESUMMARY_UPTODATE ;
+}
+
+/* ****************************************************************** */
+
+static void
+copyStraightPixels(rgba *dest,unsigned npixels,
+ uint32_t ptr,convertParams *params)
+{
+ unsigned bpp = params->bpp;
+ const rgba *lookup = params->lookup;
+ rgba base_pixel = params->base_pixel ;
+ uint8_t *bp = xcf_file + ptr ;
+ xcfCheckspace(ptr,bpp*npixels,
+ "pixel array (%u x %d bpp) at %"PRIX32,npixels,bpp,ptr);
+ while( npixels-- ) {
+ rgba pixel = base_pixel ;
+ unsigned i ;
+ for( i = 0 ; i < bpp ; i++ ) {
+ if( params->shift[i] < 0 ) {
+ pixel += lookup[*bp++] ;
+ } else {
+ pixel += *bp++ << params->shift[i] ;
+ }
+ }
+ *dest++ = pixel ;
+ }
+}
+
+static inline void
+copyRLEpixels(rgba *dest,unsigned npixels,uint32_t ptr,convertParams *params)
+{
+ unsigned i,j ;
+ rgba base_pixel = params->base_pixel ;
+
+#ifdef xDEBUG
+ fprintf(stderr,"RLE stream at %x, want %u x %u pixels, base %x\n",
+ ptr,params->bpp,npixels,base_pixel);
+#endif
+
+
+ /* This algorithm depends on the indexed byte always being the first one */
+ if( params->shift[0] < -1 )
+ base_pixel = 0 ;
+ for( j = npixels ; j-- ; )
+ dest[j] = base_pixel ;
+
+ for( i = 0 ; i < params->bpp ; i++ ) {
+ int shift = params->shift[i] ;
+ if( shift < 0 )
+ shift = 0 ;
+ for( j = 0 ; j < npixels ; ) {
+ int countspec ;
+ unsigned count ;
+ xcfCheckspace(ptr,2,"RLE data stream");
+ countspec = (int8_t) xcf_file[ptr++] ;
+ count = countspec >= 0 ? countspec+1 : -countspec ;
+ if( count == 128 ) {
+ xcfCheckspace(ptr,3,"RLE long count");
+ count = xcf_file[ptr++] << 8 ;
+ count += xcf_file[ptr++] ;
+ }
+ if( j + count > npixels )
+ FatalBadXCF("Overlong RLE run at %"PRIX32" (plane %u, %u left)",
+ ptr,i,npixels-j);
+ if( countspec >= 0 ) {
+ rgba data = (uint32_t) xcf_file[ptr++] << shift ;
+ while( count-- )
+ dest[j++] += data ;
+ } else {
+ while( count-- )
+ dest[j++] += (uint32_t) xcf_file[ptr++] << shift ;
+ }
+ }
+ if( i == 0 && params->shift[0] < 0 ) {
+ const rgba *lookup = params->lookup ;
+ base_pixel = params->base_pixel ;
+ for( j = npixels ; j-- ; ) {
+ dest[j] = lookup[dest[j]-base_pixel] + base_pixel ;
+ }
+ }
+ }
+#ifdef xDEBUG
+ fprintf(stderr,"RLE decoding OK at %"PRIX32"\n",ptr);
+ /*
+ for( j = 0 ; j < npixels ; j++ ) {
+ if( j % 8 == 0 ) fprintf(stderr,"\n");
+ fprintf(stderr," %8x",dest[j]);
+ }
+ fprintf(stderr,"\n");
+ */
+#endif
+}
+
+static inline void
+copyTilePixels(struct Tile *dest, uint32_t ptr,convertParams *params)
+{
+ if( FULLALPHA(params->base_pixel) )
+ dest->summary = TILESUMMARY_UPTODATE+TILESUMMARY_ALLFULL+TILESUMMARY_CRISP;
+ else
+ dest->summary = 0 ;
+ switch( XCF.compression ) {
+ case COMPRESS_NONE:
+ copyStraightPixels(dest->pixels,dest->count,ptr,params);
+ break ;
+ case COMPRESS_RLE:
+ copyRLEpixels(dest->pixels,dest->count,ptr,params);
+ break ;
+ default:
+ FatalUnsupportedXCF(_("%s compression"),
+ _(showXcfCompressionType(XCF.compression)));
+ }
+}
+
+static struct Tile *
+getMaskOrLayerTile(struct tileDimensions *dim, struct xcfTiles *tiles,
+ struct rect want)
+{
+ struct Tile *tile = newTile(want);
+
+ assert( want.l < want.r && want.t < want.b );
+ if( tiles->tileptrs == 0 ) {
+ fillTile(tile,0);
+ return tile ;
+ }
+
+#ifdef xDEBUG
+ fprintf(stderr,"getMaskOrLayer: (%d-%d),(%d-%d)\n",left,right,top,bottom);
+#endif
+
+ if( isSubrect(want,dim->c) &&
+ (want.l - dim->c.l) % TILE_WIDTH == 0 &&
+ (want.t - dim->c.t) % TILE_HEIGHT == 0 ) {
+ unsigned tx = (want.l - dim->c.l) / TILE_WIDTH ;
+ unsigned ty = (want.t - dim->c.t) / TILE_WIDTH ;
+ if( want.r == TILEXn(*dim,tx+1) && want.b == TILEYn(*dim,ty+1) ) {
+ /* The common case? An entire single tile from the layer */
+ copyTilePixels(tile,tiles->tileptrs[tx + ty*dim->tilesx],tiles->params);
+ return tile ;
+ }
+ }
+
+ /* OK, we must construct the wanted tile as a jigsaw */
+ {
+ unsigned width = want.r-want.l ;
+ rgba *pixvert = tile->pixels ;
+ rgba *pixhoriz ;
+ unsigned y, ty, l0, l1, lstart, lnum ;
+ unsigned x, tx, c0, c1, cstart, cnum ;
+
+ if( !isSubrect(want,dim->c) ) {
+ if( want.l < dim->c.l ) pixvert += (dim->c.l - want.l),
+ want.l = dim->c.l ;
+ if( want.r > dim->c.r ) want.r = dim->c.r ;
+ if( want.t < dim->c.t ) pixvert += (dim->c.t - want.t) * width,
+ want.t = dim->c.t ;
+ if( want.b > dim->c.b ) want.b = dim->c.b ;
+ fillTile(tile,0);
+ } else {
+ tile->summary = -1 ; /* I.e. whatever the jigsaw pieces say */
+ }
+
+#ifdef xDEBUG
+ fprintf(stderr,"jig0 (%d-%d),(%d-%d)\n",left,right,top,bottom);
+#endif
+
+ for( y=want.t, ty=(want.t-dim->c.t)/TILE_HEIGHT, l0=TILEYn(*dim,ty);
+ y<want.b;
+ pixvert += lnum*width, ty++, y=l0=l1 ) {
+ l1 = TILEYn(*dim,ty+1) ;
+ lstart = y - l0 ;
+ lnum = (l1 > want.b ? want.b : l1) - y ;
+
+ pixhoriz = pixvert ;
+ for( x=want.l, tx=(want.l-dim->c.l)/TILE_WIDTH, c0=TILEXn(*dim,tx);
+ x<want.r;
+ pixhoriz += cnum, tx++, x=c0=c1 ) {
+ c1 = TILEXn(*dim,tx+1);
+ cstart = x - c0 ;
+ cnum = (c1 > want.r ? want.r : c1) - x ;
+
+ {
+ static struct Tile tmptile ;
+ unsigned dwidth = c1-c0 ;
+ unsigned i, j ;
+ tmptile.count = (c1-c0)*(l1-l0) ;
+#ifdef xDEBUG
+ fprintf(stderr,"jig ty=%u(%u-%u-%u)(%u+%u) tx=%u(%u-%u-%u)(%u+%u)\n",
+ ty,l0,y,l1,lstart,lnum,
+ tx,c0,x,c1,cstart,cnum);
+#endif
+ copyTilePixels(&tmptile,
+ tiles->tileptrs[tx+ty*dim->tilesx],tiles->params);
+ for(i=0; i<lnum; i++)
+ for(j=0; j<cnum; j++)
+ pixhoriz[i*width+j]
+ = tmptile.pixels[(i+lstart)*dwidth+(j+cstart)];
+ tile->summary &= tmptile.summary ;
+ }
+ }
+ }
+ }
+ return tile ;
+}
+
+void
+applyMask(struct Tile *tile, struct Tile *mask)
+{
+ unsigned i ;
+ assertTileCompatibility(tile,mask);
+ assert( tile->count == mask->count );
+ INIT_SCALETABLE_IF(1);
+ invalidateSummary(tile,0);
+ for( i=0; i < tile->count ;i++ )
+ tile->pixels[i] = NEWALPHA(tile->pixels[i],
+ scaletable[mask->pixels[i]>>ALPHA_SHIFT]
+ [ALPHA(tile->pixels[i])]);
+ freeTile(mask);
+}
+
+struct Tile *
+getLayerTile(struct xcfLayer *layer,const struct rect *where)
+{
+ struct Tile *data ;
+
+#ifdef xDEBUG
+ fprintf(stderr,"getLayerTile(%s): (%d-%d),(%d-%d)\n",
+ layer->name,where->l,where->r,where->t,where->b);
+#endif
+
+ if( disjointRects(*where,layer->dim.c) ||
+ layer->opacity == 0 ) {
+ data = newTile(*where);
+ fillTile(data,0);
+ return data ;
+ }
+
+ data = getMaskOrLayerTile(&layer->dim,&layer->pixels,*where);
+ if( (data->summary & TILESUMMARY_ALLNULL) != 0 )
+ return data ;
+ if( layer->hasMask ) {
+ struct Tile *mask = getMaskOrLayerTile(&layer->dim,&layer->mask,*where);
+ applyMask(data,mask);
+ }
+ if( layer->opacity < 255 ) {
+ const uint8_t *ourtable ;
+ int i ;
+ invalidateSummary(data,~(TILESUMMARY_CRISP | TILESUMMARY_ALLFULL));
+ INIT_SCALETABLE_IF(1);
+ ourtable = scaletable[layer->opacity] ;
+ for( i=0; i < data->count; i++ )
+ data->pixels[i]
+ = NEWALPHA(data->pixels[i],ourtable[ALPHA(data->pixels[i])]) ;
+ }
+ return data ;
+}
+
diff --git a/kernel/kls_xcf/xcf2pnm/pixels.h b/kernel/kls_xcf/xcf2pnm/pixels.h
new file mode 100644
index 0000000..1ee5219
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/pixels.h
@@ -0,0 +1,128 @@
+/* Pixel and tile functions for xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef PIXELS_H
+#define PIXELS_H
+
+#include "xcftools.h"
+
+/* MACROS FOR INTERNAL PIXEL ORDERING HERE */
+/*=========================================*/
+/* In principle the internal representation of pixels may change.
+ * - this was supposed to allow an optimization where a layer could
+ * be represented as a pointer into the mmapped xcf file, if
+ * alignment, bpp, and endianness agreed (the point was that the
+ * pixel representation had to agree with the endianness).
+ *
+ * However, it turns out that the current Gimp _always_ saves images
+ * with RLE encoding of tiles, so such an effort would be in vain.
+ *
+ * Just for modularity, nevertheless try to isolate knowledge of
+ * the RGBA-to-machine-word packing in this section of the
+ * header file. Define new macros if necessary.
+ *
+ * Given that we don't have to agree with the uncompressed
+ * RLE format, we choose to have the alpha in the _least_
+ * significant byte on all archs - it is tested and used more
+ * often than the visible channels.
+ */
+typedef uint32_t rgba ;
+
+#define ALPHA_SHIFT 0
+#define RED_SHIFT 8
+#define GREEN_SHIFT 16
+#define BLUE_SHIFT 24
+
+#define ALPHA(rgba) ((uint8_t)(rgba))
+#define FULLALPHA(rgba) ((uint8_t)(rgba) == 255)
+#define NULLALPHA(rgba) ((uint8_t)(rgba) == 0)
+#define NEWALPHA(rgb,a) (((rgba)(rgb) & 0xFFFFFF00) + (a))
+
+#ifdef PRECOMPUTED_SCALETABLE
+extern const uint8_t scaletable[256][256] ;
+#define INIT_SCALETABLE_IF(foo) ((void)0)
+#else
+extern uint8_t scaletable[256][256] ;
+extern int ok_scaletable ;
+void mk_scaletable(void);
+#define INIT_SCALETABLE_IF(foo) \
+ (ok_scaletable || !(foo) || (mk_scaletable(),0) )
+#endif
+
+extern const rgba graytable[256] ;
+extern rgba colormap[256] ;
+extern unsigned colormapLength ;
+void initLayer(struct xcfLayer *);
+void initColormap();
+
+int degrayPixel(rgba); /* returns -1 for non-gray pixels */
+
+/* ******************************************************* */
+
+#define TILEXn(dim,tx) \
+ ((tx)==(dim).tilesx ? (dim).c.r : (dim).c.l + ((tx)*TILE_WIDTH))
+#define TILEYn(dim,ty) \
+ ((ty)==(dim).tilesy ? (dim).c.b : (dim).c.t + ((ty)*TILE_HEIGHT))
+
+#if __i386__
+/* This is probably the only common architecture where small constants
+ * are more efficient for byte operations.
+ */
+typedef int8_t summary_t ;
+typedef short int refcount_t ;
+#else
+typedef int summary_t ;
+typedef int refcount_t ;
+#endif
+
+#define TILESUMMARY_UPTODATE 8
+#define TILESUMMARY_ALLNULL 4
+#define TILESUMMARY_ALLFULL 2
+#define TILESUMMARY_CRISP 1 /* everyting either null or full */
+struct Tile {
+ refcount_t refcount ;
+ summary_t summary ; /* a combination of TIMESUMMARY_FOO constatns */
+ unsigned count ;
+ rgba pixels[TILE_WIDTH * TILE_HEIGHT];
+};
+/* Actually, the Tile structures that get allocated many not have
+ * room for that many pixels. We subtract the space for those we don't
+ * use - which is Not Legal C, but ought to be portable.
+ * OTOH, one can also use a static struct Tile for temporary storage.
+ */
+
+
+#define assertTileCompatibility(t1,t2) assert((t1)->count==(t2)->count)
+
+struct Tile *newTile(struct rect);
+struct Tile *forkTile(struct Tile*);
+void freeTile(struct Tile*);
+#define invalidateSummary(tile,mask) \
+ do{ assert((tile)->refcount==1); (tile)->summary &= mask; } while(0)
+summary_t __ATTRIBUTE__((pure)) tileSummary(struct Tile *);
+
+void fillTile(struct Tile*,rgba);
+
+/* applyMask() destructively changes tile,
+ * applyMask() gets ownership of mask
+ */
+void applyMask(struct Tile *tile, struct Tile *mask);
+
+struct Tile *getLayerTile(struct xcfLayer *,const struct rect *);
+
+#endif /* FLATTEN_H */
diff --git a/kernel/kls_xcf/xcf2pnm/scaletab.c b/kernel/kls_xcf/xcf2pnm/scaletab.c
new file mode 100644
index 0000000..c09867e
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/scaletab.c
@@ -0,0 +1,42 @@
+/* Run-time scaletable computation for Xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "pixels.h"
+#ifndef PRECOMPUTED_SCALETABLE
+
+uint8_t scaletable[256][256] ;
+int ok_scaletable = 0 ;
+
+void
+mk_scaletable(void)
+{
+ unsigned p, q, r ;
+ if( ok_scaletable ) return ;
+ for( p = 0 ; p < 128 ; p++ )
+ for( q = 0 ; q <= p ; q++ ) {
+ r = (p*q+127)/255 ;
+ scaletable[p][q] = scaletable[q][p] = r ;
+ scaletable[255-p][q] = scaletable[q][255-p] = q-r ;
+ scaletable[p][255-q] = scaletable[255-q][p] = p-r ;
+ scaletable[255-p][255-q] = scaletable[255-q][255-p] = (255-q)-(p-r) ;
+ }
+ ok_scaletable = 1 ;
+}
+
+#endif
+
diff --git a/kernel/kls_xcf/xcf2pnm/table.c b/kernel/kls_xcf/xcf2pnm/table.c
new file mode 100644
index 0000000..9e76923
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/table.c
@@ -0,0 +1,263 @@
+/* Autogenerated by mktablec.pl */
+#include "pixels.h"
+#ifdef PRECOMPUTED_SCALETABLE
+#error PRECOMPUTED_SCALETABLE was not defined at generation time
+#endif
+const rgba graytable[256] = {
+ (rgba)0 << RED_SHIFT | (rgba)0 << GREEN_SHIFT | (rgba)0 << BLUE_SHIFT,
+ (rgba)1 << RED_SHIFT | (rgba)1 << GREEN_SHIFT | (rgba)1 << BLUE_SHIFT,
+ (rgba)2 << RED_SHIFT | (rgba)2 << GREEN_SHIFT | (rgba)2 << BLUE_SHIFT,
+ (rgba)3 << RED_SHIFT | (rgba)3 << GREEN_SHIFT | (rgba)3 << BLUE_SHIFT,
+ (rgba)4 << RED_SHIFT | (rgba)4 << GREEN_SHIFT | (rgba)4 << BLUE_SHIFT,
+ (rgba)5 << RED_SHIFT | (rgba)5 << GREEN_SHIFT | (rgba)5 << BLUE_SHIFT,
+ (rgba)6 << RED_SHIFT | (rgba)6 << GREEN_SHIFT | (rgba)6 << BLUE_SHIFT,
+ (rgba)7 << RED_SHIFT | (rgba)7 << GREEN_SHIFT | (rgba)7 << BLUE_SHIFT,
+ (rgba)8 << RED_SHIFT | (rgba)8 << GREEN_SHIFT | (rgba)8 << BLUE_SHIFT,
+ (rgba)9 << RED_SHIFT | (rgba)9 << GREEN_SHIFT | (rgba)9 << BLUE_SHIFT,
+ (rgba)10 << RED_SHIFT | (rgba)10 << GREEN_SHIFT | (rgba)10 << BLUE_SHIFT,
+ (rgba)11 << RED_SHIFT | (rgba)11 << GREEN_SHIFT | (rgba)11 << BLUE_SHIFT,
+ (rgba)12 << RED_SHIFT | (rgba)12 << GREEN_SHIFT | (rgba)12 << BLUE_SHIFT,
+ (rgba)13 << RED_SHIFT | (rgba)13 << GREEN_SHIFT | (rgba)13 << BLUE_SHIFT,
+ (rgba)14 << RED_SHIFT | (rgba)14 << GREEN_SHIFT | (rgba)14 << BLUE_SHIFT,
+ (rgba)15 << RED_SHIFT | (rgba)15 << GREEN_SHIFT | (rgba)15 << BLUE_SHIFT,
+ (rgba)16 << RED_SHIFT | (rgba)16 << GREEN_SHIFT | (rgba)16 << BLUE_SHIFT,
+ (rgba)17 << RED_SHIFT | (rgba)17 << GREEN_SHIFT | (rgba)17 << BLUE_SHIFT,
+ (rgba)18 << RED_SHIFT | (rgba)18 << GREEN_SHIFT | (rgba)18 << BLUE_SHIFT,
+ (rgba)19 << RED_SHIFT | (rgba)19 << GREEN_SHIFT | (rgba)19 << BLUE_SHIFT,
+ (rgba)20 << RED_SHIFT | (rgba)20 << GREEN_SHIFT | (rgba)20 << BLUE_SHIFT,
+ (rgba)21 << RED_SHIFT | (rgba)21 << GREEN_SHIFT | (rgba)21 << BLUE_SHIFT,
+ (rgba)22 << RED_SHIFT | (rgba)22 << GREEN_SHIFT | (rgba)22 << BLUE_SHIFT,
+ (rgba)23 << RED_SHIFT | (rgba)23 << GREEN_SHIFT | (rgba)23 << BLUE_SHIFT,
+ (rgba)24 << RED_SHIFT | (rgba)24 << GREEN_SHIFT | (rgba)24 << BLUE_SHIFT,
+ (rgba)25 << RED_SHIFT | (rgba)25 << GREEN_SHIFT | (rgba)25 << BLUE_SHIFT,
+ (rgba)26 << RED_SHIFT | (rgba)26 << GREEN_SHIFT | (rgba)26 << BLUE_SHIFT,
+ (rgba)27 << RED_SHIFT | (rgba)27 << GREEN_SHIFT | (rgba)27 << BLUE_SHIFT,
+ (rgba)28 << RED_SHIFT | (rgba)28 << GREEN_SHIFT | (rgba)28 << BLUE_SHIFT,
+ (rgba)29 << RED_SHIFT | (rgba)29 << GREEN_SHIFT | (rgba)29 << BLUE_SHIFT,
+ (rgba)30 << RED_SHIFT | (rgba)30 << GREEN_SHIFT | (rgba)30 << BLUE_SHIFT,
+ (rgba)31 << RED_SHIFT | (rgba)31 << GREEN_SHIFT | (rgba)31 << BLUE_SHIFT,
+ (rgba)32 << RED_SHIFT | (rgba)32 << GREEN_SHIFT | (rgba)32 << BLUE_SHIFT,
+ (rgba)33 << RED_SHIFT | (rgba)33 << GREEN_SHIFT | (rgba)33 << BLUE_SHIFT,
+ (rgba)34 << RED_SHIFT | (rgba)34 << GREEN_SHIFT | (rgba)34 << BLUE_SHIFT,
+ (rgba)35 << RED_SHIFT | (rgba)35 << GREEN_SHIFT | (rgba)35 << BLUE_SHIFT,
+ (rgba)36 << RED_SHIFT | (rgba)36 << GREEN_SHIFT | (rgba)36 << BLUE_SHIFT,
+ (rgba)37 << RED_SHIFT | (rgba)37 << GREEN_SHIFT | (rgba)37 << BLUE_SHIFT,
+ (rgba)38 << RED_SHIFT | (rgba)38 << GREEN_SHIFT | (rgba)38 << BLUE_SHIFT,
+ (rgba)39 << RED_SHIFT | (rgba)39 << GREEN_SHIFT | (rgba)39 << BLUE_SHIFT,
+ (rgba)40 << RED_SHIFT | (rgba)40 << GREEN_SHIFT | (rgba)40 << BLUE_SHIFT,
+ (rgba)41 << RED_SHIFT | (rgba)41 << GREEN_SHIFT | (rgba)41 << BLUE_SHIFT,
+ (rgba)42 << RED_SHIFT | (rgba)42 << GREEN_SHIFT | (rgba)42 << BLUE_SHIFT,
+ (rgba)43 << RED_SHIFT | (rgba)43 << GREEN_SHIFT | (rgba)43 << BLUE_SHIFT,
+ (rgba)44 << RED_SHIFT | (rgba)44 << GREEN_SHIFT | (rgba)44 << BLUE_SHIFT,
+ (rgba)45 << RED_SHIFT | (rgba)45 << GREEN_SHIFT | (rgba)45 << BLUE_SHIFT,
+ (rgba)46 << RED_SHIFT | (rgba)46 << GREEN_SHIFT | (rgba)46 << BLUE_SHIFT,
+ (rgba)47 << RED_SHIFT | (rgba)47 << GREEN_SHIFT | (rgba)47 << BLUE_SHIFT,
+ (rgba)48 << RED_SHIFT | (rgba)48 << GREEN_SHIFT | (rgba)48 << BLUE_SHIFT,
+ (rgba)49 << RED_SHIFT | (rgba)49 << GREEN_SHIFT | (rgba)49 << BLUE_SHIFT,
+ (rgba)50 << RED_SHIFT | (rgba)50 << GREEN_SHIFT | (rgba)50 << BLUE_SHIFT,
+ (rgba)51 << RED_SHIFT | (rgba)51 << GREEN_SHIFT | (rgba)51 << BLUE_SHIFT,
+ (rgba)52 << RED_SHIFT | (rgba)52 << GREEN_SHIFT | (rgba)52 << BLUE_SHIFT,
+ (rgba)53 << RED_SHIFT | (rgba)53 << GREEN_SHIFT | (rgba)53 << BLUE_SHIFT,
+ (rgba)54 << RED_SHIFT | (rgba)54 << GREEN_SHIFT | (rgba)54 << BLUE_SHIFT,
+ (rgba)55 << RED_SHIFT | (rgba)55 << GREEN_SHIFT | (rgba)55 << BLUE_SHIFT,
+ (rgba)56 << RED_SHIFT | (rgba)56 << GREEN_SHIFT | (rgba)56 << BLUE_SHIFT,
+ (rgba)57 << RED_SHIFT | (rgba)57 << GREEN_SHIFT | (rgba)57 << BLUE_SHIFT,
+ (rgba)58 << RED_SHIFT | (rgba)58 << GREEN_SHIFT | (rgba)58 << BLUE_SHIFT,
+ (rgba)59 << RED_SHIFT | (rgba)59 << GREEN_SHIFT | (rgba)59 << BLUE_SHIFT,
+ (rgba)60 << RED_SHIFT | (rgba)60 << GREEN_SHIFT | (rgba)60 << BLUE_SHIFT,
+ (rgba)61 << RED_SHIFT | (rgba)61 << GREEN_SHIFT | (rgba)61 << BLUE_SHIFT,
+ (rgba)62 << RED_SHIFT | (rgba)62 << GREEN_SHIFT | (rgba)62 << BLUE_SHIFT,
+ (rgba)63 << RED_SHIFT | (rgba)63 << GREEN_SHIFT | (rgba)63 << BLUE_SHIFT,
+ (rgba)64 << RED_SHIFT | (rgba)64 << GREEN_SHIFT | (rgba)64 << BLUE_SHIFT,
+ (rgba)65 << RED_SHIFT | (rgba)65 << GREEN_SHIFT | (rgba)65 << BLUE_SHIFT,
+ (rgba)66 << RED_SHIFT | (rgba)66 << GREEN_SHIFT | (rgba)66 << BLUE_SHIFT,
+ (rgba)67 << RED_SHIFT | (rgba)67 << GREEN_SHIFT | (rgba)67 << BLUE_SHIFT,
+ (rgba)68 << RED_SHIFT | (rgba)68 << GREEN_SHIFT | (rgba)68 << BLUE_SHIFT,
+ (rgba)69 << RED_SHIFT | (rgba)69 << GREEN_SHIFT | (rgba)69 << BLUE_SHIFT,
+ (rgba)70 << RED_SHIFT | (rgba)70 << GREEN_SHIFT | (rgba)70 << BLUE_SHIFT,
+ (rgba)71 << RED_SHIFT | (rgba)71 << GREEN_SHIFT | (rgba)71 << BLUE_SHIFT,
+ (rgba)72 << RED_SHIFT | (rgba)72 << GREEN_SHIFT | (rgba)72 << BLUE_SHIFT,
+ (rgba)73 << RED_SHIFT | (rgba)73 << GREEN_SHIFT | (rgba)73 << BLUE_SHIFT,
+ (rgba)74 << RED_SHIFT | (rgba)74 << GREEN_SHIFT | (rgba)74 << BLUE_SHIFT,
+ (rgba)75 << RED_SHIFT | (rgba)75 << GREEN_SHIFT | (rgba)75 << BLUE_SHIFT,
+ (rgba)76 << RED_SHIFT | (rgba)76 << GREEN_SHIFT | (rgba)76 << BLUE_SHIFT,
+ (rgba)77 << RED_SHIFT | (rgba)77 << GREEN_SHIFT | (rgba)77 << BLUE_SHIFT,
+ (rgba)78 << RED_SHIFT | (rgba)78 << GREEN_SHIFT | (rgba)78 << BLUE_SHIFT,
+ (rgba)79 << RED_SHIFT | (rgba)79 << GREEN_SHIFT | (rgba)79 << BLUE_SHIFT,
+ (rgba)80 << RED_SHIFT | (rgba)80 << GREEN_SHIFT | (rgba)80 << BLUE_SHIFT,
+ (rgba)81 << RED_SHIFT | (rgba)81 << GREEN_SHIFT | (rgba)81 << BLUE_SHIFT,
+ (rgba)82 << RED_SHIFT | (rgba)82 << GREEN_SHIFT | (rgba)82 << BLUE_SHIFT,
+ (rgba)83 << RED_SHIFT | (rgba)83 << GREEN_SHIFT | (rgba)83 << BLUE_SHIFT,
+ (rgba)84 << RED_SHIFT | (rgba)84 << GREEN_SHIFT | (rgba)84 << BLUE_SHIFT,
+ (rgba)85 << RED_SHIFT | (rgba)85 << GREEN_SHIFT | (rgba)85 << BLUE_SHIFT,
+ (rgba)86 << RED_SHIFT | (rgba)86 << GREEN_SHIFT | (rgba)86 << BLUE_SHIFT,
+ (rgba)87 << RED_SHIFT | (rgba)87 << GREEN_SHIFT | (rgba)87 << BLUE_SHIFT,
+ (rgba)88 << RED_SHIFT | (rgba)88 << GREEN_SHIFT | (rgba)88 << BLUE_SHIFT,
+ (rgba)89 << RED_SHIFT | (rgba)89 << GREEN_SHIFT | (rgba)89 << BLUE_SHIFT,
+ (rgba)90 << RED_SHIFT | (rgba)90 << GREEN_SHIFT | (rgba)90 << BLUE_SHIFT,
+ (rgba)91 << RED_SHIFT | (rgba)91 << GREEN_SHIFT | (rgba)91 << BLUE_SHIFT,
+ (rgba)92 << RED_SHIFT | (rgba)92 << GREEN_SHIFT | (rgba)92 << BLUE_SHIFT,
+ (rgba)93 << RED_SHIFT | (rgba)93 << GREEN_SHIFT | (rgba)93 << BLUE_SHIFT,
+ (rgba)94 << RED_SHIFT | (rgba)94 << GREEN_SHIFT | (rgba)94 << BLUE_SHIFT,
+ (rgba)95 << RED_SHIFT | (rgba)95 << GREEN_SHIFT | (rgba)95 << BLUE_SHIFT,
+ (rgba)96 << RED_SHIFT | (rgba)96 << GREEN_SHIFT | (rgba)96 << BLUE_SHIFT,
+ (rgba)97 << RED_SHIFT | (rgba)97 << GREEN_SHIFT | (rgba)97 << BLUE_SHIFT,
+ (rgba)98 << RED_SHIFT | (rgba)98 << GREEN_SHIFT | (rgba)98 << BLUE_SHIFT,
+ (rgba)99 << RED_SHIFT | (rgba)99 << GREEN_SHIFT | (rgba)99 << BLUE_SHIFT,
+ (rgba)100 << RED_SHIFT | (rgba)100 << GREEN_SHIFT | (rgba)100 << BLUE_SHIFT,
+ (rgba)101 << RED_SHIFT | (rgba)101 << GREEN_SHIFT | (rgba)101 << BLUE_SHIFT,
+ (rgba)102 << RED_SHIFT | (rgba)102 << GREEN_SHIFT | (rgba)102 << BLUE_SHIFT,
+ (rgba)103 << RED_SHIFT | (rgba)103 << GREEN_SHIFT | (rgba)103 << BLUE_SHIFT,
+ (rgba)104 << RED_SHIFT | (rgba)104 << GREEN_SHIFT | (rgba)104 << BLUE_SHIFT,
+ (rgba)105 << RED_SHIFT | (rgba)105 << GREEN_SHIFT | (rgba)105 << BLUE_SHIFT,
+ (rgba)106 << RED_SHIFT | (rgba)106 << GREEN_SHIFT | (rgba)106 << BLUE_SHIFT,
+ (rgba)107 << RED_SHIFT | (rgba)107 << GREEN_SHIFT | (rgba)107 << BLUE_SHIFT,
+ (rgba)108 << RED_SHIFT | (rgba)108 << GREEN_SHIFT | (rgba)108 << BLUE_SHIFT,
+ (rgba)109 << RED_SHIFT | (rgba)109 << GREEN_SHIFT | (rgba)109 << BLUE_SHIFT,
+ (rgba)110 << RED_SHIFT | (rgba)110 << GREEN_SHIFT | (rgba)110 << BLUE_SHIFT,
+ (rgba)111 << RED_SHIFT | (rgba)111 << GREEN_SHIFT | (rgba)111 << BLUE_SHIFT,
+ (rgba)112 << RED_SHIFT | (rgba)112 << GREEN_SHIFT | (rgba)112 << BLUE_SHIFT,
+ (rgba)113 << RED_SHIFT | (rgba)113 << GREEN_SHIFT | (rgba)113 << BLUE_SHIFT,
+ (rgba)114 << RED_SHIFT | (rgba)114 << GREEN_SHIFT | (rgba)114 << BLUE_SHIFT,
+ (rgba)115 << RED_SHIFT | (rgba)115 << GREEN_SHIFT | (rgba)115 << BLUE_SHIFT,
+ (rgba)116 << RED_SHIFT | (rgba)116 << GREEN_SHIFT | (rgba)116 << BLUE_SHIFT,
+ (rgba)117 << RED_SHIFT | (rgba)117 << GREEN_SHIFT | (rgba)117 << BLUE_SHIFT,
+ (rgba)118 << RED_SHIFT | (rgba)118 << GREEN_SHIFT | (rgba)118 << BLUE_SHIFT,
+ (rgba)119 << RED_SHIFT | (rgba)119 << GREEN_SHIFT | (rgba)119 << BLUE_SHIFT,
+ (rgba)120 << RED_SHIFT | (rgba)120 << GREEN_SHIFT | (rgba)120 << BLUE_SHIFT,
+ (rgba)121 << RED_SHIFT | (rgba)121 << GREEN_SHIFT | (rgba)121 << BLUE_SHIFT,
+ (rgba)122 << RED_SHIFT | (rgba)122 << GREEN_SHIFT | (rgba)122 << BLUE_SHIFT,
+ (rgba)123 << RED_SHIFT | (rgba)123 << GREEN_SHIFT | (rgba)123 << BLUE_SHIFT,
+ (rgba)124 << RED_SHIFT | (rgba)124 << GREEN_SHIFT | (rgba)124 << BLUE_SHIFT,
+ (rgba)125 << RED_SHIFT | (rgba)125 << GREEN_SHIFT | (rgba)125 << BLUE_SHIFT,
+ (rgba)126 << RED_SHIFT | (rgba)126 << GREEN_SHIFT | (rgba)126 << BLUE_SHIFT,
+ (rgba)127 << RED_SHIFT | (rgba)127 << GREEN_SHIFT | (rgba)127 << BLUE_SHIFT,
+ (rgba)128 << RED_SHIFT | (rgba)128 << GREEN_SHIFT | (rgba)128 << BLUE_SHIFT,
+ (rgba)129 << RED_SHIFT | (rgba)129 << GREEN_SHIFT | (rgba)129 << BLUE_SHIFT,
+ (rgba)130 << RED_SHIFT | (rgba)130 << GREEN_SHIFT | (rgba)130 << BLUE_SHIFT,
+ (rgba)131 << RED_SHIFT | (rgba)131 << GREEN_SHIFT | (rgba)131 << BLUE_SHIFT,
+ (rgba)132 << RED_SHIFT | (rgba)132 << GREEN_SHIFT | (rgba)132 << BLUE_SHIFT,
+ (rgba)133 << RED_SHIFT | (rgba)133 << GREEN_SHIFT | (rgba)133 << BLUE_SHIFT,
+ (rgba)134 << RED_SHIFT | (rgba)134 << GREEN_SHIFT | (rgba)134 << BLUE_SHIFT,
+ (rgba)135 << RED_SHIFT | (rgba)135 << GREEN_SHIFT | (rgba)135 << BLUE_SHIFT,
+ (rgba)136 << RED_SHIFT | (rgba)136 << GREEN_SHIFT | (rgba)136 << BLUE_SHIFT,
+ (rgba)137 << RED_SHIFT | (rgba)137 << GREEN_SHIFT | (rgba)137 << BLUE_SHIFT,
+ (rgba)138 << RED_SHIFT | (rgba)138 << GREEN_SHIFT | (rgba)138 << BLUE_SHIFT,
+ (rgba)139 << RED_SHIFT | (rgba)139 << GREEN_SHIFT | (rgba)139 << BLUE_SHIFT,
+ (rgba)140 << RED_SHIFT | (rgba)140 << GREEN_SHIFT | (rgba)140 << BLUE_SHIFT,
+ (rgba)141 << RED_SHIFT | (rgba)141 << GREEN_SHIFT | (rgba)141 << BLUE_SHIFT,
+ (rgba)142 << RED_SHIFT | (rgba)142 << GREEN_SHIFT | (rgba)142 << BLUE_SHIFT,
+ (rgba)143 << RED_SHIFT | (rgba)143 << GREEN_SHIFT | (rgba)143 << BLUE_SHIFT,
+ (rgba)144 << RED_SHIFT | (rgba)144 << GREEN_SHIFT | (rgba)144 << BLUE_SHIFT,
+ (rgba)145 << RED_SHIFT | (rgba)145 << GREEN_SHIFT | (rgba)145 << BLUE_SHIFT,
+ (rgba)146 << RED_SHIFT | (rgba)146 << GREEN_SHIFT | (rgba)146 << BLUE_SHIFT,
+ (rgba)147 << RED_SHIFT | (rgba)147 << GREEN_SHIFT | (rgba)147 << BLUE_SHIFT,
+ (rgba)148 << RED_SHIFT | (rgba)148 << GREEN_SHIFT | (rgba)148 << BLUE_SHIFT,
+ (rgba)149 << RED_SHIFT | (rgba)149 << GREEN_SHIFT | (rgba)149 << BLUE_SHIFT,
+ (rgba)150 << RED_SHIFT | (rgba)150 << GREEN_SHIFT | (rgba)150 << BLUE_SHIFT,
+ (rgba)151 << RED_SHIFT | (rgba)151 << GREEN_SHIFT | (rgba)151 << BLUE_SHIFT,
+ (rgba)152 << RED_SHIFT | (rgba)152 << GREEN_SHIFT | (rgba)152 << BLUE_SHIFT,
+ (rgba)153 << RED_SHIFT | (rgba)153 << GREEN_SHIFT | (rgba)153 << BLUE_SHIFT,
+ (rgba)154 << RED_SHIFT | (rgba)154 << GREEN_SHIFT | (rgba)154 << BLUE_SHIFT,
+ (rgba)155 << RED_SHIFT | (rgba)155 << GREEN_SHIFT | (rgba)155 << BLUE_SHIFT,
+ (rgba)156 << RED_SHIFT | (rgba)156 << GREEN_SHIFT | (rgba)156 << BLUE_SHIFT,
+ (rgba)157 << RED_SHIFT | (rgba)157 << GREEN_SHIFT | (rgba)157 << BLUE_SHIFT,
+ (rgba)158 << RED_SHIFT | (rgba)158 << GREEN_SHIFT | (rgba)158 << BLUE_SHIFT,
+ (rgba)159 << RED_SHIFT | (rgba)159 << GREEN_SHIFT | (rgba)159 << BLUE_SHIFT,
+ (rgba)160 << RED_SHIFT | (rgba)160 << GREEN_SHIFT | (rgba)160 << BLUE_SHIFT,
+ (rgba)161 << RED_SHIFT | (rgba)161 << GREEN_SHIFT | (rgba)161 << BLUE_SHIFT,
+ (rgba)162 << RED_SHIFT | (rgba)162 << GREEN_SHIFT | (rgba)162 << BLUE_SHIFT,
+ (rgba)163 << RED_SHIFT | (rgba)163 << GREEN_SHIFT | (rgba)163 << BLUE_SHIFT,
+ (rgba)164 << RED_SHIFT | (rgba)164 << GREEN_SHIFT | (rgba)164 << BLUE_SHIFT,
+ (rgba)165 << RED_SHIFT | (rgba)165 << GREEN_SHIFT | (rgba)165 << BLUE_SHIFT,
+ (rgba)166 << RED_SHIFT | (rgba)166 << GREEN_SHIFT | (rgba)166 << BLUE_SHIFT,
+ (rgba)167 << RED_SHIFT | (rgba)167 << GREEN_SHIFT | (rgba)167 << BLUE_SHIFT,
+ (rgba)168 << RED_SHIFT | (rgba)168 << GREEN_SHIFT | (rgba)168 << BLUE_SHIFT,
+ (rgba)169 << RED_SHIFT | (rgba)169 << GREEN_SHIFT | (rgba)169 << BLUE_SHIFT,
+ (rgba)170 << RED_SHIFT | (rgba)170 << GREEN_SHIFT | (rgba)170 << BLUE_SHIFT,
+ (rgba)171 << RED_SHIFT | (rgba)171 << GREEN_SHIFT | (rgba)171 << BLUE_SHIFT,
+ (rgba)172 << RED_SHIFT | (rgba)172 << GREEN_SHIFT | (rgba)172 << BLUE_SHIFT,
+ (rgba)173 << RED_SHIFT | (rgba)173 << GREEN_SHIFT | (rgba)173 << BLUE_SHIFT,
+ (rgba)174 << RED_SHIFT | (rgba)174 << GREEN_SHIFT | (rgba)174 << BLUE_SHIFT,
+ (rgba)175 << RED_SHIFT | (rgba)175 << GREEN_SHIFT | (rgba)175 << BLUE_SHIFT,
+ (rgba)176 << RED_SHIFT | (rgba)176 << GREEN_SHIFT | (rgba)176 << BLUE_SHIFT,
+ (rgba)177 << RED_SHIFT | (rgba)177 << GREEN_SHIFT | (rgba)177 << BLUE_SHIFT,
+ (rgba)178 << RED_SHIFT | (rgba)178 << GREEN_SHIFT | (rgba)178 << BLUE_SHIFT,
+ (rgba)179 << RED_SHIFT | (rgba)179 << GREEN_SHIFT | (rgba)179 << BLUE_SHIFT,
+ (rgba)180 << RED_SHIFT | (rgba)180 << GREEN_SHIFT | (rgba)180 << BLUE_SHIFT,
+ (rgba)181 << RED_SHIFT | (rgba)181 << GREEN_SHIFT | (rgba)181 << BLUE_SHIFT,
+ (rgba)182 << RED_SHIFT | (rgba)182 << GREEN_SHIFT | (rgba)182 << BLUE_SHIFT,
+ (rgba)183 << RED_SHIFT | (rgba)183 << GREEN_SHIFT | (rgba)183 << BLUE_SHIFT,
+ (rgba)184 << RED_SHIFT | (rgba)184 << GREEN_SHIFT | (rgba)184 << BLUE_SHIFT,
+ (rgba)185 << RED_SHIFT | (rgba)185 << GREEN_SHIFT | (rgba)185 << BLUE_SHIFT,
+ (rgba)186 << RED_SHIFT | (rgba)186 << GREEN_SHIFT | (rgba)186 << BLUE_SHIFT,
+ (rgba)187 << RED_SHIFT | (rgba)187 << GREEN_SHIFT | (rgba)187 << BLUE_SHIFT,
+ (rgba)188 << RED_SHIFT | (rgba)188 << GREEN_SHIFT | (rgba)188 << BLUE_SHIFT,
+ (rgba)189 << RED_SHIFT | (rgba)189 << GREEN_SHIFT | (rgba)189 << BLUE_SHIFT,
+ (rgba)190 << RED_SHIFT | (rgba)190 << GREEN_SHIFT | (rgba)190 << BLUE_SHIFT,
+ (rgba)191 << RED_SHIFT | (rgba)191 << GREEN_SHIFT | (rgba)191 << BLUE_SHIFT,
+ (rgba)192 << RED_SHIFT | (rgba)192 << GREEN_SHIFT | (rgba)192 << BLUE_SHIFT,
+ (rgba)193 << RED_SHIFT | (rgba)193 << GREEN_SHIFT | (rgba)193 << BLUE_SHIFT,
+ (rgba)194 << RED_SHIFT | (rgba)194 << GREEN_SHIFT | (rgba)194 << BLUE_SHIFT,
+ (rgba)195 << RED_SHIFT | (rgba)195 << GREEN_SHIFT | (rgba)195 << BLUE_SHIFT,
+ (rgba)196 << RED_SHIFT | (rgba)196 << GREEN_SHIFT | (rgba)196 << BLUE_SHIFT,
+ (rgba)197 << RED_SHIFT | (rgba)197 << GREEN_SHIFT | (rgba)197 << BLUE_SHIFT,
+ (rgba)198 << RED_SHIFT | (rgba)198 << GREEN_SHIFT | (rgba)198 << BLUE_SHIFT,
+ (rgba)199 << RED_SHIFT | (rgba)199 << GREEN_SHIFT | (rgba)199 << BLUE_SHIFT,
+ (rgba)200 << RED_SHIFT | (rgba)200 << GREEN_SHIFT | (rgba)200 << BLUE_SHIFT,
+ (rgba)201 << RED_SHIFT | (rgba)201 << GREEN_SHIFT | (rgba)201 << BLUE_SHIFT,
+ (rgba)202 << RED_SHIFT | (rgba)202 << GREEN_SHIFT | (rgba)202 << BLUE_SHIFT,
+ (rgba)203 << RED_SHIFT | (rgba)203 << GREEN_SHIFT | (rgba)203 << BLUE_SHIFT,
+ (rgba)204 << RED_SHIFT | (rgba)204 << GREEN_SHIFT | (rgba)204 << BLUE_SHIFT,
+ (rgba)205 << RED_SHIFT | (rgba)205 << GREEN_SHIFT | (rgba)205 << BLUE_SHIFT,
+ (rgba)206 << RED_SHIFT | (rgba)206 << GREEN_SHIFT | (rgba)206 << BLUE_SHIFT,
+ (rgba)207 << RED_SHIFT | (rgba)207 << GREEN_SHIFT | (rgba)207 << BLUE_SHIFT,
+ (rgba)208 << RED_SHIFT | (rgba)208 << GREEN_SHIFT | (rgba)208 << BLUE_SHIFT,
+ (rgba)209 << RED_SHIFT | (rgba)209 << GREEN_SHIFT | (rgba)209 << BLUE_SHIFT,
+ (rgba)210 << RED_SHIFT | (rgba)210 << GREEN_SHIFT | (rgba)210 << BLUE_SHIFT,
+ (rgba)211 << RED_SHIFT | (rgba)211 << GREEN_SHIFT | (rgba)211 << BLUE_SHIFT,
+ (rgba)212 << RED_SHIFT | (rgba)212 << GREEN_SHIFT | (rgba)212 << BLUE_SHIFT,
+ (rgba)213 << RED_SHIFT | (rgba)213 << GREEN_SHIFT | (rgba)213 << BLUE_SHIFT,
+ (rgba)214 << RED_SHIFT | (rgba)214 << GREEN_SHIFT | (rgba)214 << BLUE_SHIFT,
+ (rgba)215 << RED_SHIFT | (rgba)215 << GREEN_SHIFT | (rgba)215 << BLUE_SHIFT,
+ (rgba)216 << RED_SHIFT | (rgba)216 << GREEN_SHIFT | (rgba)216 << BLUE_SHIFT,
+ (rgba)217 << RED_SHIFT | (rgba)217 << GREEN_SHIFT | (rgba)217 << BLUE_SHIFT,
+ (rgba)218 << RED_SHIFT | (rgba)218 << GREEN_SHIFT | (rgba)218 << BLUE_SHIFT,
+ (rgba)219 << RED_SHIFT | (rgba)219 << GREEN_SHIFT | (rgba)219 << BLUE_SHIFT,
+ (rgba)220 << RED_SHIFT | (rgba)220 << GREEN_SHIFT | (rgba)220 << BLUE_SHIFT,
+ (rgba)221 << RED_SHIFT | (rgba)221 << GREEN_SHIFT | (rgba)221 << BLUE_SHIFT,
+ (rgba)222 << RED_SHIFT | (rgba)222 << GREEN_SHIFT | (rgba)222 << BLUE_SHIFT,
+ (rgba)223 << RED_SHIFT | (rgba)223 << GREEN_SHIFT | (rgba)223 << BLUE_SHIFT,
+ (rgba)224 << RED_SHIFT | (rgba)224 << GREEN_SHIFT | (rgba)224 << BLUE_SHIFT,
+ (rgba)225 << RED_SHIFT | (rgba)225 << GREEN_SHIFT | (rgba)225 << BLUE_SHIFT,
+ (rgba)226 << RED_SHIFT | (rgba)226 << GREEN_SHIFT | (rgba)226 << BLUE_SHIFT,
+ (rgba)227 << RED_SHIFT | (rgba)227 << GREEN_SHIFT | (rgba)227 << BLUE_SHIFT,
+ (rgba)228 << RED_SHIFT | (rgba)228 << GREEN_SHIFT | (rgba)228 << BLUE_SHIFT,
+ (rgba)229 << RED_SHIFT | (rgba)229 << GREEN_SHIFT | (rgba)229 << BLUE_SHIFT,
+ (rgba)230 << RED_SHIFT | (rgba)230 << GREEN_SHIFT | (rgba)230 << BLUE_SHIFT,
+ (rgba)231 << RED_SHIFT | (rgba)231 << GREEN_SHIFT | (rgba)231 << BLUE_SHIFT,
+ (rgba)232 << RED_SHIFT | (rgba)232 << GREEN_SHIFT | (rgba)232 << BLUE_SHIFT,
+ (rgba)233 << RED_SHIFT | (rgba)233 << GREEN_SHIFT | (rgba)233 << BLUE_SHIFT,
+ (rgba)234 << RED_SHIFT | (rgba)234 << GREEN_SHIFT | (rgba)234 << BLUE_SHIFT,
+ (rgba)235 << RED_SHIFT | (rgba)235 << GREEN_SHIFT | (rgba)235 << BLUE_SHIFT,
+ (rgba)236 << RED_SHIFT | (rgba)236 << GREEN_SHIFT | (rgba)236 << BLUE_SHIFT,
+ (rgba)237 << RED_SHIFT | (rgba)237 << GREEN_SHIFT | (rgba)237 << BLUE_SHIFT,
+ (rgba)238 << RED_SHIFT | (rgba)238 << GREEN_SHIFT | (rgba)238 << BLUE_SHIFT,
+ (rgba)239 << RED_SHIFT | (rgba)239 << GREEN_SHIFT | (rgba)239 << BLUE_SHIFT,
+ (rgba)240 << RED_SHIFT | (rgba)240 << GREEN_SHIFT | (rgba)240 << BLUE_SHIFT,
+ (rgba)241 << RED_SHIFT | (rgba)241 << GREEN_SHIFT | (rgba)241 << BLUE_SHIFT,
+ (rgba)242 << RED_SHIFT | (rgba)242 << GREEN_SHIFT | (rgba)242 << BLUE_SHIFT,
+ (rgba)243 << RED_SHIFT | (rgba)243 << GREEN_SHIFT | (rgba)243 << BLUE_SHIFT,
+ (rgba)244 << RED_SHIFT | (rgba)244 << GREEN_SHIFT | (rgba)244 << BLUE_SHIFT,
+ (rgba)245 << RED_SHIFT | (rgba)245 << GREEN_SHIFT | (rgba)245 << BLUE_SHIFT,
+ (rgba)246 << RED_SHIFT | (rgba)246 << GREEN_SHIFT | (rgba)246 << BLUE_SHIFT,
+ (rgba)247 << RED_SHIFT | (rgba)247 << GREEN_SHIFT | (rgba)247 << BLUE_SHIFT,
+ (rgba)248 << RED_SHIFT | (rgba)248 << GREEN_SHIFT | (rgba)248 << BLUE_SHIFT,
+ (rgba)249 << RED_SHIFT | (rgba)249 << GREEN_SHIFT | (rgba)249 << BLUE_SHIFT,
+ (rgba)250 << RED_SHIFT | (rgba)250 << GREEN_SHIFT | (rgba)250 << BLUE_SHIFT,
+ (rgba)251 << RED_SHIFT | (rgba)251 << GREEN_SHIFT | (rgba)251 << BLUE_SHIFT,
+ (rgba)252 << RED_SHIFT | (rgba)252 << GREEN_SHIFT | (rgba)252 << BLUE_SHIFT,
+ (rgba)253 << RED_SHIFT | (rgba)253 << GREEN_SHIFT | (rgba)253 << BLUE_SHIFT,
+ (rgba)254 << RED_SHIFT | (rgba)254 << GREEN_SHIFT | (rgba)254 << BLUE_SHIFT,
+ (rgba)255 << RED_SHIFT | (rgba)255 << GREEN_SHIFT | (rgba)255 << BLUE_SHIFT,
+};
diff --git a/kernel/kls_xcf/xcf2pnm/utils.c b/kernel/kls_xcf/xcf2pnm/utils.c
new file mode 100644
index 0000000..bde0782
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/utils.c
@@ -0,0 +1,164 @@
+/* Generic support functions for Xcftools
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xcftools.h"
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+
+const char *progname = "$0" ;
+int verboseFlag = 0 ;
+
+
+static void __ATTRIBUTE__((noreturn))
+vFatalGeneric(int status,const char *format,va_list args)
+{
+ if( format ) {
+ if( *format == '!' ) {
+ vfprintf(stderr,format+1,args);
+ fprintf(stderr,": %s\n",strerror(errno));
+ } else {
+ vfprintf(stderr,format,args);
+ fputc('\n',stderr);
+ }
+ }
+ exit(status);
+}
+
+void
+FatalGeneric(int status,const char* format,...)
+{
+ va_list v; va_start(v,format);
+ if( format ) fprintf(stderr,"%s: ",progname);
+ vFatalGeneric(status,format,v);
+}
+
+void
+FatalUnexpected(const char* format,...)
+{
+ va_list v; va_start(v,format);
+ fprintf(stderr,"%s: ",progname);
+ vFatalGeneric(127,format,v) ;
+}
+
+void
+FatalBadXCF(const char* format,...)
+{
+ va_list v; va_start(v,format);
+ fprintf(stderr,"%s: %s:\n ",progname,_("Corrupted or malformed XCF file"));
+ vFatalGeneric(125,format,v) ;
+}
+
+void
+xcfCheckspace(uint32_t addr,int spaceafter,const char *format,...)
+{
+ if( xcf_length < spaceafter || addr > xcf_length - spaceafter ) {
+ va_list v; va_start(v,format);
+ fprintf(stderr,"%s: %s\n ",progname,_("Corrupted or truncated XCF file"));
+ fprintf(stderr,"(0x%" PRIXPTR " bytes): ",(uintptr_t)xcf_length);
+ vFatalGeneric(125,format,v) ;
+ }
+}
+
+
+void
+FatalUnsupportedXCF(const char* format,...)
+{
+ va_list v; va_start(v,format);
+ fprintf(stderr,"%s: %s\n ",progname,
+ _("The image contains features not understood by this program:"));
+ vFatalGeneric(123,format,v) ;
+}
+
+void
+gpl_blurb(void)
+{
+ fprintf(stderr,PACKAGE_STRING "\n");
+ fprintf(stderr,
+ _("This program is free software; you can modify and distribute it\n"
+ "under the terms of the GNU General Public License, version 2.\n"
+ "There is no warranty for %s.\n\n"),
+ PACKAGE_NAME);
+ fprintf(stderr,
+ _("Type \"%s -h\" to get an option summary.\n"),progname);
+ exit(1) ;
+}
+
+/* ******************************************************* */
+
+void *
+xcfmalloc(size_t size)
+{
+ void *ptr = malloc(size);
+ if( !ptr )
+ FatalUnexpected(_("Out of memory"));
+ return ptr ;
+}
+
+void
+xcffree(void *block)
+{
+ if( xcf_file &&
+ (uint8_t*)block >= xcf_file &&
+ (uint8_t*)block < xcf_file + xcf_length )
+ ;
+ else
+ free(block);
+}
+
+/* ******************************************************* */
+
+FILE *
+openout(const char *name)
+{
+ FILE *newfile ;
+ if( strcmp(name,"-") == 0 )
+ return stdout ;
+ newfile = fopen(name,"wb") ;
+ if( newfile == NULL )
+ FatalUnexpected(_("!Cannot create file %s"),name);
+ return newfile ;
+}
+
+void
+closeout(FILE *f,const char *name)
+{
+ if( f == NULL )
+ return ;
+ if( fflush(f) == 0 ) {
+ errno = 0 ;
+ if( !ferror(f) ) {
+ if( fclose(f) == 0 )
+ return ;
+ } else if( errno == 0 ) {
+ /* Attempt to coax a valid errno out of the standard library,
+ * following an idea by Bruno Haible
+ * http://lists.gnu.org/archive/html/bug-gnulib/2003-09/msg00157.html
+ */
+ if( fputc('\0', f) != EOF &&
+ fflush(f) == 0 )
+ errno = EIO ; /* Argh, everything succeds. Just call it an I/O error */
+ }
+ }
+ FatalUnexpected(_("!Error writing file %s"),name);
+}
+
+
+
+
diff --git a/kernel/kls_xcf/xcf2pnm/xcf-general.c b/kernel/kls_xcf/xcf2pnm/xcf-general.c
new file mode 100644
index 0000000..9231134
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/xcf-general.c
@@ -0,0 +1,287 @@
+/* Generic functions for reading XCF files
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xcftools.h"
+#include <string.h>
+#include <errno.h>
+#ifdef HAVE_ICONV
+# include <iconv.h>
+#elif !defined(ICONV_CONST)
+# define ICONV_CONST const
+#endif
+
+uint8_t *xcf_file = 0 ;
+size_t xcf_length ;
+int use_utf8 = 0 ;
+
+uint32_t
+xcfOffset(uint32_t addr,int spaceafter)
+{
+ uint32_t apparent ;
+ xcfCheckspace(addr,4,"(xcfOffset)");
+ apparent = xcfL(addr);
+ xcfCheckspace(apparent,spaceafter,
+ "Too large offset (%" PRIX32 ") at position %" PRIX32,
+ apparent,addr);
+ return apparent ;
+}
+
+int
+xcfNextprop(uint32_t *master,uint32_t *body)
+{
+ uint32_t ptr, length, total, minlength ;
+ PropType type ;
+ ptr = *master ;
+ xcfCheckspace(ptr,8,"(property header)");
+ type = xcfL(ptr);
+ length = xcfL(ptr+4);
+ *body = ptr+8 ;
+
+ switch(type) {
+ case PROP_COLORMAP:
+ {
+ uint32_t ncolors ;
+ xcfCheckspace(ptr+8,4,"(colormap length)");
+ ncolors = xcfL(ptr+8) ;
+ if( ncolors > 256 )
+ FatalBadXCF("Colormap has %" PRIu32 " entries",ncolors);
+ /* Surprise! Some older verion of the Gimp computed the wrong length
+ * word, and the _reader_ always just reads three bytes per color
+ * and ignores the length tag! Duplicate this so we too can read
+ * the buggy XCF files.
+ */
+ length = minlength = 4+3*ncolors;
+ break;
+ }
+ case PROP_COMPRESSION: minlength = 1; break;
+ case PROP_OPACITY: minlength = 4; break;
+ case PROP_APPLY_MASK: minlength = 4; break;
+ case PROP_OFFSETS: minlength = 8; break;
+ case PROP_MODE: minlength = 4; break;
+ default: minlength = 0; break;
+ }
+ if( length < minlength )
+ FatalBadXCF("Short %s property at %" PRIX32 " (%" PRIu32 "<%" PRIu32 ")",
+ showPropType(type),ptr,length,minlength);
+ *master = ptr+8+length ;
+ total = 8 + length + (type != PROP_END ? 8 : 0) ;
+ if( total < length ) /* Check overwrap */
+ FatalBadXCF("Overlong property at %" PRIX32, ptr);
+ xcfCheckspace(ptr,total,"Overlong property at %" PRIX32,ptr) ;
+ return type ;
+}
+
+const char*
+xcfString(uint32_t ptr,uint32_t *after)
+{
+ uint32_t length ;
+ unsigned i ;
+ ICONV_CONST char *utf8master ;
+
+ xcfCheckspace(ptr,4,"(string length)");
+ length = xcfL(ptr) ;
+ ptr += 4 ;
+ xcfCheckspace(ptr,length,"(string)");
+ utf8master = (ICONV_CONST char*)(xcf_file+ptr) ;
+ if( after ) *after = ptr + length ;
+ if( length == 0 || utf8master[length-1] != 0 )
+ FatalBadXCF("String at %" PRIX32 " not zero-terminated",ptr-4);
+ length-- ;
+
+ if( use_utf8 ) return utf8master ;
+
+ /* We assume that the local character set includes ASCII...
+ * Check if conversion is needed at all
+ */
+ for( i=0 ; ; i++ ) {
+ if( i == length )
+ return utf8master ; /* Only ASCII after all */
+ if( utf8master[i] == 0 )
+ FatalBadXCF("String at %" PRIX32 " has embedded zeroes",ptr-4);
+ if( (int8_t) utf8master[i] < 0 )
+ break ;
+ }
+#ifdef HAVE_ICONV
+ {
+ size_t targetsize = length+1 ;
+ int sloppy_translation = 0 ;
+ iconv_t cd = iconv_open("//TRANSLIT","UTF-8");
+ if( cd == (iconv_t) -1 ) {
+ cd = iconv_open("","UTF-8");
+ sloppy_translation = 1 ;
+ }
+ if( cd == (iconv_t) -1 )
+ iconv_close(cd) ; /* Give up; perhaps iconv doesn't know UTF-8 */
+ else
+ while(1) {
+ char *buffer = xcfmalloc(targetsize) ;
+ ICONV_CONST char *inbuf = utf8master ;
+ char *outbuf = buffer ;
+ size_t incount = length ;
+ size_t outcount = targetsize ;
+ while(1) { /* Loop for systems without //ICONV support */
+ size_t result = iconv(cd,&inbuf,&incount,&outbuf,&outcount) ;
+ if( result == (size_t)-1 && errno == EILSEQ &&
+ sloppy_translation && outcount > 0 ) {
+ *outbuf++ = '?' ;
+ outcount-- ;
+ while( (int8_t)*inbuf < 0 ) inbuf++, incount-- ;
+ continue ;
+ }
+ if( result != (size_t)-1 ) {
+ if( outcount == 0 )
+ errno = E2BIG ;
+ else {
+ *outbuf = 0 ;
+ iconv_close(cd) ;
+ return buffer ;
+ }
+ }
+ break ;
+ }
+ if( errno == EILSEQ || errno == EINVAL )
+ FatalBadXCF("Bad UTF-8 encoding '%s' at %" PRIXPTR,
+ inbuf,(uintptr_t)((inbuf-utf8master)+ptr));
+ if( errno == E2BIG ) {
+ targetsize += 1+incount ;
+ xcffree(buffer) ;
+ continue ;
+ }
+ FatalUnexpected("!iconv on layer name at %"PRIX32,ptr);
+ }
+ }
+#endif
+ {
+ static int warned = 0 ;
+ if( !warned ) {
+ fprintf(stderr,_("Warning: one or more layer names could not be\n"
+ " translated to the local character set.\n"));
+ warned = 1 ;
+ }
+ }
+ return utf8master ;
+}
+
+/* ****************************************************************** */
+
+void
+computeDimensions(struct tileDimensions *d)
+{
+ d->c.r = d->c.l + d->width ;
+ d->c.b = d->c.t + d->height ;
+ d->tilesx = (d->width+TILE_WIDTH-1)/TILE_WIDTH ;
+ d->tilesy = (d->height+TILE_HEIGHT-1)/TILE_HEIGHT ;
+ d->ntiles = d->tilesx * d->tilesy ;
+}
+
+struct xcfImage XCF ;
+
+void
+getBasicXcfInfo(void)
+{
+ uint32_t ptr, data, layerfile ;
+ PropType type ;
+ int i ;
+
+ xcfCheckspace(0,14+7*4,"(very short)");
+ if( strcmp((char*)xcf_file,"gimp xcf file") == 0 )
+ XCF.version = 0 ;
+ else if( xcf_file[13] == 0 &&
+ sscanf((char*)xcf_file,"gimp xcf v%d",&XCF.version) == 1 )
+ ;
+ else
+ FatalBadXCF(_("Not an XCF file at all (magic not recognized)"));
+
+ if( XCF.version < 0 || XCF.version > 2 ) {
+ fprintf(stderr,
+ _("Warning: XCF version %d not supported (trying anyway...)\n"),
+ XCF.version);
+ }
+
+ XCF.compression = COMPRESS_NONE ;
+ XCF.colormapptr = 0 ;
+
+ ptr = 14 ;
+ XCF.width = xcfL(ptr); ptr += 4 ;
+ XCF.height = xcfL(ptr); ptr += 4 ;
+ XCF.type = xcfL(ptr); ptr += 4 ;
+ while( (type = xcfNextprop(&ptr,&data)) != PROP_END ) {
+ switch(type) {
+ case PROP_COLORMAP:
+ XCF.colormapptr = data ;
+ break ;
+ case PROP_COMPRESSION:
+ XCF.compression = xcf_file[data] ;
+ break ;
+ default:
+ /* Ignore unknown properties */
+ break ;
+ }
+ }
+
+ layerfile = ptr ;
+ for( XCF.numLayers = 0 ; xcfOffset(ptr,8*4) ; XCF.numLayers++, ptr+=4 )
+ ;
+ XCF.layers = xcfmalloc(XCF.numLayers * sizeof(struct xcfLayer)) ;
+ for( i = 0 ; i < XCF.numLayers ; i++ ) {
+ struct xcfLayer *L = XCF.layers + i ;
+ ptr = xcfL(layerfile+4*(XCF.numLayers-1-i)) ;
+ L->mode = GIMP_NORMAL_MODE ;
+ L->opacity = 255 ;
+ L->isVisible = 1 ;
+ L->hasMask = 0 ;
+ L->dim.width = xcfL(ptr); ptr+=4 ;
+ L->dim.height = xcfL(ptr); ptr+=4 ;
+ L->type = xcfL(ptr); ptr+=4 ;
+ L->name = xcfString(ptr,&ptr);
+ L->propptr = ptr ;
+ while( (type = xcfNextprop(&ptr,&data)) != PROP_END ) {
+ switch(type) {
+ case PROP_OPACITY:
+ L->opacity = xcfL(data);
+ if( L->opacity > 255 )
+ L->opacity = 255 ;
+ break ;
+ case PROP_VISIBLE:
+ L->isVisible = xcfL(data) != 0 ;
+ break ;
+ case PROP_APPLY_MASK:
+ L->hasMask = xcfL(data) != 0 ;
+ break ;
+ case PROP_OFFSETS:
+ L->dim.c.l = (int32_t)(xcfL(data )) ;
+ L->dim.c.t = (int32_t)(xcfL(data+4)) ;
+ break ;
+ case PROP_MODE:
+ L->mode = xcfL(data);
+ break ;
+ default:
+ /* Ignore unknown properties */
+ break ;
+ }
+ }
+ xcfCheckspace(ptr,8,"(end of layer %s)",L->name);
+ L->pixels.tileptrs = 0 ;
+ L->pixels.hierarchy = xcfOffset(ptr ,4*4);
+ L->mask.tileptrs = 0 ;
+ L->mask.hierarchy = xcfOffset(ptr+4,4*4);
+
+ computeDimensions(&L->dim);
+ }
+}
+
diff --git a/kernel/kls_xcf/xcf2pnm/xcf2pnm.c b/kernel/kls_xcf/xcf2pnm/xcf2pnm.c
new file mode 100644
index 0000000..06baf8d
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/xcf2pnm.c
@@ -0,0 +1,269 @@
+/* Convert xcf files to ppm
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "xcftools.h"
+#include "flatten.h"
+#include <stdlib.h>
+#include <string.h>
+#include <locale.h>
+#include <ctype.h>
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#else
+#include <unistd.h>
+#endif
+#ifndef HAVE_GETOPT_LONG
+#define getopt_long(argc,argv,optstring,l1,l2) getopt(argc,argv,optstring)
+#endif
+
+#include "xcf2pnm.oi"
+
+static int suppress_byline ;
+static struct FlattenSpec flatspec ;
+static FILE *outfile = NULL ;
+static FILE *transfile = NULL ;
+
+static void
+start_writing(FILE **f,int version)
+{
+ const char *format[] = {"(format zero)",
+ "PBM-ascii",
+ "PGM-ascii",
+ "PPM-ascii",
+ "PBM",
+ "PGM",
+ "PPM" };
+
+ if( verboseFlag )
+ fprintf(stderr,f == &outfile ? _("Writing converted image as %s\n")
+ : _("Writing transparency map as %s\n"),
+ format[version]);
+
+ *f = openout( f == &outfile ? flatspec.output_filename
+ : flatspec.transmap_filename );
+ fprintf(*f,"P%d",version);
+ if( suppress_byline )
+ ;
+ else if( f == &outfile )
+ fprintf(*f,_(" # Converted by xcf2pnm %s"),PACKAGE_VERSION);
+ else
+ fprintf(*f,_(" # Transparency map by xcf2pnm %s"),PACKAGE_VERSION);
+ fprintf(*f,"\n%d %d\n%s",
+ flatspec.dim.width,
+ flatspec.dim.height,
+ version == 4 ? "" : "255\n");
+}
+
+int
+put_pbm_row(FILE *file,unsigned num,rgba *pixels,rgba mask);
+
+int
+put_pbm_row(FILE *file,unsigned num,rgba *pixels,rgba mask) {
+ unsigned out ;
+ unsigned i ;
+ int bitsleft = 8 ;
+ out = 0 ;
+ for( i=0; i<num; i++ ) {
+ out <<= 1 ;
+ if( (pixels[i] & mask) == 0 )
+ out++ ; /* 1 is black */
+ else if( (pixels[i] & mask) == mask )
+ ; /* 0 is white */
+ else
+ return 0 ;
+ if( --bitsleft == 0 ) {
+ putc( out, file );
+ out = 0 ;
+ bitsleft = 8 ;
+ }
+ }
+ if( bitsleft < 8 )
+ putc( out << bitsleft, file );
+ return 1 ;
+}
+
+static void
+callback_common(unsigned num,rgba *pixels)
+{
+ if( flatspec.transmap_filename ) {
+ if( flatspec.partial_transparency_mode == ALLOW_PARTIAL_TRANSPARENCY ) {
+ unsigned i ;
+ if( transfile == NULL ) start_writing(&transfile,5);
+ for( i=0; i < num; i++ )
+ putc( ALPHA(pixels[i]), transfile );
+ } else {
+ if( transfile == NULL ) {
+ start_writing(&transfile,4);
+ }
+ /* Partial transparency should have been caught in the flattener,
+ * so just extract a single byte.
+ */
+ put_pbm_row(transfile,num,pixels,(rgba)1 << ALPHA_SHIFT);
+ }
+ } else if( ALPHA(flatspec.default_pixel) < 128 ) {
+ unsigned i ;
+ for( i=0; i < num; i++ )
+ if( !FULLALPHA(pixels[i]) )
+ FatalGeneric(100,_("Transparency found, but -a option not given"));
+ }
+ xcffree(pixels) ;
+}
+
+static void
+ppm_callback(unsigned num,rgba *pixels)
+{
+ unsigned i ;
+ if( outfile == NULL ) start_writing(&outfile,6);
+ for( i=0; i < num; i++ ) {
+ putc( (pixels[i] >> RED_SHIFT) & 0xFF , outfile );
+ putc( (pixels[i] >> GREEN_SHIFT) & 0xFF , outfile );
+ putc( (pixels[i] >> BLUE_SHIFT) & 0xFF , outfile );
+ }
+ callback_common(num,pixels);
+}
+
+static void
+pgm_callback(unsigned num,rgba *pixels)
+{
+ unsigned i ;
+ if( outfile == NULL ) start_writing(&outfile,5);
+ for( i=0; i < num; i++ ) {
+ int gray = degrayPixel(pixels[i]) ;
+ if( gray == -1 )
+ FatalGeneric(103,
+ _("Grayscale output selected, but colored pixel(s) found"));
+ putc( gray, outfile );
+ }
+ callback_common(num,pixels);
+}
+
+static void
+pbm_callback(unsigned num,rgba *pixels)
+{
+ if( outfile == NULL ) start_writing(&outfile,4);
+ if( !put_pbm_row(outfile,num,pixels,
+ ((rgba)255 << RED_SHIFT) +
+ ((rgba)255 << GREEN_SHIFT) +
+ ((rgba)255 << BLUE_SHIFT)) )
+ FatalGeneric(103,_("Monochrome output selected, but not all pixels "
+ "are black or white"));
+ callback_common(num,pixels);
+}
+
+static enum out_color_mode
+guess_color_mode(const char *string)
+{
+ if( strlen(string) >= 3 ) {
+ string += strlen(string)-3 ;
+ if( strcmp(string,"ppm")==0 ) return COLOR_RGB ;
+ if( strcmp(string,"pgm")==0 ) return COLOR_GRAY ;
+ if( strcmp(string,"pbm")==0 ) return COLOR_MONO ;
+ }
+ return COLOR_BY_FILENAME ;
+}
+
+static lineCallback
+selectCallback(void)
+{
+ if( flatspec.transmap_filename && ALPHA(flatspec.default_pixel) >= 128 )
+ FatalGeneric(101,_("The -a option was given, "
+ "but the image has no transparency"));
+
+ switch( flatspec.out_color_mode ) {
+ default:
+ case COLOR_RGB: return &ppm_callback ;
+ case COLOR_GRAY: return &pgm_callback ;
+ case COLOR_MONO: return &pbm_callback ;
+ }
+}
+
+int
+main(int argc,char **argv)
+{
+ int option ;
+ const char *unzipper = NULL ;
+ const char *infile = NULL ;
+
+ setlocale(LC_ALL,"");
+ progname = argv[0] ;
+ nls_init();
+
+ if( argc <= 1 ) gpl_blurb() ;
+
+ init_flatspec(&flatspec) ;
+ flatspec.out_color_mode = COLOR_BY_FILENAME ;
+ while( (option=getopt_long(argc,argv,"-@#"OPTSTRING,longopts,NULL)) >= 0 )
+ switch(option) {
+
+#define OPTION(char,long,desc,man) case char:
+#include "options.i"
+
+ case 1:
+ if( infile )
+ add_layer_request(&flatspec,optarg);
+ else
+ infile = optarg ;
+ break ;
+ case '?':
+ exit(1);
+ case '@':
+ /* Non-documented option for build-time test */
+ suppress_byline = 1 ;
+ break ;
+ case '#':
+ /* Non-documented option for xcfview */
+ flatspec.default_pixel = CHECKERED_BACKGROUND ;
+ break ;
+ default:
+ FatalUnexpected("Getopt(_long) unexpectedly returned '%c'",option);
+ }
+ if( infile == NULL ) {
+ exit(1);
+ }
+
+ if( flatspec.out_color_mode == COLOR_BY_FILENAME &&
+ strlen(flatspec.output_filename) > 4 &&
+ flatspec.output_filename[strlen(flatspec.output_filename)-4] == '.' )
+ flatspec.out_color_mode = guess_color_mode(flatspec.output_filename);
+
+ /* If the output filename was not enough cue, see if we're running
+ * through a symlink/hardlink that gives the required output format
+ */
+ if( flatspec.out_color_mode == COLOR_BY_FILENAME &&
+ strlen(progname) > 3 )
+ flatspec.out_color_mode = guess_color_mode(progname);
+
+ if( flatspec.out_color_mode == COLOR_BY_FILENAME )
+ flatspec.out_color_mode = COLOR_BY_CONTENTS ;
+
+ read_or_mmap_xcf(infile,unzipper);
+ getBasicXcfInfo() ;
+ initColormap();
+
+ complete_flatspec(&flatspec,NULL);
+ if( flatspec.process_in_memory ) {
+ rgba **allPixels = flattenAll(&flatspec);
+ analyse_colormode(&flatspec,allPixels,NULL);
+ shipoutWithCallback(&flatspec,allPixels,selectCallback());
+ } else {
+ flattenIncrementally(&flatspec,selectCallback());
+ }
+ closeout(outfile,flatspec.output_filename) ;
+ closeout(transfile,flatspec.transmap_filename) ;
+ return 0 ;
+}
diff --git a/kernel/kls_xcf/xcf2pnm/xcf2pnm.oi b/kernel/kls_xcf/xcf2pnm/xcf2pnm.oi
new file mode 100644
index 0000000..382bd96
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/xcf2pnm.oi
@@ -0,0 +1,41 @@
+/* Autogenerated by mkopti.pl xcf2pnm */
+#define XCF2PNM
+#define OPTI_TARGET "xcf2pnm"
+#define XCF2FOO
+#define OPTIONGROUP(a,b)
+
+#ifdef HAVE_GETOPT_LONG
+static const struct option longopts[] = {
+ { "help", 0, 0, 'h'},
+ { "version", 0, 0, 'V'},
+ { "verbose", 0, 0, 'v'},
+ { "bzip", 0, 0, 'j'},
+ { "gzip", 0, 0, 'z'},
+ { "unpack", 1, 0, 'Z'},
+ { "output", 1, 0, 'o'},
+ { "alpha", 1, 0, 'a'},
+ { "background", 1, 0, 'b'},
+ { "force-alpha", 0, 0, 'A'},
+ { "color", 0, 0, 'c'},
+ { "colour", 0, 0, 'c'},
+ { "gray", 0, 0, 'g'},
+ { "grey", 0, 0, 'g'},
+ { "mono", 0, 0, 'm'},
+ { "pnm", 0, 0, 'n'},
+ { "truecolor", 0, 0, 'T'},
+ { "for-gif", 0, 0, 'G'},
+ { "dissolve", 0, 0, 'D'},
+ { "full-image", 0, 0, 'f'},
+ { "size", 1, 0, 'S'},
+ { "offset", 1, 0, 'O'},
+ { "autocrop", 0, 0, 'C'},
+ { "mode", 1, 0, 300},
+ { "percent", 1, 0, 301},
+ { "opacity", 1, 0, 302},
+ { "mask", 0, 0, 303},
+ { "nomask", 0, 0, 304},
+ { "utf8", 0, 0, 'u'},
+{0}};
+#endif
+
+#define OPTSTRING "hVvjzZ:o:a:b:AcgmnTGDfS:O:Cu"
diff --git a/kernel/kls_xcf/xcf2pnm/xcftools.h b/kernel/kls_xcf/xcf2pnm/xcftools.h
new file mode 100644
index 0000000..d3efbab
--- /dev/null
+++ b/kernel/kls_xcf/xcf2pnm/xcftools.h
@@ -0,0 +1,182 @@
+/* Generic functions and macros for reading XCF files
+ *
+ * Copyright (C) 2006 Henning Makholm
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef XCFTOOLS_H
+#define XCFTOOLS_H
+
+#include "enums.h"
+#include <stddef.h>
+#include <stdio.h>
+
+#define _(s) (s)
+#define nls_init() (void)0
+#define N_(s) (s)
+
+#if HAVE_INTTYPES_H
+# define __STDC_FORMAT_MACROS
+# include <inttypes.h>
+#else
+/* These legacy fall-backs will probably work on every system
+ * that does not supply a inttypes.h ... */
+typedef unsigned char uint8_t ;
+typedef unsigned long int uint32_t, uintptr_t ;
+typedef signed char int8_t ;
+typedef signed long int int32_t ;
+# define PRIX32 "lX"
+# define PRIu32 "lu"
+# define PRIXPTR "lX"
+#endif
+
+#if __GNUC__
+# define __ATTRIBUTE__ __attribute__
+#else
+# define __ATTRIBUTE__(x)
+#endif
+
+#if HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#elif HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#elif WORDS_BIGENDIAN
+# define ntohl(x) (x)
+#else
+static inline uint32_t ntohl(uint32_t a) {
+ return (a << 24) + ((a & 0xFF00) << 8) + ((a >> 8) & 0xFF00) + (a >> 24) ;
+}
+#endif
+
+#ifndef HAVE_STRCASECMP
+#define strcasecmp strcmp
+#endif
+
+/* Read a single word value from the XCF file */
+
+/* Use + instead of | because that allows LEA instructions */
+#define xcfBE(a) ( ((uint32_t)xcf_file[(a) ] << 24) + \
+ ((uint32_t)xcf_file[(a)+1] << 16) + \
+ ((uint32_t)xcf_file[(a)+2] << 8 ) + \
+ ((uint32_t)xcf_file[(a)+3] ) )
+#define xcfLE(a) ( ((uint32_t)xcf_file[(a) ] ) + \
+ ((uint32_t)xcf_file[(a)+1] << 8 ) + \
+ ((uint32_t)xcf_file[(a)+2] << 16) + \
+ ((uint32_t)xcf_file[(a)+3] << 24) )
+
+#if CAN_DO_UNALIGNED_WORDS
+# define xcfL(a) ntohl(*(uint32_t *)(xcf_file + (a)))
+#else
+# define xcfL(a) ((a) & 3 ? xcfBE(a) : ntohl(*(uint32_t *)(xcf_file + (a))))
+#endif
+
+/* ****************************************************************** */
+
+/* The following are exported from am OS-specific source file;
+ * io-unix.c on unixish systems.
+ */
+void read_or_mmap_xcf(const char* filename, const char *unzipper);
+void free_or_close_xcf(void);
+
+/* ****************************************************************** */
+/* utils.c */
+
+extern const char *progname ;
+extern int verboseFlag ;
+
+void *xcfmalloc(size_t size);
+void xcffree(void*);
+
+void FatalGeneric(int status,const char* format,...)
+ __ATTRIBUTE__((format(printf,2,3),noreturn)) ;
+void FatalUnexpected(const char* format,...)
+ __ATTRIBUTE__((format(printf,1,2),noreturn)) ;
+void FatalBadXCF(const char* format,...)
+ __ATTRIBUTE__((format(printf,1,2),noreturn)) ;
+void FatalUnsupportedXCF(const char* format,...)
+ __ATTRIBUTE__((format(printf,1,2),noreturn)) ;
+
+void gpl_blurb(void) __ATTRIBUTE__((noreturn));
+
+FILE* openout(const char*);
+void closeout(FILE *,const char*);
+
+struct rect {
+ int t, b, l, r ;
+};
+
+#define isSubrect(A,B) \
+ ((A).l >= (B).l && (A).r <= (B).r && (A).t >= (B).t && (A).b <= (B).b)
+#define disjointRects(A,B) \
+ ((A).l >= (B).r || (A).r <= (B).l || (A).t >= (B).b || (A).b <= (B).t)
+
+/* ****************************************************************** */
+/* xcf-general.c */
+
+extern uint8_t *xcf_file ;
+extern size_t xcf_length ;
+extern int use_utf8 ;
+
+void xcfCheckspace(uint32_t addr,int spaceafter, const char *format,...)
+ __ATTRIBUTE__((format(printf,3,4)));
+uint32_t xcfOffset(uint32_t addr,int spaceafter);
+
+int xcfNextprop(uint32_t *master,uint32_t *body);
+const char* xcfString(uint32_t ptr,uint32_t *after);
+
+/* These are hardcoded in the Gimp sources: */
+#define TILE_WIDTH 64
+#define TILE_HEIGHT 64
+
+struct tileDimensions {
+ struct rect c ;
+ unsigned width, height ;
+ unsigned tilesx, tilesy ;
+ unsigned ntiles ;
+};
+/* computeDimensions assumes that width, height, c.l, and c.t are set */
+void computeDimensions(struct tileDimensions *);
+
+struct xcfTiles {
+ const struct _convertParams *params ;
+ uint32_t *tileptrs ;
+ uint32_t hierarchy ;
+};
+
+struct xcfLayer {
+ struct tileDimensions dim ;
+ const char *name ;
+ GimpLayerModeEffects mode ;
+ GimpImageType type ;
+ unsigned int opacity ;
+ int isVisible, hasMask ;
+ uint32_t propptr ;
+ struct xcfTiles pixels ;
+ struct xcfTiles mask ;
+};
+
+extern struct xcfImage {
+ int version ;
+ unsigned width, height ;
+ GimpImageBaseType type ;
+ XcfCompressionType compression ;
+ int numLayers ;
+ struct xcfLayer *layers ;
+ uint32_t colormapptr ;
+} XCF ;
+
+void getBasicXcfInfo(void);
+
+#endif /* XCFTOOLS_H */