public override byte[][] Transform(Hashtable input)
        {
            //reseed it
            if(input == null)
                return null;
            rnd = new Random(Guid.NewGuid().ToString().GetHashCode());
            byte[][] b = (byte[][])input["image"];
            int width = (int)input["width"];
            int height = (int)input["height"];
            allowSawtooth = (bool)input["sawtooth"];
            allowVariance = (bool)input["variance"];
            allowGauss = (bool)input["gauss"];
            ScaleInfo si = new ScaleInfo(b.Length, b[0].Length, width, height);
            if(si.IsZooming)
            {
                //compute k across the entire image
                int nWidth = si.ResultWidth;
                int nHeight = si.ResultHeight;
                //apply the original image values to the given points
                float w = si.WidthScalingFactor;
                float h = si.HeightScalingFactor;
                float?[][] newImage = new float?[nWidth][];
                float[][] displacementTable = new float[nWidth][];
                float[][] imageF = ToFloatTable(b);
                byte[][] resultant = new byte[si.ResultWidth][];
                for(int i = 0; i < nWidth; i++)
                {
                    newImage[i] = new float?[nHeight];
                    displacementTable[i] = new float[nHeight];
                    resultant[i] = new byte[nHeight];
                }
                for(int i = 0; i < nWidth - 1; i++)
                {
                    int x0 = (int)((float)i / w);
                    int x1 = (int)((float)(i + 1) / w);
                    float p0 = (float)Math.Pow(x0 - x1, 2.0f);
                    float[] line0 = imageF[x0];
                    float[] line1 = imageF[x1];
                    for(int j = 0; j < nHeight - 1; j++)
                    {

                        int y0 = (int)((float)j / h);
                        int y1 = (int)((float)(j + 1) / h);
                        //order has been messed up for sometime
                        //should go (x0,y0), (x0,y1), (x1,y1), (x1,y0)
                        float f0 = line0[y0];
                        float f1 = line0[y1];
                        float f2 = line1[y1];
                        float f3 = line1[y0];
                        k = ComputeK(2,i,j,b);
                        displacementTable[i][j] = k; //save the base value
                        //if(k < 1.0f)
                        //{
                        float gauss = !allowGauss ? (float)rnd.NextDouble() : 1.0f;
                        float var = !allowVariance ? Variance(f0,f1,f2,f3) : 1.0f;
                        float tmp = (float)Math.Sqrt(1.0f - (float)Math.Pow(2.0f, 2.0f * k - 2f)) *
                            DeltaX(p0,y0,y1) * gauss * var;
                        k = tmp;
                        //}
                        DivideGrid(resultant, newImage, i, j, w, h, f0, f1, f2, f3);
                    }
                }
                if(allowSawtooth)
                {
                    List<float> temp = new List<float>();
                    for(int x = 0; x < si.ResultWidth; x++)
                    {
                        int outCount = 0;
                        int pX = x - 1;
                        bool pXValid = (pX >=0);
                        if(pXValid)
                            outCount++;
                        int fX = x + 1;
                        bool fXValid = (fX < si.ResultWidth);
                        if(fXValid)
                            outCount++;
                        for(int y = 0; y < si.ResultHeight; y++)
                        {
                            if(newImage[x][y] == null || newImage[x][y] > 1.0f)
                            {
                                temp.Clear();
                                int pY = y - 1;
                                int fY = y + 1;
                                int count = outCount;
                                float v0 = 0f, v1 = 0f, v2 = 0f, v3 = 0f;
                                //f-type computation
                                if(pXValid)
                                {
                                    v0 = ((float)newImage[pX][y]);
                                    temp.Add(v0);
                                }
                                if(pY >= 0)
                                {
                                    v1 = ((float)newImage[x][pY]);
                                    temp.Add(v1);
                                    count++;
                                }
                                if(fXValid)
                                {
                                    v2 = ((float)newImage[fX][y]);
                                    temp.Add(v2);
                                }
                                if(fY < si.ResultHeight)
                                {
                                    v3 = ((float)newImage[x][fY]);
                                    temp.Add(v3);
                                    count++;
                                }
                                //if count == 0 then we have bigger problems
                                float total = (1.0f / (float)count);
                                float p0 = total * (v0 + v1 + v2 + v3);

                                float gauss = !allowGauss ? (float)rnd.NextDouble() : 1.0f;
                                //get the k value
                                float dX = DeltaX(pX,fX,pY,fY);
                                float cK = displacementTable[x][y];
                                float var = !allowVariance ? Variance(temp.ToArray()) : 1.0f;
                                float p1 = (float)Math.Pow(2.0f, -(cK / 2.0f));
                                float p2 = (float)Math.Sqrt(1.0f - (float)Math.Pow(2.0, 2.0f * cK - 2.0f));
                                float result = 255.0f * Normalize(p0 + p1 * p2 * dX * gauss * var);
                                resultant[x][y] = (byte)result;
                            }
                        }
                    }
                    temp = null;
                }
                newImage = null;
                displacementTable = null;
                si = null;
                rnd = null;
                imageF = null;
                return resultant;
            }
            else
            {
                ByteImage image = new ByteImage(b);
                if(si.IsShrinking)
                {
                    var _i = image.ReplicationScale(si.ResultWidth, si.ResultHeight);
                    byte[][] target = new byte[_i.Width][];
                    for(int i = 0; i < _i.Width; i++)
                    {
                        byte[] q = new byte[_i.Height];
                        for(int j = 0; j < _i.Height; j++)
                            target[i][j] = _i[i,j];
                        target[i] = q;
                    }
                    image = null;
                    return target;
                }
                else
                    return b;
            }
            //we create the new
        }
        public override byte[][] Transform(Hashtable input)
        {
            //DateTime start = DateTime.Now;
            //reseed it
            if(input == null)
                return null;
            byte[][] b = (byte[][])input["image"];
            int width = (int)input["width"];
            int height = (int)input["height"];
            //allowSawtooth = (bool)input["sawtooth"];
            bool allowVariance = (bool)input["variance"];
            bool allowGauss = (bool)input["gauss"];
            ScaleInfo si = new ScaleInfo(b.Length, b[0].Length, width, height);
            if(si.IsZooming)
            {
                //compute k across the entire image
                int nWidth = si.ResultWidth;
                int nHeight = si.ResultHeight;
                //apply the original image values to the given points
                float w = si.WidthScalingFactor;
                float h = si.HeightScalingFactor;
                int w0 = (int)Math.Ceiling(w);
                int h0 = (int)Math.Ceiling(h);
            //	int w0 = 1;
            //	int h0 = 1;
                float?[][] newImage = new float?[nWidth][];
                float[][] imageF = ToFloatTable(b);
                byte[][] resultant = new byte[si.ResultWidth][];
                float[][] preComputedTable = new float[nWidth][];
                int[] scaleX = new int[nWidth];
                int[] scaleY = new int[nHeight];
                float[] xDiv = new float[nWidth - 1];
                Thread t = new Thread(() => UpdateDisplacementTable(b, imageF, preComputedTable,
                            nWidth, nHeight, 4, allowGauss, allowVariance, w, h, scaleX, scaleY, xDiv));

                for(int i = 0; i < nWidth; i++)
                {
                    newImage[i] = new float?[nHeight];
                    resultant[i] = new byte[nHeight];
                    preComputedTable[i] = new float[nHeight];
                    scaleX[i] = (int)((float)i / w);
                }
                for(int i = 0; i < nWidth - 1; i++)
                    xDiv[i] = (float)Math.Pow(scaleX[i] - scaleX[i + 1], 2.0f);
                for(int i = 0; i < nHeight; i++)
                    scaleY[i] = (int)((float)i / h);
                t.Start();

                for(int i = 0; i < nWidth - 3; i+=w0)
                {
                    int x0 = scaleX[i];
                    int x1 = scaleX[i + 1];
                  float[] fx0 = imageF[x0];
                    float[] fx1 = imageF[x1];
                    float[] pctX = preComputedTable[i];
                    for(int j = 0; j < nHeight - 3; j+=h0)
                    {
                        int y0 = scaleY[j];
                        int y1 = scaleY[j + 1];
                        //order has been messed up for sometime
                        //should go (x0,y0), (x0,y1), (x1,y1), (x1,y0)
                        float f0 = fx0[y0];
                        float f1 = fx1[y0];
                        float f2 = fx1[y1];
                        float f3 = fx0[y1];
                        float k = pctX[j];
                        DivideGrid(resultant, newImage, i, j, w, h, f0, f1, f2, f3, k);
                    }

                }
                newImage = null;
                si = null;
                imageF = null;
                //Console.WriteLine("Took {0} seconds", DateTime.Now - start);
                return resultant;
            }
            else
            {
                ByteImage image = new ByteImage(b);
                if(si.IsShrinking)
                {
                    var _i = image.ReplicationScale(si.ResultWidth, si.ResultHeight);
                    byte[][] target = new byte[_i.Width][];
                    for(int i = 0; i < _i.Width; i++)
                    {
                        byte[] q = new byte[_i.Height];
                        for(int j = 0; j < _i.Height; j++)
                            target[i][j] = _i[i,j];
                        target[i] = q;
                    }
                    image = null;
                    return target;
                }
                else
                    return b;
            }
        }