*** tkImgPhoto.c.orig	Fri Dec  1 13:07:50 2000
--- tkImgPhoto.c	Fri Dec  1 12:58:41 2000
***************
*** 153,156 ****
--- 153,157 ----
  				 * deleted. */
      int	flags;			/* Sundry flags, defined below. */
+     int	dither;			/* Type of dithering to apply to instances. */
      int	width, height;		/* Dimensions of image. */
      int userWidth, userHeight;	/* User-declared image dimensions. */
***************
*** 172,175 ****
--- 173,180 ----
  } PhotoMaster;
  
+ /* Dithering types */
+ #define DITHER_NONE 0 /*Quantize to nearest color*/
+ #define DITHER_BEST 1 /*Dither as well as possible*/
+ 
  /*
   * Bit definitions for the flags field of a PhotoMaster.
***************
*** 326,329 ****
--- 331,335 ----
  #define DEF_PHOTO_PALETTE	""
  #define DEF_PHOTO_WIDTH		"0"
+ #define DEF_PHOTO_DITHER        "1"
  
  /*
***************
*** 341,344 ****
--- 347,352 ----
      {TK_CONFIG_INT, "-width", (char *) NULL, (char *) NULL,
  	 DEF_PHOTO_WIDTH, Tk_Offset(PhotoMaster, userWidth), 0},
+     {TK_CONFIG_INT, "-dither", (char *) NULL, (char *) NULL,
+ 	 DEF_PHOTO_DITHER, Tk_Offset(PhotoMaster, dither), 0},
      {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  	 (char *) NULL, 0, 0}
***************
*** 3734,3743 ****
      pitch = masterPtr->width * 4;
  
!     /*
!      * This test is probably too restrictive.  We should also be able to
!      * do a memcpy if pixelSize == 3 and alphaOffset == 0.  Maybe other cases
!      * too.
!      */
!     if ((blockPtr->pixelSize == 4)
  	    && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3)
  	    && (width <= blockPtr->width) && (height <= blockPtr->height)
--- 3742,3746 ----
      pitch = masterPtr->width * 4;
  
!     if ((blockPtr->pixelSize == 4)    /*Memcpy case*/
  	    && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3)
  	    && (width <= blockPtr->width) && (height <= blockPtr->height)
***************
*** 3747,3751 ****
  		(VOID *) (blockPtr->pixelPtr + blockPtr->offset[0]),
  		(size_t) (height * width * 4));
