add libvncserver
[presencevnc] / libvnc / libvncserver / zywrletemplate.c
diff --git a/libvnc/libvncserver/zywrletemplate.c b/libvnc/libvncserver/zywrletemplate.c
new file mode 100644 (file)
index 0000000..52b2b0b
--- /dev/null
@@ -0,0 +1,824 @@
+
+/********************************************************************
+ *                                                                  *
+ * THIS FILE IS PART OF THE 'ZYWRLE' VNC CODEC SOURCE CODE.         *
+ *                                                                  *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS     *
+ * GOVERNED BY A FOLLOWING BSD-STYLE SOURCE LICENSE.                *
+ * PLEASE READ THESE TERMS BEFORE DISTRIBUTING.                     *
+ *                                                                  *
+ * THE 'ZYWRLE' VNC CODEC SOURCE CODE IS (C) COPYRIGHT 2006         *
+ * BY Hitachi Systems & Services, Ltd.                              *
+ * (Noriaki Yamazaki, Research & Developement Center)               *                                                                 *
+ *                                                                  *
+ ********************************************************************
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+- Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+- Neither the name of the Hitachi Systems & Services, Ltd. nor
+the names of its contributors may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ********************************************************************/
+
+/* Change Log:
+     V0.02 : 2008/02/04 : Fix mis encode/decode when width != scanline
+                            (Thanks Johannes Schindelin, author of LibVNC
+                                                 Server/Client)
+     V0.01 : 2007/02/06 : Initial release
+*/
+
+/* #define ZYWRLE_ENCODE */
+/* #define ZYWRLE_DECODE */
+#define ZYWRLE_QUANTIZE
+
+/*
+[References]
+ PLHarr:
+   Senecal, J. G., P. Lindstrom, M. A. Duchaineau, and K. I. Joy, "An Improved N-Bit to N-Bit Reversible Haar-Like Transform," Pacific Graphics 2004, October 2004, pp. 371-380.
+ EZW:
+   Shapiro, JM: Embedded Image Coding Using Zerotrees of Wavelet Coefficients, IEEE Trans. Signal. Process., Vol.41, pp.3445-3462 (1993).
+*/
+
+
+/* Template Macro stuffs. */
+#undef ZYWRLE_ANALYZE
+#undef ZYWRLE_SYNTHESIZE
+#define ZYWRLE_ANALYZE __RFB_CONCAT3E(zywrleAnalyze,BPP,END_FIX)
+#define ZYWRLE_SYNTHESIZE __RFB_CONCAT3E(zywrleSynthesize,BPP,END_FIX)
+
+#define ZYWRLE_RGBYUV __RFB_CONCAT3E(zywrleRGBYUV,BPP,END_FIX)
+#define ZYWRLE_YUVRGB __RFB_CONCAT3E(zywrleYUVRGB,BPP,END_FIX)
+#define ZYWRLE_YMASK __RFB_CONCAT2E(ZYWRLE_YMASK,BPP)
+#define ZYWRLE_UVMASK __RFB_CONCAT2E(ZYWRLE_UVMASK,BPP)
+#define ZYWRLE_LOAD_PIXEL __RFB_CONCAT2E(ZYWRLE_LOAD_PIXEL,BPP)
+#define ZYWRLE_SAVE_PIXEL __RFB_CONCAT2E(ZYWRLE_SAVE_PIXEL,BPP)
+
+/* Packing/Unpacking pixel stuffs.
+   Endian conversion stuffs. */
+#undef S_0
+#undef S_1
+#undef L_0
+#undef L_1
+#undef L_2
+#if ZYWRLE_ENDIAN == ENDIAN_BIG
+#  define S_0  1
+#  define S_1  0
+#  define L_0  3
+#  define L_1  2
+#  define L_2  1
+#else
+#  define S_0  0
+#  define S_1  1
+#  define L_0  0
+#  define L_1  1
+#  define L_2  2
+#endif
+
+/*   Load/Save pixel stuffs. */
+#define ZYWRLE_YMASK15  0xFFFFFFF8
+#define ZYWRLE_UVMASK15 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL15(pSrc,R,G,B) { \
+       R =  (((unsigned char*)pSrc)[S_1]<< 1)& 0xF8;   \
+       G = ((((unsigned char*)pSrc)[S_1]<< 6)|(((unsigned char*)pSrc)[S_0]>> 2))& 0xF8;        \
+       B =  (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8;   \
+}
+#define ZYWRLE_SAVE_PIXEL15(pDst,R,G,B) { \
+       R &= 0xF8;      \
+       G &= 0xF8;      \
+       B &= 0xF8;      \
+       ((unsigned char*)pDst)[S_1] = (unsigned char)( (R>>1)|(G>>6)       );   \
+       ((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<2))& 0xFF);   \
+}
+#define ZYWRLE_YMASK16  0xFFFFFFFC
+#define ZYWRLE_UVMASK16 0xFFFFFFF8
+#define ZYWRLE_LOAD_PIXEL16(pSrc,R,G,B) { \
+       R =   ((unsigned char*)pSrc)[S_1]     & 0xF8;   \
+       G = ((((unsigned char*)pSrc)[S_1]<< 5)|(((unsigned char*)pSrc)[S_0]>> 3))& 0xFC;        \
+       B =  (((unsigned char*)pSrc)[S_0]<< 3)& 0xF8;   \
+}
+#define ZYWRLE_SAVE_PIXEL16(pDst,R,G,B) { \
+       R &= 0xF8;      \
+       G &= 0xFC;      \
+       B &= 0xF8;      \
+       ((unsigned char*)pDst)[S_1] = (unsigned char)(  R    |(G>>5)       );   \
+       ((unsigned char*)pDst)[S_0] = (unsigned char)(((B>>3)|(G<<3))& 0xFF);   \
+}
+#define ZYWRLE_YMASK32  0xFFFFFFFF
+#define ZYWRLE_UVMASK32 0xFFFFFFFF
+#define ZYWRLE_LOAD_PIXEL32(pSrc,R,G,B) { \
+       R = ((unsigned char*)pSrc)[L_2];        \
+       G = ((unsigned char*)pSrc)[L_1];        \
+       B = ((unsigned char*)pSrc)[L_0];        \
+}
+#define ZYWRLE_SAVE_PIXEL32(pDst,R,G,B) { \
+       ((unsigned char*)pDst)[L_2] = (unsigned char)R; \
+       ((unsigned char*)pDst)[L_1] = (unsigned char)G; \
+       ((unsigned char*)pDst)[L_0] = (unsigned char)B; \
+}
+
+#ifndef ZYWRLE_ONCE
+#define ZYWRLE_ONCE
+
+#ifdef WIN32
+#define InlineX __inline
+#else
+#define InlineX inline
+#endif
+
+#ifdef ZYWRLE_ENCODE
+/* Tables for Coefficients filtering. */
+#  ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+const static unsigned int zywrleParam[3][3]={
+       {0x0000F000,0x00000000,0x00000000},
+       {0x0000C000,0x00F0F0F0,0x00000000},
+       {0x0000C000,0x00C0C0C0,0x00F0F0F0},
+/*     {0x0000FF00,0x00000000,0x00000000},
+       {0x0000FF00,0x00FFFFFF,0x00000000},
+       {0x0000FF00,0x00FFFFFF,0x00FFFFFF}, */
+};
+#  else
+/* Type B:Non liner quantization filter. */
+static const signed char zywrleConv[4][256]={
+{      /* bi=5, bo=5 r=0.0:PSNR=24.849 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+},
+{      /* bi=5, bo=5 r=2.0:PSNR=74.031 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 32,
+       32, 32, 32, 32, 32, 32, 32, 32,
+       32, 32, 32, 32, 32, 32, 32, 32,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       48, 48, 48, 56, 56, 56, 56, 56,
+       56, 56, 56, 56, 64, 64, 64, 64,
+       64, 64, 64, 64, 72, 72, 72, 72,
+       72, 72, 72, 72, 80, 80, 80, 80,
+       80, 80, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 96, 96,
+       96, 96, 96, 104, 104, 104, 104, 104,
+       104, 104, 104, 104, 104, 112, 112, 112,
+       112, 112, 112, 112, 112, 112, 120, 120,
+       120, 120, 120, 120, 120, 120, 120, 120,
+       0, -120, -120, -120, -120, -120, -120, -120,
+       -120, -120, -120, -112, -112, -112, -112, -112,
+       -112, -112, -112, -112, -104, -104, -104, -104,
+       -104, -104, -104, -104, -104, -104, -96, -96,
+       -96, -96, -96, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -80,
+       -80, -80, -80, -80, -80, -72, -72, -72,
+       -72, -72, -72, -72, -72, -64, -64, -64,
+       -64, -64, -64, -64, -64, -56, -56, -56,
+       -56, -56, -56, -56, -56, -56, -48, -48,
+       -48, -48, -48, -48, -48, -48, -48, -48,
+       -48, -32, -32, -32, -32, -32, -32, -32,
+       -32, -32, -32, -32, -32, -32, -32, -32,
+       -32, -32, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+},
+{      /* bi=5, bo=4 r=2.0:PSNR=64.441 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       48, 48, 48, 48, 48, 48, 48, 48,
+       64, 64, 64, 64, 64, 64, 64, 64,
+       64, 64, 64, 64, 64, 64, 64, 64,
+       80, 80, 80, 80, 80, 80, 80, 80,
+       80, 80, 80, 80, 80, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       104, 104, 104, 104, 104, 104, 104, 104,
+       104, 104, 104, 112, 112, 112, 112, 112,
+       112, 112, 112, 112, 120, 120, 120, 120,
+       120, 120, 120, 120, 120, 120, 120, 120,
+       0, -120, -120, -120, -120, -120, -120, -120,
+       -120, -120, -120, -120, -120, -112, -112, -112,
+       -112, -112, -112, -112, -112, -112, -104, -104,
+       -104, -104, -104, -104, -104, -104, -104, -104,
+       -104, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -80, -80, -80, -80,
+       -80, -80, -80, -80, -80, -80, -80, -80,
+       -80, -64, -64, -64, -64, -64, -64, -64,
+       -64, -64, -64, -64, -64, -64, -64, -64,
+       -64, -48, -48, -48, -48, -48, -48, -48,
+       -48, -48, -48, -48, -48, -48, -48, -48,
+       -48, -48, -48, -48, -48, -48, -48, -48,
+       -48, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+},
+{      /* bi=5, bo=2 r=2.0:PSNR=43.175 */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       88, 88, 88, 88, 88, 88, 88, 88,
+       0, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, -88, -88, -88, -88, -88, -88, -88,
+       -88, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+}
+};
+const static signed char* zywrleParam[3][3][3]={
+       {{zywrleConv[0],zywrleConv[2],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}},
+       {{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]},{zywrleConv[0],zywrleConv[0],zywrleConv[0]}},
+       {{zywrleConv[0],zywrleConv[3],zywrleConv[0]},{zywrleConv[2],zywrleConv[2],zywrleConv[2]},{zywrleConv[1],zywrleConv[1],zywrleConv[1]}},
+};
+#  endif
+#endif
+
+static InlineX void Harr(signed char* pX0, signed char* pX1)
+{
+       /* Piecewise-Linear Harr(PLHarr) */
+       int X0 = (int)*pX0, X1 = (int)*pX1;
+       int orgX0 = X0, orgX1 = X1;
+       if ((X0 ^ X1) & 0x80) {
+               /* differ sign */
+               X1 += X0;
+               if (((X1^orgX1)&0x80)==0) {
+                       /* |X1| > |X0| */
+                       X0 -= X1;       /* H = -B */
+               }
+       } else {
+               /* same sign */
+               X0 -= X1;
+               if (((X0 ^ orgX0) & 0x80) == 0) {
+                       /* |X0| > |X1| */
+                       X1 += X0;       /* L = A */
+               }
+       }
+       *pX0 = (signed char)X1;
+       *pX1 = (signed char)X0;
+}
+/*
+ 1D-Wavelet transform.
+
+ In coefficients array, the famous 'pyramid' decomposition is well used.
+
+ 1D Model:
+   |L0L0L0L0|L0L0L0L0|H0H0H0H0|H0H0H0H0| : level 0
+   |L1L1L1L1|H1H1H1H1|H0H0H0H0|H0H0H0H0| : level 1
+
+ But this method needs line buffer because H/L is different position from X0/X1.
+ So, I used 'interleave' decomposition instead of it.
+
+ 1D Model:
+   |L0H0L0H0|L0H0L0H0|L0H0L0H0|L0H0L0H0| : level 0
+   |L1H0H1H0|L1H0H1H0|L1H0H1H0|L1H0H1H0| : level 1
+
+ In this method, H/L and X0/X1 is always same position.
+ This lead us to more speed and less memory.
+ Of cause, the result of both method is quite same
+ because it's only difference that coefficient position.
+*/
+static InlineX void WaveletLevel(int* data, int size, int l, int SkipPixel)
+{
+       int s, ofs;
+       signed char* pX0;
+       signed char* end;
+
+       pX0 = (signed char*)data;
+       s = (8<<l)*SkipPixel;
+       end = pX0+(size>>(l+1))*s;
+       s -= 2;
+       ofs = (4<<l)*SkipPixel;
+       while (pX0 < end) {
+               Harr(pX0, pX0+ofs);
+               pX0++;
+               Harr(pX0, pX0+ofs);
+               pX0++;
+               Harr(pX0, pX0+ofs);
+               pX0 += s;
+       }
+}
+#define InvWaveletLevel(d,s,l,pix) WaveletLevel(d,s,l,pix)
+
+#ifdef ZYWRLE_ENCODE
+#  ifndef ZYWRLE_QUANTIZE
+/* Type A:lower bit omitting of EZW style. */
+static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l)
+{
+       int r, s;
+       int x, y;
+       int* pH;
+       const unsigned int* pM;
+
+       pM = &(zywrleParam[level-1][l]);
+       s = 2<<l;
+       for (r = 1; r < 4; r++) {
+               pH   = pBuf;
+               if (r & 0x01)
+                       pH +=  s>>1;
+               if (r & 0x02)
+                       pH += (s>>1)*width;
+               for (y = 0; y < height / s; y++) {
+                       for (x = 0; x < width / s; x++) {
+                               /*
+                                these are same following code.
+                                    pH[x] = pH[x] / (~pM[x]+1) * (~pM[x]+1);
+                                    ( round pH[x] with pM[x] bit )
+                                '&' operator isn't 'round' but is 'floor'.
+                                So, we must offset when pH[x] is negative.
+                               */
+                               if (((signed char*)pH)[0] & 0x80)
+                                       ((signed char*)pH)[0] += ~((signed char*)pM)[0];
+                               if (((signed char*)pH)[1] & 0x80)
+                                       ((signed char*)pH)[1] += ~((signed char*)pM)[1];
+                               if (((signed char*)pH)[2] & 0x80)
+                                       ((signed char*)pH)[2] += ~((signed char*)pM)[2];
+                               *pH &= *pM;
+                               pH += s;
+                       }
+                       pH += (s-1)*width;
+               }
+       }
+}
+#  else
+/*
+ Type B:Non liner quantization filter.
+
+ Coefficients have Gaussian curve and smaller value which is
+ large part of coefficients isn't more important than larger value.
+ So, I use filter of Non liner quantize/dequantize table.
+ In general, Non liner quantize formula is explained as following.
+
+    y=f(x)   = sign(x)*round( ((abs(x)/(2^7))^ r   )* 2^(bo-1) )*2^(8-bo)
+    x=f-1(y) = sign(y)*round( ((abs(y)/(2^7))^(1/r))* 2^(bi-1) )*2^(8-bi)
+ ( r:power coefficient  bi:effective MSB in input  bo:effective MSB in output )
+
+   r < 1.0 : Smaller value is more important than larger value.
+   r > 1.0 : Larger value is more important than smaller value.
+   r = 1.0 : Liner quantization which is same with EZW style.
+
+ r = 0.75 is famous non liner quantization used in MP3 audio codec.
+ In contrast to audio data, larger value is important in wavelet coefficients.
+ So, I select r = 2.0 table( quantize is x^2, dequantize sqrt(x) ).
+
+ As compared with EZW style liner quantization, this filter tended to be
+ more sharp edge and be more compression rate but be more blocking noise and be less quality.
+ Especially, the surface of graphic objects has distinguishable noise in middle quality mode.
+
+ We need only quantized-dequantized(filtered) value rather than quantized value itself
+ because all values are packed or palette-lized in later ZRLE section.
+ This lead us not to need to modify client decoder when we change
+ the filtering procedure in future.
+ Client only decodes coefficients given by encoder.
+*/
+static InlineX void FilterWaveletSquare(int* pBuf, int width, int height, int level, int l)
+{
+       int r, s;
+       int x, y;
+       int* pH;
+       const signed char** pM;
+
+       pM = zywrleParam[level-1][l];
+       s = 2<<l;
+       for (r = 1; r < 4; r++) {
+               pH   = pBuf;
+               if (r & 0x01)
+                       pH +=  s>>1;
+               if (r & 0x02)
+                       pH += (s>>1)*width;
+               for (y = 0; y < height / s; y++) {
+                       for (x = 0; x < width / s; x++) {
+                               ((signed char*)pH)[0] = pM[0][((unsigned char*)pH)[0]];
+                               ((signed char*)pH)[1] = pM[1][((unsigned char*)pH)[1]];
+                               ((signed char*)pH)[2] = pM[2][((unsigned char*)pH)[2]];
+                               pH += s;
+                       }
+                       pH += (s-1)*width;
+               }
+       }
+}
+#  endif
+
+static InlineX void Wavelet(int* pBuf, int width, int height, int level)
+{
+       int l, s;
+       int* pTop;
+       int* pEnd;
+
+       for (l = 0; l < level; l++) {
+               pTop = pBuf;
+               pEnd = pBuf+height*width;
+               s = width<<l;
+               while (pTop < pEnd) {
+                       WaveletLevel(pTop, width, l, 1);
+                       pTop += s;
+               }
+               pTop = pBuf;
+               pEnd = pBuf+width;
+               s = 1<<l;
+               while (pTop < pEnd) {
+                       WaveletLevel(pTop, height,l, width);
+                       pTop += s;
+               }
+               FilterWaveletSquare(pBuf, width, height, level, l);
+       }
+}
+#endif
+#ifdef ZYWRLE_DECODE
+static InlineX void InvWavelet(int* pBuf, int width, int height, int level)
+{
+       int l, s;
+       int* pTop;
+       int* pEnd;
+
+       for (l = level - 1; l >= 0; l--) {
+               pTop = pBuf;
+               pEnd = pBuf+width;
+               s = 1<<l;
+               while (pTop < pEnd) {
+                       InvWaveletLevel(pTop, height,l, width);
+                       pTop += s;
+               }
+               pTop = pBuf;
+               pEnd = pBuf+height*width;
+               s = width<<l;
+               while (pTop < pEnd) {
+                       InvWaveletLevel(pTop, width, l, 1);
+                       pTop += s;
+               }
+       }
+}
+#endif
+
+/* Load/Save coefficients stuffs.
+ Coefficients manages as 24 bits little-endian pixel. */
+#define ZYWRLE_LOAD_COEFF(pSrc,R,G,B) { \
+       R = ((signed char*)pSrc)[2];    \
+       G = ((signed char*)pSrc)[1];    \
+       B = ((signed char*)pSrc)[0];    \
+}
+#define ZYWRLE_SAVE_COEFF(pDst,R,G,B) { \
+       ((signed char*)pDst)[2] = (signed char)R;       \
+       ((signed char*)pDst)[1] = (signed char)G;       \
+       ((signed char*)pDst)[0] = (signed char)B;       \
+}
+
+/*
+ RGB <=> YUV conversion stuffs.
+ YUV coversion is explained as following formula in strict meaning:
+   Y =  0.299R + 0.587G + 0.114B (   0<=Y<=255)
+   U = -0.169R - 0.331G + 0.500B (-128<=U<=127)
+   V =  0.500R - 0.419G - 0.081B (-128<=V<=127)
+
+ I use simple conversion RCT(reversible color transform) which is described
+ in JPEG-2000 specification.
+   Y = (R + 2G + B)/4 (   0<=Y<=255)
+   U = B-G (-256<=U<=255)
+   V = R-G (-256<=V<=255)
+*/
+#define ROUND(x) (((x)<0)?0:(((x)>255)?255:(x)))
+       /* RCT is N-bit RGB to N-bit Y and N+1-bit UV.
+        For make Same N-bit, UV is lossy.
+        More exact PLHarr, we reduce to odd range(-127<=x<=127). */
+#define ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ymask,uvmask) { \
+       Y = (R+(G<<1)+B)>>2;    \
+       U =  B-G;       \
+       V =  R-G;       \
+       Y -= 128;       \
+       U >>= 1;        \
+       V >>= 1;        \
+       Y &= ymask;     \
+       U &= uvmask;    \
+       V &= uvmask;    \
+       if (Y == -128)  \
+               Y += (0xFFFFFFFF-ymask+1);      \
+       if (U == -128)  \
+               U += (0xFFFFFFFF-uvmask+1);     \
+       if (V == -128)  \
+               V += (0xFFFFFFFF-uvmask+1);     \
+}
+#define ZYWRLE_YUVRGB1(R,G,B,Y,U,V) { \
+       Y += 128;       \
+       U <<= 1;        \
+       V <<= 1;        \
+       G = Y-((U+V)>>2);       \
+       B = U+G;        \
+       R = V+G;        \
+       G = ROUND(G);   \
+       B = ROUND(B);   \
+       R = ROUND(R);   \
+}
+
+/*
+ coefficient packing/unpacking stuffs.
+ Wavelet transform makes 4 sub coefficient image from 1 original image.
+
+ model with pyramid decomposition:
+   +------+------+
+   |      |      |
+   |  L   |  Hx  |
+   |      |      |
+   +------+------+
+   |      |      |
+   |  H   |  Hxy |
+   |      |      |
+   +------+------+
+
+ So, we must transfer each sub images individually in strict meaning.
+ But at least ZRLE meaning, following one decompositon image is same as
+ avobe individual sub image. I use this format.
+ (Strictly saying, transfer order is reverse(Hxy->Hy->Hx->L)
+  for simplified procedure for any wavelet level.)
+
+   +------+------+
+   |      L      |
+   +------+------+
+   |      Hx     |
+   +------+------+
+   |      Hy     |
+   +------+------+
+   |      Hxy    |
+   +------+------+
+*/
+#define INC_PTR(data) \
+       data++; \
+       if( data-pData >= (w+uw) ){     \
+               data += scanline-(w+uw);        \
+               pData = data;   \
+       }
+
+#define ZYWRLE_TRANSFER_COEFF(pBuf,data,r,w,h,scanline,level,TRANS)    \
+       pH = pBuf;      \
+       s = 2<<level;   \
+       if (r & 0x01)   \
+               pH +=  s>>1;    \
+       if (r & 0x02)   \
+               pH += (s>>1)*w; \
+       pEnd = pH+h*w;  \
+       while (pH < pEnd) {     \
+               pLine = pH+w;   \
+               while (pH < pLine) {    \
+                       TRANS   \
+                       INC_PTR(data)   \
+                       pH += s;        \
+               }       \
+               pH += (s-1)*w;  \
+       }
+
+#define ZYWRLE_PACK_COEFF(pBuf,data,r,width,height,scanline,level)     \
+       ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_COEFF(pH,R,G,B);ZYWRLE_SAVE_PIXEL(data,R,G,B);)
+
+#define ZYWRLE_UNPACK_COEFF(pBuf,data,r,width,height,scanline,level)   \
+       ZYWRLE_TRANSFER_COEFF(pBuf,data,r,width,height,scanline,level,ZYWRLE_LOAD_PIXEL(data,R,G,B);ZYWRLE_SAVE_COEFF(pH,R,G,B);)
+
+#define ZYWRLE_SAVE_UNALIGN(data,TRANS)        \
+       pTop = pBuf+w*h;        \
+       pEnd = pBuf + (w+uw)*(h+uh);    \
+       while (pTop < pEnd) {   \
+               TRANS   \
+               INC_PTR(data)   \
+               pTop++; \
+       }
+
+#define ZYWRLE_LOAD_UNALIGN(data,TRANS)        \
+       pTop = pBuf+w*h;        \
+       if (uw) {       \
+               pData=         data + w;        \
+               pEnd = (int*)(pData+ h*scanline);       \
+               while (pData < (PIXEL_T*)pEnd) {        \
+                       pLine = (int*)(pData + uw);     \
+                       while (pData < (PIXEL_T*)pLine) {       \
+                               TRANS   \
+                               pData++;        \
+                               pTop++; \
+                       }       \
+                       pData += scanline-uw;   \
+               }       \
+       }       \
+       if (uh) {       \
+               pData=         data +  h*scanline;      \
+               pEnd = (int*)(pData+ uh*scanline);      \
+               while (pData < (PIXEL_T*)pEnd) {        \
+                       pLine = (int*)(pData + w);      \
+                       while (pData < (PIXEL_T*)pLine) {       \
+                               TRANS   \
+                               pData++;        \
+                               pTop++; \
+                       }       \
+                       pData += scanline-w;    \
+               }       \
+       }       \
+       if (uw && uh) { \
+               pData=         data + w+ h*scanline;    \
+               pEnd = (int*)(pData+   uh*scanline);    \
+               while (pData < (PIXEL_T*)pEnd) {        \
+                       pLine = (int*)(pData + uw);     \
+                       while (pData < (PIXEL_T*)pLine) {       \
+                               TRANS   \
+                               pData++;        \
+                               pTop++; \
+                       }       \
+                       pData += scanline-uw;   \
+               }       \
+       }
+
+static InlineX void zywrleCalcSize(int* pW, int* pH, int level)
+{
+       *pW &= ~((1<<level)-1);
+       *pH &= ~((1<<level)-1);
+}
+
+#endif /* ZYWRLE_ONCE */
+
+#ifndef CPIXEL
+#ifdef ZYWRLE_ENCODE
+static InlineX void ZYWRLE_RGBYUV(int* pBuf, PIXEL_T* data, int width, int height, int scanline)
+{
+       int R, G, B;
+       int Y, U, V;
+       int* pLine;
+       int* pEnd;
+       pEnd = pBuf+height*width;
+       while (pBuf < pEnd) {
+               pLine = pBuf+width;
+               while (pBuf < pLine) {
+                       ZYWRLE_LOAD_PIXEL(data,R,G,B);
+                       ZYWRLE_RGBYUV1(R,G,B,Y,U,V,ZYWRLE_YMASK,ZYWRLE_UVMASK);
+                       ZYWRLE_SAVE_COEFF(pBuf,V,Y,U);
+                       pBuf++;
+                       data++;
+               }
+               data += scanline-width;
+       }
+}
+#endif
+#ifdef ZYWRLE_DECODE
+static InlineX void ZYWRLE_YUVRGB(int* pBuf, PIXEL_T* data, int width, int height, int scanline) {
+       int R, G, B;
+       int Y, U, V;
+       int* pLine;
+       int* pEnd;
+       pEnd = pBuf+height*width;
+       while (pBuf < pEnd) {
+               pLine = pBuf+width;
+               while (pBuf < pLine) {
+                       ZYWRLE_LOAD_COEFF(pBuf,V,Y,U);
+                       ZYWRLE_YUVRGB1(R,G,B,Y,U,V);
+                       ZYWRLE_SAVE_PIXEL(data,R,G,B);
+                       pBuf++;
+                       data++;
+               }
+               data += scanline-width;
+       }
+}
+#endif
+
+#ifdef ZYWRLE_ENCODE
+PIXEL_T* ZYWRLE_ANALYZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf) {
+       int l;
+       int uw = w;
+       int uh = h;
+       int* pTop;
+       int* pEnd;
+       int* pLine;
+       PIXEL_T* pData;
+       int R, G, B;
+       int s;
+       int* pH;
+
+       zywrleCalcSize(&w, &h, level);
+       if (w == 0 || h == 0)
+               return NULL;
+       uw -= w;
+       uh -= h;
+
+       pData = dst;
+       ZYWRLE_LOAD_UNALIGN(src,*(PIXEL_T*)pTop=*pData;)
+       ZYWRLE_RGBYUV(pBuf, src, w, h, scanline);
+       Wavelet(pBuf, w, h, level);
+       for (l = 0; l < level; l++) {
+               ZYWRLE_PACK_COEFF(pBuf, dst, 3, w, h, scanline, l);
+               ZYWRLE_PACK_COEFF(pBuf, dst, 2, w, h, scanline, l);
+               ZYWRLE_PACK_COEFF(pBuf, dst, 1, w, h, scanline, l);
+               if (l == level - 1) {
+                       ZYWRLE_PACK_COEFF(pBuf, dst, 0, w, h, scanline, l);
+               }
+       }
+       ZYWRLE_SAVE_UNALIGN(dst,*dst=*(PIXEL_T*)pTop;)
+       return dst;
+}
+#endif
+#ifdef ZYWRLE_DECODE
+PIXEL_T* ZYWRLE_SYNTHESIZE(PIXEL_T* dst, PIXEL_T* src, int w, int h, int scanline, int level, int* pBuf)
+{
+       int l;
+       int uw = w;
+       int uh = h;
+       int* pTop;
+       int* pEnd;
+       int* pLine;
+       PIXEL_T* pData;
+       int R, G, B;
+       int s;
+       int* pH;
+
+       zywrleCalcSize(&w, &h, level);
+       if (w == 0 || h == 0)
+               return NULL;
+       uw -= w;
+       uh -= h;
+
+       pData = src;
+       for (l = 0; l < level; l++) {
+               ZYWRLE_UNPACK_COEFF(pBuf, src, 3, w, h, scanline, l);
+               ZYWRLE_UNPACK_COEFF(pBuf, src, 2, w, h, scanline, l);
+               ZYWRLE_UNPACK_COEFF(pBuf, src, 1, w, h, scanline, l);
+               if (l == level - 1) {
+                       ZYWRLE_UNPACK_COEFF(pBuf, src, 0, w, h, scanline, l);
+               }
+       }
+       ZYWRLE_SAVE_UNALIGN(src,*(PIXEL_T*)pTop=*src;)
+       InvWavelet(pBuf, w, h, level);
+       ZYWRLE_YUVRGB(pBuf, dst, w, h, scanline);
+       ZYWRLE_LOAD_UNALIGN(dst,*pData=*(PIXEL_T*)pTop;)
+       return src;
+}
+#endif
+#endif  /* CPIXEL */
+
+#undef ZYWRLE_RGBYUV
+#undef ZYWRLE_YUVRGB
+#undef ZYWRLE_LOAD_PIXEL
+#undef ZYWRLE_SAVE_PIXEL