Пример #1
0
        /// <summary>
        /// Creates a new surface based on the PixelFormat of the Bitmap.
        /// </summary>
        /// <param name="image">The input Bitmap.</param>
        /// <param name="imageMode">The ImageMode of the current surface.</param>
        /// <returns></returns>
        internal static unsafe SurfaceBase CreateFromGdipBitmap(Bitmap image, out ImageModes imageMode)
        {
            int width  = image.Width;
            int height = image.Height;

            imageMode = ImageModes.RGB;
            SurfaceBGRA32 surface = new SurfaceBGRA32(width, height, image.HorizontalResolution, image.VerticalResolution);

            using (Bitmap temp = new Bitmap(image)) // Copy the image to remove any invalid meta-data that causes LockBits to fail.
            {
                BitmapData data = temp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

                try
                {
                    byte *scan0  = (byte *)data.Scan0.ToPointer();
                    int   stride = data.Stride;

                    ulong length = (ulong)width * 4UL;
                    for (int y = 0; y < height; y++)
                    {
                        ImageSurfaceMemory.Copy(surface.GetRowAddressUnchecked(y), scan0 + (y * stride), length);
                    }
                }
                finally
                {
                    temp.UnlockBits(data);
                }
            }


            return(surface);
        }
Пример #2
0
        public void CopySurface(SurfaceBase source)
        {
            if (width == source.width &&
                height == source.height &&
                stride == source.stride &&
                (width * bytesPerPixel) == stride)
            {
                unsafe
                {
                    ImageSurfaceMemory.Copy(scan0.VoidStar,
                                            source.Scan0.VoidStar,
                                            ((ulong)(height - 1) * (ulong)stride) + ((ulong)width * (ulong)bytesPerPixel));
                }
            }
            else
            {
                int copyWidth  = Math.Min(width, source.Width);
                int copyHeight = Math.Min(height, source.Height);

                unsafe
                {
                    for (int y = 0; y < copyHeight; ++y)
                    {
                        ImageSurfaceMemory.Copy(GetRowAddressUnchecked(y), source.GetRowAddressUnchecked(y), (ulong)copyWidth * (ulong)bytesPerPixel);
                    }
                }
            }
        }
Пример #3
0
        private static IntPtr Allocate(long bytes, bool allowRetry)
        {
            IntPtr block;

            try
            {
                if (bytes >= largeBlockThreshold)
                {
                    block = ImageSurfaceMemory.AllocateLarge((ulong)bytes);
                }
                else
                {
                    block = ImageSurfaceMemory.Allocate((ulong)bytes);
                }
            }
            catch (OutOfMemoryException)
            {
                if (allowRetry)
                {
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                    return(Allocate(bytes, false));
                }
                else
                {
                    throw;
                }
            }

            return(block);
        }
Пример #4
0
        private void Dispose(bool disposing)
        {
            if (!disposed)
            {
                disposed = true;

                if (disposing)
                {
                }

                if (valid && parentBlock == null)
                {
                    if (length >= largeBlockThreshold)
                    {
                        ImageSurfaceMemory.FreeLarge(new IntPtr(voidStar), (ulong)length);
                    }
                    else
                    {
                        ImageSurfaceMemory.Free(new IntPtr(voidStar));
                    }
                }

                parentBlock = null;
                voidStar    = null;
                valid       = false;
            }
        }
