ports/96971: [patch] graphics/xv incorrectly handles xwd files
Peter Jeremy
peterjeremy at optushome.com.au
Mon May 8 08:30:10 UTC 2006
>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 at 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:
More information about the freebsd-ports-bugs
mailing list