xref: /plan9-contrib/sys/src/cmd/gs/src/gsflip.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gsflip.c,v 1.5 2002/06/16 05:48:55 lpd Exp $ */
187dd7cddfSDavid du Colombier /* Routines for "flipping" image data */
197dd7cddfSDavid du Colombier #include "gx.h"
207dd7cddfSDavid du Colombier #include "gserrors.h"		/* for rangecheck in sample macros */
217dd7cddfSDavid du Colombier #include "gsbitops.h"
227dd7cddfSDavid du Colombier #include "gsbittab.h"
237dd7cddfSDavid du Colombier #include "gsflip.h"
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier #define ARCH_HAS_BYTE_REGS 1
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier /* Transpose a block of bits between registers. */
287dd7cddfSDavid du Colombier #define TRANSPOSE(r,s,mask,shift)\
297dd7cddfSDavid du Colombier   r ^= (temp = ((s >> shift) ^ r) & mask);\
307dd7cddfSDavid du Colombier   s ^= temp << shift
317dd7cddfSDavid du Colombier 
327dd7cddfSDavid du Colombier /* Define the size of byte temporaries.  On Intel CPUs, this should be */
337dd7cddfSDavid du Colombier /* byte, but on all other CPUs, it should be uint. */
347dd7cddfSDavid du Colombier #if ARCH_HAS_BYTE_REGS
357dd7cddfSDavid du Colombier typedef byte byte_var;
367dd7cddfSDavid du Colombier #else
377dd7cddfSDavid du Colombier typedef uint byte_var;
387dd7cddfSDavid du Colombier #endif
397dd7cddfSDavid du Colombier 
407dd7cddfSDavid du Colombier #define VTAB(v80,v40,v20,v10,v8,v4,v2,v1)\
417dd7cddfSDavid du Colombier   bit_table_8(0,v80,v40,v20,v10,v8,v4,v2,v1)
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier /* Convert 3Mx1 to 3x1. */
447dd7cddfSDavid du Colombier private int
flip3x1(byte * buffer,const byte ** planes,int offset,int nbytes)457dd7cddfSDavid du Colombier flip3x1(byte * buffer, const byte ** planes, int offset, int nbytes)
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier     byte *out = buffer;
487dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
497dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
507dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
517dd7cddfSDavid du Colombier     int n = nbytes;
527dd7cddfSDavid du Colombier     static const bits32 tab3x1[256] = {
537dd7cddfSDavid du Colombier 	VTAB(0x800000, 0x100000, 0x20000, 0x4000, 0x800, 0x100, 0x20, 4)
547dd7cddfSDavid du Colombier     };
557dd7cddfSDavid du Colombier 
567dd7cddfSDavid du Colombier     for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
577dd7cddfSDavid du Colombier 	bits32 b24 = tab3x1[*in1] | (tab3x1[*in2] >> 1) | (tab3x1[*in3] >> 2);
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier 	out[0] = (byte) (b24 >> 16);
607dd7cddfSDavid du Colombier 	out[1] = (byte) (b24 >> 8);
617dd7cddfSDavid du Colombier 	out[2] = (byte) b24;
627dd7cddfSDavid du Colombier     }
637dd7cddfSDavid du Colombier     return 0;
647dd7cddfSDavid du Colombier }
657dd7cddfSDavid du Colombier 
667dd7cddfSDavid du Colombier /* Convert 3Mx2 to 3x2. */
677dd7cddfSDavid du Colombier private int
flip3x2(byte * buffer,const byte ** planes,int offset,int nbytes)687dd7cddfSDavid du Colombier flip3x2(byte * buffer, const byte ** planes, int offset, int nbytes)
697dd7cddfSDavid du Colombier {
707dd7cddfSDavid du Colombier     byte *out = buffer;
717dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
727dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
737dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
747dd7cddfSDavid du Colombier     int n = nbytes;
757dd7cddfSDavid du Colombier     static const bits32 tab3x2[256] = {
767dd7cddfSDavid du Colombier 	VTAB(0x800000, 0x400000, 0x20000, 0x10000, 0x800, 0x400, 0x20, 0x10)
777dd7cddfSDavid du Colombier     };
787dd7cddfSDavid du Colombier 
797dd7cddfSDavid du Colombier     for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
807dd7cddfSDavid du Colombier 	bits32 b24 = tab3x2[*in1] | (tab3x2[*in2] >> 2) | (tab3x2[*in3] >> 4);
817dd7cddfSDavid du Colombier 
827dd7cddfSDavid du Colombier 	out[0] = (byte) (b24 >> 16);
837dd7cddfSDavid du Colombier 	out[1] = (byte) (b24 >> 8);
847dd7cddfSDavid du Colombier 	out[2] = (byte) b24;
857dd7cddfSDavid du Colombier     }
867dd7cddfSDavid du Colombier     return 0;
877dd7cddfSDavid du Colombier }
887dd7cddfSDavid du Colombier 
897dd7cddfSDavid du Colombier /* Convert 3Mx4 to 3x4. */
907dd7cddfSDavid du Colombier private int
flip3x4(byte * buffer,const byte ** planes,int offset,int nbytes)917dd7cddfSDavid du Colombier flip3x4(byte * buffer, const byte ** planes, int offset, int nbytes)
927dd7cddfSDavid du Colombier {
937dd7cddfSDavid du Colombier     byte *out = buffer;
947dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
957dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
967dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
977dd7cddfSDavid du Colombier     int n = nbytes;
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier     for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
1007dd7cddfSDavid du Colombier 	byte_var b1 = *in1, b2 = *in2, b3 = *in3;
1017dd7cddfSDavid du Colombier 
1027dd7cddfSDavid du Colombier 	out[0] = (b1 & 0xf0) | (b2 >> 4);
1037dd7cddfSDavid du Colombier 	out[1] = (b3 & 0xf0) | (b1 & 0xf);
1047dd7cddfSDavid du Colombier 	out[2] = (byte) (b2 << 4) | (b3 & 0xf);
1057dd7cddfSDavid du Colombier     }
1067dd7cddfSDavid du Colombier     return 0;
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier /* Convert 3Mx8 to 3x8. */
1107dd7cddfSDavid du Colombier private int
flip3x8(byte * buffer,const byte ** planes,int offset,int nbytes)1117dd7cddfSDavid du Colombier flip3x8(byte * buffer, const byte ** planes, int offset, int nbytes)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier     byte *out = buffer;
1147dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
1157dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
1167dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
1177dd7cddfSDavid du Colombier     int n = nbytes;
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier     for (; n > 0; out += 3, ++in1, ++in2, ++in3, --n) {
1207dd7cddfSDavid du Colombier 	out[0] = *in1;
1217dd7cddfSDavid du Colombier 	out[1] = *in2;
1227dd7cddfSDavid du Colombier 	out[2] = *in3;
1237dd7cddfSDavid du Colombier     }
1247dd7cddfSDavid du Colombier     return 0;
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier /* Convert 3Mx12 to 3x12. */
1287dd7cddfSDavid du Colombier private int
flip3x12(byte * buffer,const byte ** planes,int offset,int nbytes)1297dd7cddfSDavid du Colombier flip3x12(byte * buffer, const byte ** planes, int offset, int nbytes)
1307dd7cddfSDavid du Colombier {
1317dd7cddfSDavid du Colombier     byte *out = buffer;
1327dd7cddfSDavid du Colombier     const byte *pa = planes[0] + offset;
1337dd7cddfSDavid du Colombier     const byte *pb = planes[1] + offset;
1347dd7cddfSDavid du Colombier     const byte *pc = planes[2] + offset;
1357dd7cddfSDavid du Colombier     int n = nbytes;
1367dd7cddfSDavid du Colombier 
1377dd7cddfSDavid du Colombier     /*
1387dd7cddfSDavid du Colombier      * We assume that the input is an integral number of pixels, and
1397dd7cddfSDavid du Colombier      * round up n to a multiple of 3.
1407dd7cddfSDavid du Colombier      */
1417dd7cddfSDavid du Colombier     for (; n > 0; out += 9, pa += 3, pb += 3, pc += 3, n -= 3) {
1427dd7cddfSDavid du Colombier 	byte_var a1 = pa[1], b0 = pb[0], b1 = pb[1], b2 = pb[2], c1 = pc[1];
1437dd7cddfSDavid du Colombier 
1447dd7cddfSDavid du Colombier 	out[0] = pa[0];
1457dd7cddfSDavid du Colombier 	out[1] = (a1 & 0xf0) | (b0 >> 4);
1467dd7cddfSDavid du Colombier 	out[2] = (byte) ((b0 << 4) | (b1 >> 4));
1477dd7cddfSDavid du Colombier 	out[3] = pc[0];
1487dd7cddfSDavid du Colombier 	out[4] = (c1 & 0xf0) | (a1 & 0xf);
1497dd7cddfSDavid du Colombier 	out[5] = pa[2];
1507dd7cddfSDavid du Colombier 	out[6] = (byte) ((b1 << 4) | (b2 >> 4));
1517dd7cddfSDavid du Colombier 	out[7] = (byte) ((b2 << 4) | (c1 & 0xf));
1527dd7cddfSDavid du Colombier 	out[8] = pc[2];
1537dd7cddfSDavid du Colombier     }
1547dd7cddfSDavid du Colombier     return 0;
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier /* Convert 4Mx1 to 4x1. */
1587dd7cddfSDavid du Colombier private int
flip4x1(byte * buffer,const byte ** planes,int offset,int nbytes)1597dd7cddfSDavid du Colombier flip4x1(byte * buffer, const byte ** planes, int offset, int nbytes)
1607dd7cddfSDavid du Colombier {
1617dd7cddfSDavid du Colombier     byte *out = buffer;
1627dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
1637dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
1647dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
1657dd7cddfSDavid du Colombier     const byte *in4 = planes[3] + offset;
1667dd7cddfSDavid du Colombier     int n = nbytes;
1677dd7cddfSDavid du Colombier 
1687dd7cddfSDavid du Colombier     for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
1697dd7cddfSDavid du Colombier 	byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
1707dd7cddfSDavid du Colombier 	byte_var temp;
1717dd7cddfSDavid du Colombier 
1727dd7cddfSDavid du Colombier 	/* Transpose blocks of 1 */
1737dd7cddfSDavid du Colombier 	TRANSPOSE(b1, b2, 0x55, 1);
1747dd7cddfSDavid du Colombier 	TRANSPOSE(b3, b4, 0x55, 1);
1757dd7cddfSDavid du Colombier 	/* Transpose blocks of 2 */
1767dd7cddfSDavid du Colombier 	TRANSPOSE(b1, b3, 0x33, 2);
1777dd7cddfSDavid du Colombier 	TRANSPOSE(b2, b4, 0x33, 2);
1787dd7cddfSDavid du Colombier 	/* There's probably a faster way to do this.... */
1797dd7cddfSDavid du Colombier 	out[0] = (b1 & 0xf0) | (b2 >> 4);
1807dd7cddfSDavid du Colombier 	out[1] = (b3 & 0xf0) | (b4 >> 4);
1817dd7cddfSDavid du Colombier 	out[2] = (byte) ((b1 << 4) | (b2 & 0xf));
1827dd7cddfSDavid du Colombier 	out[3] = (byte) ((b3 << 4) | (b4 & 0xf));
1837dd7cddfSDavid du Colombier     }
1847dd7cddfSDavid du Colombier     return 0;
1857dd7cddfSDavid du Colombier }
1867dd7cddfSDavid du Colombier 
1877dd7cddfSDavid du Colombier /* Convert 4Mx2 to 4x2. */
1887dd7cddfSDavid du Colombier private int
flip4x2(byte * buffer,const byte ** planes,int offset,int nbytes)1897dd7cddfSDavid du Colombier flip4x2(byte * buffer, const byte ** planes, int offset, int nbytes)
1907dd7cddfSDavid du Colombier {
1917dd7cddfSDavid du Colombier     byte *out = buffer;
1927dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
1937dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
1947dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
1957dd7cddfSDavid du Colombier     const byte *in4 = planes[3] + offset;
1967dd7cddfSDavid du Colombier     int n = nbytes;
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier     for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
1997dd7cddfSDavid du Colombier 	byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
2007dd7cddfSDavid du Colombier 	byte_var temp;
2017dd7cddfSDavid du Colombier 
2027dd7cddfSDavid du Colombier 	/* Transpose blocks of 4x2 */
2037dd7cddfSDavid du Colombier 	TRANSPOSE(b1, b3, 0x0f, 4);
2047dd7cddfSDavid du Colombier 	TRANSPOSE(b2, b4, 0x0f, 4);
2057dd7cddfSDavid du Colombier 	/* Transpose blocks of 2x1 */
2067dd7cddfSDavid du Colombier 	TRANSPOSE(b1, b2, 0x33, 2);
2077dd7cddfSDavid du Colombier 	TRANSPOSE(b3, b4, 0x33, 2);
2087dd7cddfSDavid du Colombier 	out[0] = b1;
2097dd7cddfSDavid du Colombier 	out[1] = b2;
2107dd7cddfSDavid du Colombier 	out[2] = b3;
2117dd7cddfSDavid du Colombier 	out[3] = b4;
2127dd7cddfSDavid du Colombier     }
2137dd7cddfSDavid du Colombier     return 0;
2147dd7cddfSDavid du Colombier }
2157dd7cddfSDavid du Colombier 
2167dd7cddfSDavid du Colombier /* Convert 4Mx4 to 4x4. */
2177dd7cddfSDavid du Colombier private int
flip4x4(byte * buffer,const byte ** planes,int offset,int nbytes)2187dd7cddfSDavid du Colombier flip4x4(byte * buffer, const byte ** planes, int offset, int nbytes)
2197dd7cddfSDavid du Colombier {
2207dd7cddfSDavid du Colombier     byte *out = buffer;
2217dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
2227dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
2237dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
2247dd7cddfSDavid du Colombier     const byte *in4 = planes[3] + offset;
2257dd7cddfSDavid du Colombier     int n = nbytes;
2267dd7cddfSDavid du Colombier 
2277dd7cddfSDavid du Colombier     for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
2287dd7cddfSDavid du Colombier 	byte_var b1 = *in1, b2 = *in2, b3 = *in3, b4 = *in4;
2297dd7cddfSDavid du Colombier 
2307dd7cddfSDavid du Colombier 	out[0] = (b1 & 0xf0) | (b2 >> 4);
2317dd7cddfSDavid du Colombier 	out[1] = (b3 & 0xf0) | (b4 >> 4);
2327dd7cddfSDavid du Colombier 	out[2] = (byte) ((b1 << 4) | (b2 & 0xf));
2337dd7cddfSDavid du Colombier 	out[3] = (byte) ((b3 << 4) | (b4 & 0xf));
2347dd7cddfSDavid du Colombier     }
2357dd7cddfSDavid du Colombier     return 0;
2367dd7cddfSDavid du Colombier }
2377dd7cddfSDavid du Colombier 
2387dd7cddfSDavid du Colombier /* Convert 4Mx8 to 4x8. */
2397dd7cddfSDavid du Colombier private int
flip4x8(byte * buffer,const byte ** planes,int offset,int nbytes)2407dd7cddfSDavid du Colombier flip4x8(byte * buffer, const byte ** planes, int offset, int nbytes)
2417dd7cddfSDavid du Colombier {
2427dd7cddfSDavid du Colombier     byte *out = buffer;
2437dd7cddfSDavid du Colombier     const byte *in1 = planes[0] + offset;
2447dd7cddfSDavid du Colombier     const byte *in2 = planes[1] + offset;
2457dd7cddfSDavid du Colombier     const byte *in3 = planes[2] + offset;
2467dd7cddfSDavid du Colombier     const byte *in4 = planes[3] + offset;
2477dd7cddfSDavid du Colombier     int n = nbytes;
2487dd7cddfSDavid du Colombier 
2497dd7cddfSDavid du Colombier     for (; n > 0; out += 4, ++in1, ++in2, ++in3, ++in4, --n) {
2507dd7cddfSDavid du Colombier 	out[0] = *in1;
2517dd7cddfSDavid du Colombier 	out[1] = *in2;
2527dd7cddfSDavid du Colombier 	out[2] = *in3;
2537dd7cddfSDavid du Colombier 	out[3] = *in4;
2547dd7cddfSDavid du Colombier     }
2557dd7cddfSDavid du Colombier     return 0;
2567dd7cddfSDavid du Colombier }
2577dd7cddfSDavid du Colombier 
2587dd7cddfSDavid du Colombier /* Convert 4Mx12 to 4x12. */
2597dd7cddfSDavid du Colombier private int
flip4x12(byte * buffer,const byte ** planes,int offset,int nbytes)2607dd7cddfSDavid du Colombier flip4x12(byte * buffer, const byte ** planes, int offset, int nbytes)
2617dd7cddfSDavid du Colombier {
2627dd7cddfSDavid du Colombier     byte *out = buffer;
2637dd7cddfSDavid du Colombier     const byte *pa = planes[0] + offset;
2647dd7cddfSDavid du Colombier     const byte *pb = planes[1] + offset;
2657dd7cddfSDavid du Colombier     const byte *pc = planes[2] + offset;
2667dd7cddfSDavid du Colombier     const byte *pd = planes[3] + offset;
2677dd7cddfSDavid du Colombier     int n = nbytes;
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier     /*
2707dd7cddfSDavid du Colombier      * We assume that the input is an integral number of pixels, and
2717dd7cddfSDavid du Colombier      * round up n to a multiple of 3.
2727dd7cddfSDavid du Colombier      */
2737dd7cddfSDavid du Colombier     for (; n > 0; out += 12, pa += 3, pb += 3, pc += 3, pd += 3, n -= 3) {
2747dd7cddfSDavid du Colombier 	byte_var a1 = pa[1], b1 = pb[1], c1 = pc[1], d1 = pd[1];
2757dd7cddfSDavid du Colombier 
2767dd7cddfSDavid du Colombier 	{
2777dd7cddfSDavid du Colombier 	    byte_var v0;
2787dd7cddfSDavid du Colombier 
2797dd7cddfSDavid du Colombier 	    out[0] = pa[0];
2807dd7cddfSDavid du Colombier 	    v0 = pb[0];
2817dd7cddfSDavid du Colombier 	    out[1] = (a1 & 0xf0) | (v0 >> 4);
2827dd7cddfSDavid du Colombier 	    out[2] = (byte) ((v0 << 4) | (b1 >> 4));
2837dd7cddfSDavid du Colombier 	    out[3] = pc[0];
2847dd7cddfSDavid du Colombier 	    v0 = pd[0];
2857dd7cddfSDavid du Colombier 	    out[4] = (c1 & 0xf0) | (v0 >> 4);
2867dd7cddfSDavid du Colombier 	    out[5] = (byte) ((v0 << 4) | (d1 >> 4));
2877dd7cddfSDavid du Colombier 	}
2887dd7cddfSDavid du Colombier 	{
2897dd7cddfSDavid du Colombier 	    byte_var v2;
2907dd7cddfSDavid du Colombier 
2917dd7cddfSDavid du Colombier 	    v2 = pa[2];
2927dd7cddfSDavid du Colombier 	    out[6] = (byte) ((a1 << 4) | (v2 >> 4));
2937dd7cddfSDavid du Colombier 	    out[7] = (byte) ((v2 << 4) | (b1 & 0xf));
2947dd7cddfSDavid du Colombier 	    out[8] = pb[2];
2957dd7cddfSDavid du Colombier 	    v2 = pc[2];
2967dd7cddfSDavid du Colombier 	    out[9] = (byte) ((c1 << 4) | (v2 >> 4));
2977dd7cddfSDavid du Colombier 	    out[10] = (byte) ((v2 << 4) | (d1 & 0xf));
2987dd7cddfSDavid du Colombier 	    out[11] = pd[2];
2997dd7cddfSDavid du Colombier 	}
3007dd7cddfSDavid du Colombier     }
3017dd7cddfSDavid du Colombier     return 0;
3027dd7cddfSDavid du Colombier }
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier /* Convert NMx{1,2,4,8} to Nx{1,2,4,8}. */
3057dd7cddfSDavid du Colombier private int
flipNx1to8(byte * buffer,const byte ** planes,int offset,int nbytes,int num_planes,int bits_per_sample)3067dd7cddfSDavid du Colombier flipNx1to8(byte * buffer, const byte ** planes, int offset, int nbytes,
3077dd7cddfSDavid du Colombier 	   int num_planes, int bits_per_sample)
3087dd7cddfSDavid du Colombier {
3097dd7cddfSDavid du Colombier     /* This is only needed for DeviceN colors, so it can be slow. */
3107dd7cddfSDavid du Colombier     uint mask = (1 << bits_per_sample) - 1;
3117dd7cddfSDavid du Colombier     int bi, pi;
3127dd7cddfSDavid du Colombier     sample_store_declare_setup(dptr, dbit, dbbyte, buffer, 0, bits_per_sample);
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier     for (bi = 0; bi < nbytes * 8; bi += bits_per_sample) {
3157dd7cddfSDavid du Colombier 	for (pi = 0; pi < num_planes; ++pi) {
3167dd7cddfSDavid du Colombier 	    const byte *sptr = planes[pi] + offset + (bi >> 3);
3177dd7cddfSDavid du Colombier 	    uint value = (*sptr >> (8 - (bi & 7) - bits_per_sample)) & mask;
3187dd7cddfSDavid du Colombier 
3197dd7cddfSDavid du Colombier 	    sample_store_next8(value, dptr, dbit, bits_per_sample, dbbyte);
3207dd7cddfSDavid du Colombier 	}
3217dd7cddfSDavid du Colombier     }
3227dd7cddfSDavid du Colombier     sample_store_flush(dptr, dbit, bits_per_sample, dbbyte);
3237dd7cddfSDavid du Colombier     return 0;
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier /* Convert NMx12 to Nx12. */
3277dd7cddfSDavid du Colombier private int
flipNx12(byte * buffer,const byte ** planes,int offset,int nbytes,int num_planes,int ignore_bits_per_sample)3287dd7cddfSDavid du Colombier flipNx12(byte * buffer, const byte ** planes, int offset, int nbytes,
3297dd7cddfSDavid du Colombier 	 int num_planes, int ignore_bits_per_sample)
3307dd7cddfSDavid du Colombier {
3317dd7cddfSDavid du Colombier     /* This is only needed for DeviceN colors, so it can be slow. */
3327dd7cddfSDavid du Colombier     int bi, pi;
3337dd7cddfSDavid du Colombier     sample_store_declare_setup(dptr, dbit, dbbyte, buffer, 0, 12);
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier     for (bi = 0; bi < nbytes * 8; bi += 12) {
3367dd7cddfSDavid du Colombier 	for (pi = 0; pi < num_planes; ++pi) {
3377dd7cddfSDavid du Colombier 	    const byte *sptr = planes[pi] + offset + (bi >> 3);
3387dd7cddfSDavid du Colombier 	    uint value =
3397dd7cddfSDavid du Colombier 		(bi & 4 ? ((*sptr & 0xf) << 8) | sptr[1] :
3407dd7cddfSDavid du Colombier 		 (*sptr << 4) | (sptr[1] >> 4));
3417dd7cddfSDavid du Colombier 
3427dd7cddfSDavid du Colombier 	    sample_store_next_12(value, dptr, dbit, dbbyte);
3437dd7cddfSDavid du Colombier 	}
3447dd7cddfSDavid du Colombier     }
3457dd7cddfSDavid du Colombier     sample_store_flush(dptr, dbit, 12, dbbyte);
3467dd7cddfSDavid du Colombier     return 0;
3477dd7cddfSDavid du Colombier }
3487dd7cddfSDavid du Colombier 
3497dd7cddfSDavid du Colombier /* Flip data given number of planes and bits per pixel. */
350*593dc095SDavid du Colombier typedef int (*image_flip_proc) (byte *, const byte **, int, int);
3517dd7cddfSDavid du Colombier private int
flip_fail(byte * buffer,const byte ** planes,int offset,int nbytes)3527dd7cddfSDavid du Colombier flip_fail(byte * buffer, const byte ** planes, int offset, int nbytes)
3537dd7cddfSDavid du Colombier {
3547dd7cddfSDavid du Colombier     return -1;
3557dd7cddfSDavid du Colombier }
3567dd7cddfSDavid du Colombier private const image_flip_proc image_flip3_procs[13] = {
3577dd7cddfSDavid du Colombier     flip_fail, flip3x1, flip3x2, flip_fail, flip3x4,
3587dd7cddfSDavid du Colombier     flip_fail, flip_fail, flip_fail, flip3x8,
3597dd7cddfSDavid du Colombier     flip_fail, flip_fail, flip_fail, flip3x12
3607dd7cddfSDavid du Colombier };
3617dd7cddfSDavid du Colombier private const image_flip_proc image_flip4_procs[13] = {
3627dd7cddfSDavid du Colombier     flip_fail, flip4x1, flip4x2, flip_fail, flip4x4,
3637dd7cddfSDavid du Colombier     flip_fail, flip_fail, flip_fail, flip4x8,
3647dd7cddfSDavid du Colombier     flip_fail, flip_fail, flip_fail, flip4x12
3657dd7cddfSDavid du Colombier };
366*593dc095SDavid du Colombier typedef int (*image_flipN_proc) (byte *, const byte **, int, int, int, int);
3677dd7cddfSDavid du Colombier private int
flipN_fail(byte * buffer,const byte ** planes,int offset,int nbytes,int num_planes,int bits_per_sample)3687dd7cddfSDavid du Colombier flipN_fail(byte * buffer, const byte ** planes, int offset, int nbytes,
3697dd7cddfSDavid du Colombier 	   int num_planes, int bits_per_sample)
3707dd7cddfSDavid du Colombier {
3717dd7cddfSDavid du Colombier     return -1;
3727dd7cddfSDavid du Colombier }
3737dd7cddfSDavid du Colombier private const image_flipN_proc image_flipN_procs[13] = {
3747dd7cddfSDavid du Colombier     flipN_fail, flipNx1to8, flipNx1to8, flipN_fail, flipNx1to8,
3757dd7cddfSDavid du Colombier     flipN_fail, flipN_fail, flipN_fail, flipNx1to8,
3767dd7cddfSDavid du Colombier     flipN_fail, flipN_fail, flipN_fail, flipNx12
3777dd7cddfSDavid du Colombier };
3787dd7cddfSDavid du Colombier 
3797dd7cddfSDavid du Colombier /* Here is the public interface to all of the above. */
3807dd7cddfSDavid du Colombier int
image_flip_planes(byte * buffer,const byte ** planes,int offset,int nbytes,int num_planes,int bits_per_sample)3817dd7cddfSDavid du Colombier image_flip_planes(byte * buffer, const byte ** planes, int offset, int nbytes,
3827dd7cddfSDavid du Colombier 		  int num_planes, int bits_per_sample)
3837dd7cddfSDavid du Colombier {
3847dd7cddfSDavid du Colombier     if (bits_per_sample < 1 || bits_per_sample > 12)
3857dd7cddfSDavid du Colombier 	return -1;
3867dd7cddfSDavid du Colombier     switch (num_planes) {
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier     case 3:
3897dd7cddfSDavid du Colombier 	return image_flip3_procs[bits_per_sample]
3907dd7cddfSDavid du Colombier 	    (buffer, planes, offset, nbytes);
3917dd7cddfSDavid du Colombier     case 4:
3927dd7cddfSDavid du Colombier 	return image_flip4_procs[bits_per_sample]
3937dd7cddfSDavid du Colombier 	    (buffer, planes, offset, nbytes);
3947dd7cddfSDavid du Colombier     default:
3957dd7cddfSDavid du Colombier 	if (num_planes < 0)
3967dd7cddfSDavid du Colombier 	    return -1;
3977dd7cddfSDavid du Colombier 	return image_flipN_procs[bits_per_sample]
3987dd7cddfSDavid du Colombier 	    (buffer, planes, offset, nbytes, num_planes, bits_per_sample);
3997dd7cddfSDavid du Colombier     }
4007dd7cddfSDavid du Colombier }
401