Пример #5
0
        protected override unsafe void FitSurfaceImpl(SurfaceBase source)
        {
            float lastRowIndex    = height - 1;
            float lastColumnIndex = width - 1;

            IntPtr srcColCachePtr = IntPtr.Zero;

            try
            {
                srcColCachePtr = ImageSurfaceMemory.Allocate((ulong)width * sizeof(float));
                float *srcColCache = (float *)srcColCachePtr;

                // Precompute the source column indexes.
                for (int x = 0; x < width; x++)
                {
                    float u = x / lastColumnIndex;

                    srcColCache[x] = (u * source.Width) - 0.5f;
                }

                for (int y = 0; y < height; y++)
                {
                    ColorBgr8 *destRow = (ColorBgr8 *)GetRowAddressUnchecked(y);
                    float      v       = y / lastRowIndex;

                    float srcY   = (v * source.Height) - 0.5f;
                    int   yint   = (int)srcY;
                    float yfract = srcY - (float)Math.Floor(srcY);

                    for (int x = 0; x < width; x++)
                    {
                        float srcX   = srcColCache[x];
                        int   xint   = (int)srcX;
                        float xfract = srcX - (float)Math.Floor(srcX);

                        // 1st row
                        ColorBgr8 p00 = *(ColorBgr8 *)source.GetPointAddressClamped(xint - 1, yint - 1);
                        ColorBgr8 p10 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 0, yint - 1);
                        ColorBgr8 p20 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 1, yint - 1);
                        ColorBgr8 p30 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 2, yint - 1);

                        // 2nd row
                        ColorBgr8 p01 = *(ColorBgr8 *)source.GetPointAddressClamped(xint - 1, yint + 0);
                        ColorBgr8 p11 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 0, yint + 0);
                        ColorBgr8 p21 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 1, yint + 0);
                        ColorBgr8 p31 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 2, yint + 0);

                        // 3rd row
                        ColorBgr8 p02 = *(ColorBgr8 *)source.GetPointAddressClamped(xint - 1, yint + 1);
                        ColorBgr8 p12 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 0, yint + 1);
                        ColorBgr8 p22 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 1, yint + 1);
                        ColorBgr8 p32 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 2, yint + 1);

                        // 4th row
                        ColorBgr8 p03 = *(ColorBgr8 *)source.GetPointAddressClamped(xint - 1, yint + 2);
                        ColorBgr8 p13 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 0, yint + 2);
                        ColorBgr8 p23 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 1, yint + 2);
                        ColorBgr8 p33 = *(ColorBgr8 *)source.GetPointAddressClamped(xint + 2, yint + 2);

                        float blue0 = BicubicUtil.CubicHermite(p00.B, p10.B, p20.B, p30.B, xfract);
                        float blue1 = BicubicUtil.CubicHermite(p01.B, p11.B, p21.B, p31.B, xfract);
                        float blue2 = BicubicUtil.CubicHermite(p02.B, p12.B, p22.B, p32.B, xfract);
                        float blue3 = BicubicUtil.CubicHermite(p03.B, p13.B, p23.B, p33.B, xfract);

                        float blue = BicubicUtil.CubicHermite(blue0, blue1, blue2, blue3, yfract);

                        float green0 = BicubicUtil.CubicHermite(p00.G, p10.G, p20.G, p30.G, xfract);
                        float green1 = BicubicUtil.CubicHermite(p01.G, p11.G, p21.G, p31.G, xfract);
                        float green2 = BicubicUtil.CubicHermite(p02.G, p12.G, p22.G, p32.G, xfract);
                        float green3 = BicubicUtil.CubicHermite(p03.G, p13.G, p23.G, p33.G, xfract);

                        float green = BicubicUtil.CubicHermite(green0, green1, green2, green3, yfract);

                        float red0 = BicubicUtil.CubicHermite(p00.R, p10.R, p20.R, p30.R, xfract);
                        float red1 = BicubicUtil.CubicHermite(p01.R, p11.R, p21.R, p31.R, xfract);
                        float red2 = BicubicUtil.CubicHermite(p02.R, p12.R, p22.R, p32.R, xfract);
                        float red3 = BicubicUtil.CubicHermite(p03.R, p13.R, p23.R, p33.R, xfract);

                        float red = BicubicUtil.CubicHermite(red0, red1, red2, red3, yfract);

                        destRow->B = (byte)FloatUtil.Clamp(blue, 0, 255);
                        destRow->G = (byte)FloatUtil.Clamp(green, 0, 255);
                        destRow->R = (byte)FloatUtil.Clamp(red, 0, 255);
                        destRow++;
                    }
                }
            }
            finally
            {
                if (srcColCachePtr != IntPtr.Zero)
                {
                    ImageSurfaceMemory.Free(srcColCachePtr);
                    srcColCachePtr = IntPtr.Zero;
                }
            }
        }
