Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 8 May 2006 18:24:53 +1000 (EST)
From:      Peter Jeremy <peterjeremy@optushome.com.au>
To:        FreeBSD-gnats-submit@FreeBSD.org
Cc:        peter@vk2pj.dyndns.org
Subject:   ports/96971: [patch] graphics/xv incorrectly handles xwd files
Message-ID:  <200605080824.k488Orpv001057@turion.vk2pj.dyndns.org>
Resent-Message-ID: <200605080830.k488U9OZ037119@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         96971
>Category:       ports
>Synopsis:       [patch] graphics/xv incorrectly handles xwd files
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-ports-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon May 08 08:30:08 GMT 2006
>Closed-Date:
>Last-Modified:
>Originator:     Peter Jeremy
>Release:        FreeBSD 6.1-STABLE amd64
>Organization:
n/a
>Environment:
System: FreeBSD turion.vk2pj.dyndns.org 6.1-STABLE FreeBSD 6.1-STABLE #9: Mon May 8 12:06:14 EST 2006 root@turion.vk2pj.dyndns.org:/usr/obj/usr/src/sys/turion amd64
xv-3.10a_5

>Description:
	With 24/32-bit xwd files, xv swaps the red and blue channels.
	With 16-bit xwd files, the image is very dark green (almost black).

	Both problems are caused by hard-coding the channel order and
	offsets, rather than using the colour masks in the xwd header.

	xv reads the input into a 24-bit internal image, which is then
	displayed.  The lack of brightness in the 16-bit display is
	because the colour values are copied into the low-order bits of
	the internal pixmap rather than the high order bits.  The green
	hue is because the green channel has 6 bits, whereas red and
	blue only have 5 bits, making the green twice as (relatively)
	bright.
	
	Thanks to Callum Gibson for initial pointers to the bug as well
	as 16-bit dumps.

>How-To-Repeat:
	Do a window or screen dump using xwd from a 24/32-bit TrueColor
	display.  Display the screen dump using xv.

	Do a window or screen dump using xwd from a 16-bit TrueColor
	display.  Display the screen dump using xv.

>Fix:

	The following patch replaces the byte-swap routines as well - I
	initially suspected that the problem was at least partially
	caused by the non-portability of "union cheat".  Whilst that was
	not a problem, the resultant code is cleaner and I did not want
	to expend further effort removing the change.

	Rather than hard-coding the shift values (and the mask for 24-bit
	colour), the shift value is calculated from the mask during
	initialisation.  Since the low colour bits must be shifted left
	whilst all other shifts are right, each pixel colour is shifted
	so the MSB of the colour is in bit 31 and then shifted right 24
	bits to correctly locate the colour in an 8-bit field.
	
--- xvxwd.c~	Sat May  6 07:29:07 2006
+++ xvxwd.c	Sat May  6 17:24:12 2006
@@ -19,7 +19,7 @@
  */
 
 #include "xv.h"
-
+#include <sys/endian.h>
 
 /***************************** x11wd.h *****************************/
 #define X11WD_FILE_VERSION 7
@@ -66,23 +66,25 @@
 
 typedef byte pixel;
 
+#define    bs_short(x)	bswap16(x)
+#define    bs_long(x)	bswap32(x)
+
 /* local functions */
 static int    getinit         PARM((FILE *, int*, int*, int*, CARD32 *, 
 			                          CARD32, PICINFO *));
 static CARD32 getpixnum       PARM((FILE *));
 static int    xwdError        PARM((char *));
 static void   xwdWarning      PARM((char *));
-static int    bs_short        PARM((int));
-static CARD32 bs_long         PARM((CARD32));
 static int    readbigshort    PARM((FILE *, CARD16 *));
 static int    readbiglong     PARM((FILE *, CARD32 *));
 static int    readlittleshort PARM((FILE *, CARD16 *));
 static int    readlittlelong  PARM((FILE *, CARD32 *));
 static int    writebigshort   PARM((FILE *, int));
 static int    writebiglong    PARM((FILE *, CARD32));