!     } else {
  	for (hLeft = height; hLeft > 0;) {
  	    srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
--- 3750,3754 ----
  		(VOID *) (blockPtr->pixelPtr + blockPtr->offset[0]),
  		(size_t) (height * width * 4));
!     } else { /*General case*/
  	for (hLeft = height; hLeft > 0;) {
  	    srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
***************
*** 3755,3766 ****
  		destPtr = destLinePtr;
  		for (wLeft = width; wLeft > 0;) {
  		    wCopy = MIN(wLeft, blockPtr->width);
  		    wLeft -= wCopy;
  		    srcPtr = srcLinePtr;
! 		    for (; wCopy > 0; --wCopy) {
! 		      if (!destPtr[3]) {
! 			destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
  		      }
! 		      if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
  			*destPtr++ = srcPtr[0];
  			*destPtr++ = srcPtr[greenOffset];
--- 3758,3779 ----
  		destPtr = destLinePtr;
  		for (wLeft = width; wLeft > 0;) {
+ 		    int pixelSize=blockPtr->pixelSize;
  		    wCopy = MIN(wLeft, blockPtr->width);
  		    wLeft -= wCopy;
  		    srcPtr = srcLinePtr;
! 		    if (!alphaOffset)
! 		      /*Fast non-alpha case*/
! 		      for (; wCopy > 0; --wCopy) {
! 			*destPtr++ = srcPtr[0];
! 			*destPtr++ = srcPtr[greenOffset];
! 			*destPtr++ = srcPtr[blueOffset];
! 			*destPtr++ = 255;
! 		        srcPtr += pixelSize;
  		      }
! 		    else
! 		    /*Alpha case*/
! 		    for (; wCopy > 0; --wCopy) {
! 		      if (srcPtr[alphaOffset] == 255) {
! 			/*Opaque pixel*/
  			*destPtr++ = srcPtr[0];
  			*destPtr++ = srcPtr[greenOffset];
***************
*** 3768,3780 ****
  			*destPtr++ = 255;
  		      } else {
! 			if (srcPtr[alphaOffset]) {
  			    destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
  			    destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
  			    destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
  			    destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
! 		  	}
  			destPtr+=4;
  		      }
! 		      srcPtr += blockPtr->pixelSize;
  		    }
  		}
--- 3781,3797 ----
  			*destPtr++ = 255;
  		      } else {
! 			/*Semitransparent pixel*/
! 			if (!destPtr[3]) { /*Initialize background to grey*/
! 			  destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
! 			}
! 			if (srcPtr[alphaOffset]) { /*Perform alpha blending*/
  			    destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
  			    destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
  			    destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
  			    destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
! 			}
  			destPtr+=4;
  		      }
! 		      srcPtr += pixelSize;
  		    }
  		}
***************
*** 4010,4016 ****
  		for (; wCopy > 0; wCopy -= zoomX) {
  		    for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) {
- 		      if (!destPtr[3]) {
- 			destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
- 		      }
  		      if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
  			*destPtr++ = srcPtr[0];
--- 4027,4030 ----
***************
*** 4019,4022 ****
--- 4033,4039 ----
  			*destPtr++ = 255;
  		      } else {
+ 		        if (!destPtr[3]) {
+ 			  destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
+ 		        }
  			if (srcPtr[alphaOffset]) {
  			    destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
***************
*** 4194,4197 ****
--- 4211,4490 ----
   */
  
+ 
+ /*PixelWrite routines:
+ These are (possibly accellerated) versions of XPutPixel,
+ used by the dithered write routines below.
+ */
+ #define PIX_WRITE_ARGS (dest,dx,val,args) \
+ 	unsigned char *dest;/*Destination image data (start of row)*/ \
+ 	int dx; /*Pixel number in output image (pixels)*/ \
+ 	pixel val;/*Destination pixel value (redValues+greenValues+blueValues)*/ \
+ 	const DitherRow_argBlock *args;
+ typedef void (*PixWrite_t)(/*...*/);
+ 
+ typedef struct {
+ 	int errWid;/*Width of an error image line*/
+ 	int yStart,xStart;/*Location of dither block topleft in master image*/
+ 	int y;/*Location of dither line in master image*/
+ 	const PhotoInstance *instancePtr;
+ 	PixWrite_t PixWrite;/*Pixel writing function*/
+ 	const ColorTable *colorPtr;
+ 	const pixel *rv,*gv,*bv;/*Map 8-bit color channels to pixel values*/
+ 	const unsigned long *map;/*Maps pixel values to color indices (can be NULL)*/
+ } DitherRow_argBlock;
+ 
+ static void PixWrite_X PIX_WRITE_ARGS
+ {
+ 	XPutPixel(args->instancePtr->imagePtr,dx,args->y-args->yStart,(unsigned)val);
+ }
+ static void PixWrite_X_map PIX_WRITE_ARGS
+ {
+ 	XPutPixel(args->instancePtr->imagePtr,dx,args->y-args->yStart,
+ 		(unsigned)args->map[val]);
+ }
+ static void PixWrite_char_map PIX_WRITE_ARGS
+ {
+ 	dest[dx]=(unsigned char)args->map[val];
+ }
+ static void PixWrite_char PIX_WRITE_ARGS
+ {
+ 	dest[dx]=(unsigned char)val;
+ }
+ static void PixWrite_short PIX_WRITE_ARGS
+ {
+ 	((short *)dest)[dx]=(short)val;
+ }
+ static void PixWrite_int PIX_WRITE_ARGS
+ {
+ 	((int *)dest)[dx]=(int)val;
+ }
+ 
+ /************************************
+ DitherRow routines:
+ These convert a single contiguous row of source pixels
+ (unsigned char R G B A format) to a contiguous row of destination
+ pixels (the X screen pixel format; varies).  
+ 
+ They are passed pointers to the first source pixel to convert,
+ the dither error accumulator, and the destination pixel array.
+ */
+ 
+ #define DITHER_ROW_ARGS (src, err, dst,xFirst,xLast,args)\
+ 	const unsigned char *src;/*32-bit source image */ \
+ 	schar *err; /*Dither error image & line length (pixels)*/ \
+ 	unsigned char *dst;  /*Destination pixels*/ \
+ 	int xFirst,xLast;  /* first and last pixels to dither*/ \
+ 	const DitherRow_argBlock *args;
+ typedef void (*DitherRow_t)(/*...*/);
+ 
+ /**************** Floyd-Steinberg dithering routines ***************/
+ /* Propagates quantization errors below and to the right.
+  *
+  * Compute the error propagated into this pixel
+  * for this component.
+  * If e[x,y] is the array of quantization error
+  * values, we compute
+  *     7/16 * e[x-1,y] + 1/16 * e[x-1,y-1]
+  *   + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1]
+  * and round it to an integer.
+  *
+  * The expression ((c + 2056) >> 4) - 128
+  * computes round(c / 16), and works correctly on
+  * machines without a sign-extending right shift.
+  */
+ static void DitherRow_color_fs_boundary DITHER_ROW_ARGS
+ {/*Version including boundary tests*/
+ 	int col[3];
+ 	int i,x,lineLength=args->errWid*3;
+ 	for (x = xFirst; x < xLast; ++x) {
+ 		for (i = 0; i < 3; ++i) {
+ 			register int c = (x > 0) ? err[-3] * 7: 0;
+ 			if (args->y > 0) {
+ 				if (x > 0) {
+ 					c += err[-lineLength-3];
+ 				}
+ 				c += err[-lineLength] * 5;
+ 				if ((x + 1) < args->errWid) {
+ 					c += err[-lineLength+3] * 3;
+ 				}
+ 			}
+ 			c = ((c + 2056) >> 4) - 128 + *src++;
+ 			if (c < 0) c = 0;
+ 			if (c > 255) c = 255;
+ 
+ 			col[i] = args->colorPtr->colorQuant[i][c];
+ 			*err++ = c - col[i];
+ 		}
+ 		src++; /*Skip input alpha channel*/
+ 
+ 		/*Write the quantized colors into image*/
+ 		args->PixWrite(dst,x-args->xStart,
+ 		    args->rv[col[0]] + args->gv[col[1]] + args->bv[col[2]],args);
+ 	}
+ }
+ 
+ static void DitherRow_color_fs_interior DITHER_ROW_ARGS
+ {/*Version without boundary tests-- approximately twice as fast
+    as the boundary case; and hence used in interior of dither region.*/
+ 	int col[3];
+ 	int i,x,lineLength=args->errWid*3;
+ 	const ColorTable *colorPtr=args->colorPtr;
+ 	for (x = xFirst; x < xLast; ++x) {
+ 		for (i = 0; i < 3; ++i) {
+ 			register int c = err[-3]*7+err[-lineLength-3]+
+ 			   err[-lineLength]*5 +err[-lineLength+3]*3;
+ 			
+ 			c = ((c + 2056) >> 4) - 128 + *src++;
+ 			if (c < 0) c = 0;
+ 			if (c > 255) c = 255;
+ 			
+ 			col[i] = colorPtr->colorQuant[i][c];
+ 			*err++ = c - col[i];
+ 		}
+ 		src++; /*Skip input alpha channel*/
+ 		
+ 		/* Write the quantized component values into image. */
+ 		args->PixWrite(dst,x-args->xStart,
+ 		    args->rv[col[0]] + args->gv[col[1]] + args->bv[col[2]],args);
+ 	}
+ }
+ 
+ /*Dithering for greyscale display-- we convert color RGB to greyscale with
+  * grey=red*11/32+green*1/2+blue*5/32, computed as the horrific bitshift below.
+  */
+ static void DitherRow_grey_fs DITHER_ROW_ARGS
+ {
+ 	int col;
+ 	int x,lineLength=args->errWid*3;
+ 	for (x = xFirst; x < xLast; ++x) {
+ 		register int c = (x > 0) ? err[-1] * 7: 0;
+ 		if (args->y > 0) {
+ 			if (x > 0) {
+ 				c += err[-lineLength-1];
+ 			}
+ 			c += err[-lineLength] * 5;
+ 			if ((x + 1) < args->errWid) {
+ 				c += err[-lineLength+1] * 3;
+ 			}
+ 		}
+ 		c = ((c + 2056) >> 4) - 128;
+ 		if ((args->instancePtr->masterPtr->flags & COLOR_IMAGE) == 0)
+ 			c += src[0];
+ 		else
+ 			c += (unsigned)(src[0] * 11 + src[1] * 16
+ 			                + src[2] * 5 + 16) >> 5;
+ 		if (c < 0) c = 0;
+ 		if (c > 255) c = 255;
+ 		
+ 		col = args->colorPtr->colorQuant[0][c];
+ 		*err++ = c - col;
+ 		
+ 		src+=4; /*Skip to next pixel*/
+ 
+ 		/*Write the quantized colors into image*/
+ 		args->PixWrite(dst,x-args->xStart,args->rv[col],args);
+ 	}
+ }
+ 
+ /******************* Non-dithering conversion routines *********************/
+ /*These routines perform no dithering.
+ This is quite fast; but ugly for photographs (and other continuous-tone images).
+ However, toolbars and other flat-color images may look better this way.
+ */
+ /*Convert for 32-bit (ARGB) color window, gamma==1.0; no dithering performed.*/
+ static void DitherRow_intNoGamma_none DITHER_ROW_ARGS
+ {
+ 	int x=xLast-xFirst;
+ 	for ( ;x>0;--x) {
+ 		unsigned int i=(src[0]<<16)+(src[1]<<8)+src[2];
+ 		*((int *)dst)++=i;
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ }
+ /*Convert for 32-bit (ARGB) color window; no dithering performed.*/
+ static void DitherRow_int_none DITHER_ROW_ARGS
+ {
+ 	int x=xLast-xFirst;
+ 	register const pixel *rv=args->rv;
+ 	register const pixel *gv=args->gv;
+ 	register const pixel *bv=args->bv;
+ 	for ( ;x>0;--x) {
+ 		unsigned int i=rv[src[0]]+gv[src[1]]+bv[src[2]];
+ 		*((int *)dst)++=i;
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ }
+ /*Convert for 16-bit (or 15 bit) color window; no dithering performed.*/
+ static void DitherRow_short_none DITHER_ROW_ARGS
+ {
+ 	int x=xLast-xFirst;
+ 	register const pixel *rv=args->rv;
+ 	register const pixel *gv=args->gv;
+ 	register const pixel *bv=args->bv;
+ 	for ( ;x>0;--x) {
+ 		unsigned int i=rv[src[0]]+gv[src[1]]+bv[src[2]];
+ 		*((short *)dst)++=i;
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ }
+ /*Convert for 8-bit pseudocolor window; no dithering performed.*/
+ static void DitherRow_charMap_none DITHER_ROW_ARGS
+ {
+ 	int x=xLast-xFirst;
+ 	register const pixel *rv=args->rv;
+ 	register const pixel *gv=args->gv;
+ 	register const pixel *bv=args->bv;
+ 	register const unsigned long *map=args->map;
+ 	for ( ;x>0;--x) {
+ 		*dst++=map[ rv[src[0]]+gv[src[1]]+bv[src[2]] ];
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ }
+ /*Convert for 8-bit non-pseudocolor window; no dithering performed.*/
+ static void DitherRow_char_none DITHER_ROW_ARGS
+ {
+ 	int x=xLast-xFirst;
+ 	register const pixel *rv=args->rv;
+ 	register const pixel *gv=args->gv;
+ 	register const pixel *bv=args->bv;
+ 	for ( ;x>0;--x) {
+ 		*dst++=rv[src[0]]+gv[src[1]]+bv[src[2]];
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ }
+ /*Convert unusual color window; no dithering performed.*/
+ static void DitherRow_unknown_none DITHER_ROW_ARGS
+ {
+ 	int x;
+ 	register const pixel *rv=args->rv;
+ 	register const pixel *gv=args->gv;
+ 	register const pixel *bv=args->bv;
+ 	for (x=xFirst;x<xLast;++x) {
+ 		pixel val=rv[src[0]]+gv[src[1]]+bv[src[2]];
+ 		args->PixWrite(dst,x-args->xStart,val,args);
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ }
+ /*Convert greyscale window; no dithering performed.*/
+ static void DitherRow_grey_none DITHER_ROW_ARGS
+ {
+ 	int x;
+ 	register const pixel *rv=args->rv;
+ 	if ((args->instancePtr->masterPtr->flags & COLOR_IMAGE) == 0)
+ 	/*Convert greyscale image*/
+ 	for (x=xFirst;x<xLast;++x) {
+ 		pixel val=rv[src[0]];
+ 		args->PixWrite(dst,x-args->xStart,val,args);
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ 	else /*Convert color image */	
+ 	for (x=xFirst;x<xLast;++x) {
+ 		pixel val=rv[(src[0]*11+src[1]*16+src[2]*5+16)>>5];
+ 		args->PixWrite(dst,x-args->xStart,val,args);
+ 		src+=4;/*Skip to next pixel*/
+ 	}
+ }
+ 
+ 
  static void
  DitherInstance(instancePtr, xStart, yStart, width, height)
***************
*** 4204,4220 ****
      ColorTable *colorPtr;
      XImage *imagePtr;
!     int nLines, bigEndian;
!     int i, c, x, y;
      int xEnd, yEnd;
!     int bitsPerPixel, bytesPerLine, lineLength;
!     unsigned char *srcLinePtr, *srcPtr;
!     schar *errLinePtr, *errPtr;
!     unsigned char *destBytePtr, *dstLinePtr;
!     pixel *destLongPtr;
!     pixel firstBit, word, mask;
!     int col[3];
      int doDithering = 1;
  
!     colorPtr = instancePtr->colorTablePtr;
      masterPtr = instancePtr->masterPtr;
  
--- 4497,4524 ----
      ColorTable *colorPtr;
      XImage *imagePtr;
!     int nLines;
!     int y;
      int xEnd, yEnd;
!     int bitsPerPixel, bytesPerLine;
!     unsigned char *srcPtr;
!     schar *errPtr;
!     unsigned char *dstBytePtr, *dstStartPtr;
!     
      int doDithering = 1;
+     /*Function pointer to do the dithering*/
+     DitherRow_t DitherRow=NULL,DitherRow_boundary=NULL;
+     
+     /*Unchanging arguments to dithering function*/
+     DitherRow_argBlock args;
  
!     args.errWid=instancePtr->masterPtr->width;
!     args.xStart=xStart;args.yStart=yStart;
!     args.instancePtr = instancePtr;
!     args.colorPtr = colorPtr = instancePtr->colorTablePtr;
!     args.rv=colorPtr->redValues;
!     args.gv=colorPtr->greenValues;
!     args.bv=colorPtr->blueValues;
!     args.map=NULL;
!     if (colorPtr->flags & MAP_COLORS) args.map=colorPtr->pixelMap;
      masterPtr = instancePtr->masterPtr;
  
***************
*** 4235,4239 ****
  	}
      }
! 
      /*
       * First work out how many lines to do at a time,
--- 4539,4543 ----
  	}
      }
!         
      /*
       * First work out how many lines to do at a time,
***************
*** 4260,4502 ****
      imagePtr->bytes_per_line = bytesPerLine;
      imagePtr->data = (char *) ckalloc((unsigned) (imagePtr->bytes_per_line * nLines));
!     bigEndian = imagePtr->bitmap_bit_order == MSBFirst;
!     firstBit = bigEndian? (1 << (imagePtr->bitmap_unit - 1)): 1;
! 
!     lineLength = masterPtr->width * 3;
!     srcLinePtr = masterPtr->pix24 + (yStart * masterPtr->width + xStart) * 4;
!     errLinePtr = instancePtr->error + yStart * lineLength + xStart * 3;
!     xEnd = xStart + width;
! 
      /*
       * Loop over the image, doing at most nLines lines before
       * updating the screen image.
       */
! 
      for (; height > 0; height -= nLines) {
  	if (nLines > height) {
  	    nLines = height;
  	}
- 	dstLinePtr = (unsigned char *) imagePtr->data;
  	yEnd = yStart + nLines;
  	for (y = yStart; y < yEnd; ++y) {
! 	    srcPtr = srcLinePtr;
! 	    errPtr = errLinePtr;
! 	    destBytePtr = dstLinePtr;
! 	    destLongPtr = (pixel *) dstLinePtr;
! 	    if (colorPtr->flags & COLOR_WINDOW) {
! 		/*
! 		 * Color window.  We dither the three components
! 		 * independently, using Floyd-Steinberg dithering,
! 		 * which propagates errors from the quantization of
! 		 * pixels to the pixels below and to the right.
! 		 */
! 
! 		for (x = xStart; x < xEnd; ++x) {
! 		    if (doDithering) {
! 			for (i = 0; i < 3; ++i) {
! 			    /*
! 			     * Compute the error propagated into this pixel
! 			     * for this component.
! 			     * If e[x,y] is the array of quantization error
! 			     * values, we compute
! 			     *     7/16 * e[x-1,y] + 1/16 * e[x-1,y-1]
! 			     *   + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1]
! 			     * and round it to an integer.
! 			     *
! 			     * The expression ((c + 2056) >> 4) - 128
! 			     * computes round(c / 16), and works correctly on
! 			     * machines without a sign-extending right shift.
! 			     */
! 			    
! 			    c = (x > 0) ? errPtr[-3] * 7: 0;
! 			    if (y > 0) {
! 				if (x > 0) {
! 				    c += errPtr[-lineLength-3];
! 				}
! 				c += errPtr[-lineLength] * 5;
! 				if ((x + 1) < masterPtr->width) {
! 				    c += errPtr[-lineLength+3] * 3;
! 				}
! 			    }
! 			    
! 			    /*
! 			     * Add the propagated error to the value of this
! 			     * component, quantize it, and store the
! 			     * quantization error.
! 			     */
! 			    
! 			    c = ((c + 2056) >> 4) - 128 + *srcPtr++;
! 			    if (c < 0) {
! 				c = 0;
! 			    } else if (c > 255) {
! 				c = 255;
! 			    }
! 			    col[i] = colorPtr->colorQuant[i][c];
! 			    *errPtr++ = c - col[i];
! 			}
! 		    } else {
! 			/* 
! 			 * Output is virtually continuous in this case,
! 			 * so don't bother dithering.
! 			 */
! 
! 			col[0] = *srcPtr++;
! 			col[1] = *srcPtr++;
! 			col[2] = *srcPtr++;
! 		    }
! 		    srcPtr++;
! 
! 		    /*
! 		     * Translate the quantized component values into
! 		     * an X pixel value, and store it in the image.
! 		     */
! 
! 		    i = colorPtr->redValues[col[0]]
! 			    + colorPtr->greenValues[col[1]]
! 			    + colorPtr->blueValues[col[2]];
! 		    if (colorPtr->flags & MAP_COLORS) {
! 			i = colorPtr->pixelMap[i];
! 		    }
! 		    switch (bitsPerPixel) {
! 			case NBBY:
! 			    *destBytePtr++ = i;
! 			    break;
! #ifndef __WIN32__
! /*
!  * This case is not valid for Windows because the image format is different
!  * from the pixel format in Win32.  Eventually we need to fix the image
!  * code in Tk to use the Windows native image ordering.  This would speed
!  * up the image code for all of the common sizes.
!  */
! 
! 			case NBBY * sizeof(pixel):
! 			    *destLongPtr++ = i;
! 			    break;
! #endif
! 			default:
! 			    XPutPixel(imagePtr, x - xStart, y - yStart,
! 				    (unsigned) i);
! 		    }
! 		}
! 
! 	    } else if (bitsPerPixel > 1) {
! 		/*
! 		 * Multibit monochrome window.  The operation here is similar
! 		 * to the color window case above, except that there is only
! 		 * one component.  If the master image is in color, use the
! 		 * luminance computed as
! 		 *	0.344 * red + 0.5 * green + 0.156 * blue.
! 		 */
! 
! 		for (x = xStart; x < xEnd; ++x) {
! 		    c = (x > 0) ? errPtr[-1] * 7: 0;
! 		    if (y > 0) {
! 			if (x > 0)  {
! 			    c += errPtr[-lineLength-1];
! 			}
! 			c += errPtr[-lineLength] * 5;
! 			if (x + 1 < masterPtr->width) {
! 			    c += errPtr[-lineLength+1] * 3;
! 			}
! 		    }
! 		    c = ((c + 2056) >> 4) - 128;
! 
! 		    if ((masterPtr->flags & COLOR_IMAGE) == 0) {
! 			c += srcPtr[0];
! 		    } else {
! 			c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
! 					+ srcPtr[2] * 5 + 16) >> 5;
! 		    }
! 		    srcPtr += 4;
! 
! 		    if (c < 0) {
! 			c = 0;
! 		    } else if (c > 255) {
! 			c = 255;
! 		    }
! 		    i = colorPtr->colorQuant[0][c];
! 		    *errPtr++ = c - i;
! 		    i = colorPtr->redValues[i];
! 		    switch (bitsPerPixel) {
! 			case NBBY:
! 			    *destBytePtr++ = i;
! 			    break;
! #ifndef __WIN32__
! /*
!  * This case is not valid for Windows because the image format is different
!  * from the pixel format in Win32.  Eventually we need to fix the image
!  * code in Tk to use the Windows native image ordering.  This would speed
!  * up the image code for all of the common sizes.
!  */
! 
! 			case NBBY * sizeof(pixel):
! 			    *destLongPtr++ = i;
! 			    break;
! #endif
! 			default:
! 			    XPutPixel(imagePtr, x - xStart, y - yStart,
! 				    (unsigned) i);
! 		    }
! 		}
! 	    } else {
! 		/*
! 		 * 1-bit monochrome window.  This is similar to the
! 		 * multibit monochrome case above, except that the
! 		 * quantization is simpler (we only have black = 0
! 		 * and white = 255), and we produce an XY-Bitmap.
! 		 */
! 
! 		word = 0;
! 		mask = firstBit;
! 		for (x = xStart; x < xEnd; ++x) {
! 		    /*
! 		     * If we have accumulated a whole word, store it
! 		     * in the image and start a new word.
! 		     */
! 
! 		    if (mask == 0) {
! 			*destLongPtr++ = word;
! 			mask = firstBit;
! 			word = 0;
! 		    }
! 
! 		    c = (x > 0) ? errPtr[-1] * 7: 0;
! 		    if (y > 0) {
! 			if (x > 0) {
! 			    c += errPtr[-lineLength-1];
! 			}
! 			c += errPtr[-lineLength] * 5;
! 			if (x + 1 < masterPtr->width) {
! 			    c += errPtr[-lineLength+1] * 3;
! 			}
! 		    }
! 		    c = ((c + 2056) >> 4) - 128;
! 
! 		    if ((masterPtr->flags & COLOR_IMAGE) == 0) {
! 			c += srcPtr[0];
! 		    } else {
! 			c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
! 					+ srcPtr[2] * 5 + 16) >> 5;
! 		    }
! 		    srcPtr += 4;
! 
! 		    if (c < 0) {
! 			c = 0;
! 		    } else if (c > 255) {
! 			c = 255;
! 		    }
! 		    if (c >= 128) {
! 			word |= mask;
! 			*errPtr++ = c - 255;
! 		    } else {
! 			*errPtr++ = c;
! 		    }
! 		    mask = bigEndian? (mask >> 1): (mask << 1);
! 		}
! 		*destLongPtr = word;
! 	    }
! 	    srcLinePtr += masterPtr->width * 4;
! 	    errLinePtr += lineLength;
! 	    dstLinePtr += bytesPerLine;
  	}
  
--- 4564,4655 ----
      imagePtr->bytes_per_line = bytesPerLine;
      imagePtr->data = (char *) ckalloc((unsigned) (imagePtr->bytes_per_line * nLines));
!     
!     /*Figure out the pixel-writing function*/
!     switch(bitsPerPixel) {
!     	case NBBY*sizeof(int): args.PixWrite=PixWrite_int; break;
!     	case NBBY*sizeof(short): args.PixWrite=PixWrite_short; break;
!     	case NBBY*sizeof(char):
!     	         if (colorPtr->flags & MAP_COLORS)
!     	               args.PixWrite=PixWrite_char_map; 
!     	         else  args.PixWrite=PixWrite_char;
!     	         break;
!     	default: /*Strange depths use slow general X conversion*/
!     	         if (colorPtr->flags & MAP_COLORS)
!     	               args.PixWrite=PixWrite_X_map; 
!     	         else  args.PixWrite=PixWrite_X;
!     	         break;
!     };
!     
!     /*Figure out which dithering function to use*/
!     if (doDithering && masterPtr->dither==DITHER_BEST)
!     {/*Use Floyd-Steinberg error diffusion dithering*/
!     	if (colorPtr->flags & COLOR_WINDOW) {
!     	/*Color window*/
!     		DitherRow=DitherRow_color_fs_interior;
!     		DitherRow_boundary=DitherRow_color_fs_boundary;
!     	} else {
!     	/*Greyscale window*/
!     		DitherRow=DitherRow_grey_fs;
!     	}
!     } else {
!     	/*No dithering-- nearest color conversion*/
!     	if (!(colorPtr->flags & COLOR_WINDOW))
!     	     DitherRow=DitherRow_grey_none;
!     	else /*Color window*/
!     	switch(bitsPerPixel) {
!     	case NBBY*sizeof(int): 
!     		if (colorPtr->id.gamma==1.0)
!     			DitherRow=DitherRow_intNoGamma_none;/*Fastest possible case*/
!     		else DitherRow=DitherRow_int_none; 
!     		break;
!     	case NBBY*sizeof(short): DitherRow=DitherRow_short_none; break;
!     	case NBBY*sizeof(char):  
!     	        if (colorPtr->flags & MAP_COLORS)
!     	             DitherRow=DitherRow_charMap_none; 
!     	        else DitherRow=DitherRow_char_none;
!     	        break;
!     	default: /*Strange depths use slow general conversion*/
!     	        DitherRow=DitherRow_unknown_none;break;
!     	};
!     }
!  
      /*
       * Loop over the image, doing at most nLines lines before
       * updating the screen image.
       */
!     dstStartPtr = (unsigned char *) imagePtr->data;
!     xEnd = xStart + width;
      for (; height > 0; height -= nLines) {
  	if (nLines > height) {
  	    nLines = height;
  	}
  	yEnd = yStart + nLines;
+ 	
  	for (y = yStart; y < yEnd; ++y) {
! 	  args.y=y;
! 	  srcPtr = masterPtr->pix24 + 4*(y*masterPtr->width);
! 	  errPtr = instancePtr->error + 3*(y*masterPtr->width);
! 	  dstBytePtr = dstStartPtr+((y-yStart)*bytesPerLine);
! 	  if (DitherRow_boundary==NULL) /*No special boundary conditions needed*/
! 	     DitherRow(srcPtr+4*xStart, errPtr+3*xStart, dstBytePtr,
! 	       xStart,xEnd,&args);
! 	  else
! 	  { /*Special (slower) boundary case (needed for fast floyd-steinberg dithering)*/
!             int iStart=xStart,iEnd=xEnd; /*Start and end of interior region*/
!             
!             if (xStart<=0) iStart=1;
!             if (xEnd>=masterPtr->width) iEnd=masterPtr->width-1;
!             if (y<=1) iStart=iEnd=0;/*No interior for top line*/
!             
!             if (xStart!=iStart) /*Left boundary*/
! 	      DitherRow_boundary(srcPtr+4*xStart, errPtr+3*xStart, dstBytePtr,
! 	        xStart,iStart,&args);
! 	    if (iStart!=iEnd) /*Interior*/
! 	      DitherRow(srcPtr+4*iStart, errPtr+3*iStart, dstBytePtr,
! 	        iStart,iEnd,&args);
! 	    if (iEnd!=xEnd) /*Right boundary*/
! 	      DitherRow_boundary(srcPtr+4*iEnd, errPtr+3*iEnd, dstBytePtr,
! 	        iEnd,xEnd,&args);
! 	  }
  	}
  