Пример #6
0
        protected override unsafe void BicubicFitSurfaceChecked(SurfaceBase source, Rectangle dstRoi)
        {
            Rectangle roi = Rectangle.Intersect(dstRoi, Bounds);

            IntPtr  rColCacheIP = ImageSurfaceMemory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
            double *rColCache   = (double *)rColCacheIP.ToPointer();

            int  srcWidth  = source.Width;
            int  srcHeight = source.Height;
            long srcStride = source.Stride;

            // Precompute and then cache the value of R() for each column
            for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
            {
                double srcColumn      = (double)(dstX * (srcWidth - 1)) / (double)(width - 1);
                double srcColumnFloor = Math.Floor(srcColumn);
                double srcColumnFrac  = srcColumn - srcColumnFloor;

                for (int m = -1; m <= 2; ++m)
                {
                    int    index = (m + 1) + ((dstX - roi.Left) * 4);
                    double x     = m - srcColumnFrac;
                    rColCache[index] = BicubicUtil.R(x);
                }
            }

            // Set this up so we can cache the R()'s for every row
            double *rRowCache = stackalloc double[4];

            for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
            {
                double       srcRow      = (double)(dstY * (srcHeight - 1)) / (double)(height - 1);
                double       srcRowFloor = (double)Math.Floor(srcRow);
                double       srcRowFrac  = srcRow - srcRowFloor;
                int          srcRowInt   = (int)srcRow;
                ColorBgra16 *dstPtr      = (ColorBgra16 *)GetPointAddressUnchecked(roi.Left, dstY);

                // Compute the R() values for this row
                for (int n = -1; n <= 2; ++n)
                {
                    double x = srcRowFrac - n;
                    rRowCache[n + 1] = BicubicUtil.R(x);
                }

                // See Perf Note below
                //int nFirst = Math.Max(-srcRowInt, -1);
                //int nLast = Math.Min(source.height - srcRowInt - 1, 2);

                for (int dstX = roi.Left; dstX < roi.Right; dstX++)
                {
                    double srcColumn      = (double)(dstX * (srcWidth - 1)) / (double)(width - 1);
                    double srcColumnFloor = Math.Floor(srcColumn);
                    int    srcColumnInt   = (int)srcColumn;

                    double blueSum     = 0;
                    double greenSum    = 0;
                    double redSum      = 0;
                    double alphaSum    = 0;
                    double totalWeight = 0;

                    // See Perf Note below
                    //int mFirst = Math.Max(-srcColumnInt, -1);
                    //int mLast = Math.Min(source.width - srcColumnInt - 1, 2);

                    ColorBgra16 *srcPtr = (ColorBgra16 *)source.GetPointAddressUnchecked(srcColumnInt - 1, srcRowInt - 1);

                    for (int n = -1; n <= 2; ++n)
                    {
                        int srcY = srcRowInt + n;

                        for (int m = -1; m <= 2; ++m)
                        {
                            // Perf Note: It actually benchmarks faster on my system to do
                            // a bounds check for every (m,n) than it is to limit the loop
                            // to nFirst-Last and mFirst-mLast.
                            // I'm leaving the code above, albeit commented out, so that
                            // benchmarking between these two can still be performed.
                            if (source.IsVisible(srcColumnInt + m, srcY))
                            {
                                double w0 = rColCache[(m + 1) + (4 * (dstX - roi.Left))];
                                double w1 = rRowCache[n + 1];
                                double w  = w0 * w1;

                                blueSum  += srcPtr->B * w * srcPtr->A;
                                greenSum += srcPtr->G * w * srcPtr->A;
                                redSum   += srcPtr->R * w * srcPtr->A;
                                alphaSum += srcPtr->A * w;

                                totalWeight += w;
                            }

                            ++srcPtr;
                        }

                        srcPtr = (ColorBgra16 *)((byte *)(srcPtr - 4) + srcStride);
                    }

                    double alpha = alphaSum / totalWeight;
                    double blue;
                    double green;
                    double red;

                    if (alpha == 0)
                    {
                        blue  = 0;
                        green = 0;
                        red   = 0;
                    }
                    else
                    {
                        blue  = blueSum / alphaSum;
                        green = greenSum / alphaSum;
                        red   = redSum / alphaSum;

                        // add 0.5 to ensure truncation to ulong results in rounding
                        alpha += 0.5;
                        blue  += 0.5;
                        green += 0.5;
                        red   += 0.5;
                    }

                    dstPtr->Bgra = (ulong)blue + ((ulong)green << 16) + ((ulong)red << 32) + ((ulong)alpha << 48);
                    ++dstPtr;
                } // for (dstX...
            }     // for (dstY...

            ImageSurfaceMemory.Free(rColCacheIP);
        }