-
+static int    get_shift       PARM((CARD32));
 static byte  *pic8, *pic24;
 static CARD32 red_mask, green_mask, blue_mask;
+static int    red_shift, green_shift, blue_shift;
 static int    bits_per_item, bits_used, bit_shift, bits_per_pixel;
 static char   buf[4];
 static char   *byteP;
@@ -181,24 +183,9 @@
 	CARD32 ul;
 	
 	ul = getpixnum(ifp);
-	switch (bits_per_pixel) {
-	case 16:
-	  *xP++ = ((ul & red_mask)   >> 0);
-	  *xP++ = ((ul & green_mask) >> 5);
-	  *xP++ = ((ul & blue_mask)  >> 10);
-	  break;
-	  
-	case 24:
-	case 32:
-	  *xP++ = (ul    ) & 0xff;
-	  *xP++ = (ul>> 8) & 0xff;
-	  *xP++ = (ul>>16) & 0xff;
-	  break;
-	  
-	default:
-	  xwdError("True/Direct only supports 16, 24, and 32 bits");
-	  return 0;
-	}
+	*xP++ = ((ul & red_mask)   << red_shift) >> 24;
+	*xP++ = ((ul & green_mask) << green_shift) >> 24;
+	*xP++ = ((ul & blue_mask)  << blue_shift) >> 24;
       }
 
       for (col=0; col<padright; col++) getpixnum(ifp);
@@ -266,6 +253,8 @@
     byte_swap = 1;
     h11P->header_size      = bs_long(h11P->header_size);
     h11P->file_version     = bs_long(h11P->file_version);
+    if (h11P->file_version != X11WD_FILE_VERSION)
+	return(xwdError("unsupported X11 XWD file version"));
     h11P->pixmap_format    = bs_long(h11P->pixmap_format);
     h11P->pixmap_depth     = bs_long(h11P->pixmap_depth);
     h11P->pixmap_width     = bs_long(h11P->pixmap_width);
@@ -427,6 +416,10 @@
   green_mask = h11P->green_mask;
   blue_mask  = h11P->blue_mask;
 
+  red_shift   = get_shift(red_mask);
+  green_shift = get_shift(green_mask);
+  blue_shift  = get_shift(blue_mask);
+
   byteP  = (char   *) buf;
   shortP = (CARD16 *) buf;
   longP  = (CARD32 *) buf;
@@ -531,44 +524,6 @@
 
 
 /* 
- * Byte-swapping junk.
- */
-
-union cheat {
-  CARD32 l;
-  CARD16 s;
-  CARD8  c[sizeof(CARD32)];
-};
-
-static int bs_short(s)
-     int s;
-{
-  union cheat u;
-  unsigned char t;
-
-  u.s = (CARD16) s;
-  t = u.c[0];  u.c[0] = u.c[1];  u.c[1] = t;
-  return (int) u.s;
-}
-
-static CARD32 bs_long(l)
-     CARD32 l;
-{
-  union cheat u;
-  unsigned char t;
-  
-  u.l = l;
-  t = u.c[0];  u.c[0] = u.c[3];  u.c[3] = t;
-  t = u.c[1];  u.c[1] = u.c[2];  u.c[2] = t;
-  return u.l;
-}
-
-
-
-
-
-
-/* 
  * Endian I/O.
  */
 
@@ -642,4 +597,17 @@
   putc((s>>8)&0xff, out);
   putc(s&0xff, out);
   return 0;
+}
+
+
+static int get_shift(val)
+    CARD32 val;
+{
+    int		shift;
+
+    if (!val)
+	return (0);
+    for (shift = 0; !(val & 0x80000000); shift++)
+	val <<= 1;
+    return (shift);
 }



>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200605080824.k488Orpv001057>