Пример #7
0
        protected override unsafe void BicubicFitSurfaceUnchecked(SurfaceBase source, Rectangle dstRoi)
        {
            Rectangle roi = Rectangle.Intersect(dstRoi, Bounds);

            IntPtr  rColCacheIP = ImageSurfaceMemory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
            double *rColCache   = (double *)rColCacheIP.ToPointer();

            int  srcWidth  = source.Width;
            int  srcHeight = source.Height;
            long srcStride = source.Stride;

            // Precompute and then cache the value of R() for each column
            for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
            {
                double srcColumn      = (double)(dstX * (srcWidth - 1)) / (double)(width - 1);
                double srcColumnFloor = Math.Floor(srcColumn);
                double srcColumnFrac  = srcColumn - srcColumnFloor;

                for (int m = -1; m <= 2; ++m)
                {
                    int    index = (m + 1) + ((dstX - roi.Left) * 4);
                    double x     = m - srcColumnFrac;
                    rColCache[index] = BicubicUtil.R(x);
                }
            }

            // Set this up so we can cache the R()'s for every row
            double *rRowCache = stackalloc double[4];

            for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
            {
                double       srcRow      = (double)(dstY * (srcHeight - 1)) / (double)(height - 1);
                double       srcRowFloor = Math.Floor(srcRow);
                double       srcRowFrac  = srcRow - srcRowFloor;
                int          srcRowInt   = (int)srcRow;
                ColorBgra16 *dstPtr      = (ColorBgra16 *)GetPointAddressUnchecked(roi.Left, dstY);

                // Compute the R() values for this row
                for (int n = -1; n <= 2; ++n)
                {
                    double x = srcRowFrac - n;
                    rRowCache[n + 1] = BicubicUtil.R(x);
                }

                rColCache = (double *)rColCacheIP.ToPointer();
                ColorBgra16 *srcRowPtr = (ColorBgra16 *)source.GetRowAddressUnchecked(srcRowInt - 1);

                for (int dstX = roi.Left; dstX < roi.Right; dstX++)
                {
                    double srcColumn      = (double)(dstX * (srcWidth - 1)) / (double)(width - 1);
                    double srcColumnFloor = Math.Floor(srcColumn);
                    int    srcColumnInt   = (int)srcColumn;

                    double blueSum     = 0;
                    double greenSum    = 0;
                    double redSum      = 0;
                    double alphaSum    = 0;
                    double totalWeight = 0;

                    ColorBgra16 *srcPtr = srcRowPtr + srcColumnInt - 1;
                    for (int n = 0; n <= 3; ++n)
                    {
                        double w0 = rColCache[0] * rRowCache[n];
                        double w1 = rColCache[1] * rRowCache[n];
                        double w2 = rColCache[2] * rRowCache[n];
                        double w3 = rColCache[3] * rRowCache[n];

                        double a0 = srcPtr[0].A;
                        double a1 = srcPtr[1].A;
                        double a2 = srcPtr[2].A;
                        double a3 = srcPtr[3].A;

                        alphaSum    += (a0 * w0) + (a1 * w1) + (a2 * w2) + (a3 * w3);
                        totalWeight += w0 + w1 + w2 + w3;

                        blueSum  += (a0 * srcPtr[0].B * w0) + (a1 * srcPtr[1].B * w1) + (a2 * srcPtr[2].B * w2) + (a3 * srcPtr[3].B * w3);
                        greenSum += (a0 * srcPtr[0].G * w0) + (a1 * srcPtr[1].G * w1) + (a2 * srcPtr[2].G * w2) + (a3 * srcPtr[3].G * w3);
                        redSum   += (a0 * srcPtr[0].R * w0) + (a1 * srcPtr[1].R * w1) + (a2 * srcPtr[2].R * w2) + (a3 * srcPtr[3].R * w3);

                        srcPtr = (ColorBgra16 *)((byte *)srcPtr + srcStride);
                    }

                    double alpha = alphaSum / totalWeight;

                    double blue;
                    double green;
                    double red;

                    if (alpha == 0)
                    {
                        blue  = 0;
                        green = 0;
                        red   = 0;
                    }
                    else
                    {
                        blue  = blueSum / alphaSum;
                        green = greenSum / alphaSum;
                        red   = redSum / alphaSum;

                        // add 0.5 to ensure truncation to ulong results in rounding
                        alpha += 0.5;
                        blue  += 0.5;
                        green += 0.5;
                        red   += 0.5;
                    }

                    dstPtr->Bgra = (ulong)blue + ((ulong)green << 16) + ((ulong)red << 32) + ((ulong)alpha << 48);
                    ++dstPtr;
                    rColCache += 4;
                } // for (dstX...
            }     // for (dstY...

            ImageSurfaceMemory.Free(rColCacheIP);
        }
Пример #8
0
        protected override unsafe void FitSurfaceImpl(SurfaceBase source)
        {
            float lastRowIndex    = height - 1;
            float lastColumnIndex = width - 1;

            IntPtr srcColCachePtr = IntPtr.Zero;

            try
            {
                srcColCachePtr = ImageSurfaceMemory.Allocate((ulong)width * sizeof(float));
                float *srcColCache = (float *)srcColCachePtr;

                // Precompute the source column indexes.
                for (int x = 0; x < width; x++)
                {
                    float u = x / lastColumnIndex;

                    srcColCache[x] = (u * source.Width) - 0.5f;
                }

                for (int y = 0; y < height; y++)
                {
                    ushort *destRow = (ushort *)GetRowAddressUnchecked(y);
                    float   v       = y / lastRowIndex;

                    float srcY   = (v * source.Height) - 0.5f;
                    int   yint   = (int)srcY;
                    float yfract = srcY - (float)Math.Floor(srcY);

                    for (int x = 0; x < width; x++)
                    {
                        float srcX   = srcColCache[x];
                        int   xint   = (int)srcX;
                        float xfract = srcX - (float)Math.Floor(srcX);

                        // 1st row
                        ushort p00 = *(ushort *)source.GetPointAddressClamped(xint - 1, yint - 1);
                        ushort p10 = *(ushort *)source.GetPointAddressClamped(xint + 0, yint - 1);
                        ushort p20 = *(ushort *)source.GetPointAddressClamped(xint + 1, yint - 1);
                        ushort p30 = *(ushort *)source.GetPointAddressClamped(xint + 2, yint - 1);

                        // 2nd row
                        ushort p01 = *(ushort *)source.GetPointAddressClamped(xint - 1, yint + 0);
                        ushort p11 = *(ushort *)source.GetPointAddressClamped(xint + 0, yint + 0);
                        ushort p21 = *(ushort *)source.GetPointAddressClamped(xint + 1, yint + 0);
                        ushort p31 = *(ushort *)source.GetPointAddressClamped(xint + 2, yint + 0);

                        // 3rd row
                        ushort p02 = *(ushort *)source.GetPointAddressClamped(xint - 1, yint + 1);
                        ushort p12 = *(ushort *)source.GetPointAddressClamped(xint + 0, yint + 1);
                        ushort p22 = *(ushort *)source.GetPointAddressClamped(xint + 1, yint + 1);
                        ushort p32 = *(ushort *)source.GetPointAddressClamped(xint + 2, yint + 1);

                        // 4th row
                        ushort p03 = *(ushort *)source.GetPointAddressClamped(xint - 1, yint + 2);
                        ushort p13 = *(ushort *)source.GetPointAddressClamped(xint + 0, yint + 2);
                        ushort p23 = *(ushort *)source.GetPointAddressClamped(xint + 1, yint + 2);
                        ushort p33 = *(ushort *)source.GetPointAddressClamped(xint + 2, yint + 2);

                        float gray0 = BicubicUtil.CubicHermite(p00, p10, p20, p30, xfract);
                        float gray1 = BicubicUtil.CubicHermite(p01, p11, p21, p31, xfract);
                        float gray2 = BicubicUtil.CubicHermite(p02, p12, p22, p32, xfract);
                        float gray3 = BicubicUtil.CubicHermite(p03, p13, p23, p33, xfract);

                        float gray = BicubicUtil.CubicHermite(gray0, gray1, gray2, gray3, yfract);

                        *destRow = (ushort)FloatUtil.Clamp(gray, 0, 32768);
                        destRow++;
                    }
                }
            }
            finally
            {
                if (srcColCachePtr != IntPtr.Zero)
                {
                    ImageSurfaceMemory.Free(srcColCachePtr);
                    srcColCachePtr = IntPtr.Zero;
                }
            }
        }
Пример #9
0
        protected override unsafe void FitSurfaceImpl(SurfaceBase source)
        {
            float lastRowIndex    = height - 1;
            float lastColumnIndex = width - 1;

            IntPtr srcColCachePtr = IntPtr.Zero;

            try
            {
                srcColCachePtr = ImageSurfaceMemory.Allocate((ulong)width * sizeof(float));
                float *srcColCache = (float *)srcColCachePtr;

                // Precompute the source column indexes.
                for (int x = 0; x < width; x++)
                {
                    float u = x / lastColumnIndex;

                    srcColCache[x] = (u * source.Width) - 0.5f;
                }

                for (int y = 0; y < height; y++)
                {
                    ColorCmyk8 *destRow = (ColorCmyk8 *)GetRowAddressUnchecked(y);
                    float       v       = y / lastRowIndex;

                    float srcY   = (v * source.Height) - 0.5f;
                    int   yint   = (int)srcY;
                    float yfract = srcY - (float)Math.Floor(srcY);

                    for (int x = 0; x < width; x++)
                    {
                        float srcX   = srcColCache[x];
                        int   xint   = (int)srcX;
                        float xfract = srcX - (float)Math.Floor(srcX);

                        // 1st row
                        ColorCmyk8 p00 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint - 1, yint - 1);
                        ColorCmyk8 p10 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 0, yint - 1);
                        ColorCmyk8 p20 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 1, yint - 1);
                        ColorCmyk8 p30 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 2, yint - 1);

                        // 2nd row
                        ColorCmyk8 p01 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint - 1, yint + 0);
                        ColorCmyk8 p11 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 0, yint + 0);
                        ColorCmyk8 p21 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 1, yint + 0);
                        ColorCmyk8 p31 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 2, yint + 0);

                        // 3rd row
                        ColorCmyk8 p02 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint - 1, yint + 1);
                        ColorCmyk8 p12 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 0, yint + 1);
                        ColorCmyk8 p22 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 1, yint + 1);
                        ColorCmyk8 p32 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 2, yint + 1);

                        // 4th row
                        ColorCmyk8 p03 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint - 1, yint + 2);
                        ColorCmyk8 p13 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 0, yint + 2);
                        ColorCmyk8 p23 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 1, yint + 2);
                        ColorCmyk8 p33 = *(ColorCmyk8 *)source.GetPointAddressClamped(xint + 2, yint + 2);

                        float cyan0 = BicubicUtil.CubicHermite(p00.C, p10.C, p20.C, p30.C, xfract);
                        float cyan1 = BicubicUtil.CubicHermite(p01.C, p11.C, p21.C, p31.C, xfract);
                        float cyan2 = BicubicUtil.CubicHermite(p02.C, p12.C, p22.C, p32.C, xfract);
                        float cyan3 = BicubicUtil.CubicHermite(p03.C, p13.C, p23.C, p33.C, xfract);

                        float cyan = BicubicUtil.CubicHermite(cyan0, cyan1, cyan2, cyan3, yfract);

                        float magenta0 = BicubicUtil.CubicHermite(p00.M, p10.M, p20.M, p30.M, xfract);
                        float magenta1 = BicubicUtil.CubicHermite(p01.M, p11.M, p21.M, p31.M, xfract);
                        float magenta2 = BicubicUtil.CubicHermite(p02.M, p12.M, p22.M, p32.M, xfract);
                        float magenta3 = BicubicUtil.CubicHermite(p03.M, p13.M, p23.M, p33.M, xfract);

                        float magenta = BicubicUtil.CubicHermite(magenta0, magenta1, magenta2, magenta3, yfract);

                        float yellow0 = BicubicUtil.CubicHermite(p00.Y, p10.Y, p20.Y, p30.Y, xfract);
                        float yellow1 = BicubicUtil.CubicHermite(p01.Y, p11.Y, p21.Y, p31.Y, xfract);
                        float yellow2 = BicubicUtil.CubicHermite(p02.Y, p12.Y, p22.Y, p32.Y, xfract);
                        float yellow3 = BicubicUtil.CubicHermite(p03.Y, p13.Y, p23.Y, p33.Y, xfract);

                        float yellow = BicubicUtil.CubicHermite(yellow0, yellow1, yellow2, yellow3, yfract);

                        float black0 = BicubicUtil.CubicHermite(p00.K, p10.K, p20.K, p30.K, xfract);
                        float black1 = BicubicUtil.CubicHermite(p01.K, p11.K, p21.K, p31.K, xfract);
                        float black2 = BicubicUtil.CubicHermite(p02.K, p12.K, p22.K, p32.K, xfract);
                        float black3 = BicubicUtil.CubicHermite(p03.K, p13.K, p23.K, p33.K, xfract);

                        float black = BicubicUtil.CubicHermite(black0, black1, black2, black3, yfract);

                        destRow->C = (byte)FloatUtil.Clamp(cyan, 0, 255);
                        destRow->M = (byte)FloatUtil.Clamp(magenta, 0, 255);
                        destRow->Y = (byte)FloatUtil.Clamp(yellow, 0, 255);
                        destRow->K = (byte)FloatUtil.Clamp(black, 0, 255);
                        destRow++;
                    }
                }
            }
            finally
            {
                if (srcColCachePtr != IntPtr.Zero)
                {
                    ImageSurfaceMemory.Free(srcColCachePtr);
                    srcColCachePtr = IntPtr.Zero;
                }
            }
        }