protected override unsafe void BicubicFitSurfaceChecked(SurfaceBase source, Rectangle dstRoi) { Rectangle roi = Rectangle.Intersect(dstRoi, Bounds); IntPtr rColCacheIP = BGRASurfaceMemory.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] = 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; ushort *dstPtr = (ushort *)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] = 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 graySum = 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); ushort *srcPtr = (ushort *)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; graySum += *srcPtr * w * 255.0; alphaSum += 255.0 * w; totalWeight += w; } ++srcPtr; } srcPtr = (ushort *)((byte *)(srcPtr - 4) + srcStride); } double alpha = alphaSum / totalWeight; double gray; if (alpha == 0) { gray = 0; } else { gray = graySum / alphaSum; // add 0.5 to ensure truncation to ushort results in rounding gray += 0.5; } *dstPtr = (ushort)gray; ++dstPtr; } // for (dstX... } // for (dstY... BGRASurfaceMemory.Free(rColCacheIP); }
public override unsafe void SuperSampleFitSurface(SurfaceBase source) { Rectangle dstRoi2 = Rectangle.Intersect(source.Bounds, Bounds); int srcHeight = source.Height; int srcWidth = source.Width; long srcStride = source.Stride / 2; for (int dstY = dstRoi2.Top; dstY < dstRoi2.Bottom; ++dstY) { double srcTop = (double)(dstY * srcHeight) / (double)height; double srcTopFloor = Math.Floor(srcTop); double srcTopWeight = 1 - (srcTop - srcTopFloor); int srcTopInt = (int)srcTopFloor; double srcBottom = (double)((dstY + 1) * srcHeight) / (double)height; double srcBottomFloor = Math.Floor(srcBottom - 0.00001); double srcBottomWeight = srcBottom - srcBottomFloor; int srcBottomInt = (int)srcBottomFloor; ushort *dstPtr = (ushort *)GetPointAddressUnchecked(dstRoi2.Left, dstY); for (int dstX = dstRoi2.Left; dstX < dstRoi2.Right; ++dstX) { double srcLeft = (double)(dstX * srcWidth) / (double)width; double srcLeftFloor = Math.Floor(srcLeft); double srcLeftWeight = 1 - (srcLeft - srcLeftFloor); int srcLeftInt = (int)srcLeftFloor; double srcRight = (double)((dstX + 1) * srcWidth) / (double)width; double srcRightFloor = Math.Floor(srcRight - 0.00001); double srcRightWeight = srcRight - srcRightFloor; int srcRightInt = (int)srcRightFloor; double graySum = 0; double alphaSum = 0; // left fractional edge ushort *srcLeftPtr = (ushort *)source.GetPointAddressUnchecked(srcLeftInt, srcTopInt + 1); for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY) { const double a = 255.0; graySum += srcLeftPtr[0] * srcLeftWeight * a; alphaSum += a * srcLeftWeight; srcLeftPtr = (ushort *)(srcLeftPtr + srcStride); } // right fractional edge ushort *srcRightPtr = (ushort *)source.GetPointAddressUnchecked(srcRightInt, srcTopInt + 1); for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY) { const double a = 255.0; graySum += srcRightPtr[0] * srcRightWeight * a; alphaSum += a * srcRightWeight; srcRightPtr = (ushort *)(srcRightPtr + srcStride); } // top fractional edge ushort *srcTopPtr = (ushort *)source.GetPointAddressUnchecked(srcLeftInt + 1, srcTopInt); for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX) { const double a = 255.0; graySum += srcTopPtr[0] * srcTopWeight * a; alphaSum += a * srcTopWeight; ++srcTopPtr; } // bottom fractional edge ushort *srcBottomPtr = (ushort *)source.GetPointAddressUnchecked(srcLeftInt + 1, srcBottomInt); for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX) { const double a = 255.0; graySum += srcBottomPtr[0] * srcBottomWeight * a; alphaSum += 255.0 * srcBottomWeight; ++srcBottomPtr; } // center area for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY) { ushort *srcPtr = (ushort *)source.GetPointAddressUnchecked(srcLeftInt + 1, srcY); for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX) { graySum += (double)srcPtr[0] * 255.0; alphaSum += 255.0; ++srcPtr; } } // four corner pixels ushort srcTL = *(ushort *)source.GetPointAddress(srcLeftInt, srcTopInt); const double srcTLA = 255.0; graySum += srcTL * (srcTopWeight * srcLeftWeight) * srcTLA; alphaSum += srcTLA * (srcTopWeight * srcLeftWeight); ushort srcTR = *(ushort *)source.GetPointAddress(srcRightInt, srcTopInt); const double srcTRA = 255.0; graySum += srcTR * (srcTopWeight * srcRightWeight) * srcTRA; alphaSum += srcTRA * (srcTopWeight * srcRightWeight); ushort srcBL = *(ushort *)source.GetPointAddress(srcLeftInt, srcBottomInt); const double srcBLA = 255.0; graySum += srcBL * (srcBottomWeight * srcLeftWeight) * srcBLA; alphaSum += srcBLA * (srcBottomWeight * srcLeftWeight); ushort srcBR = *(ushort *)source.GetPointAddress(srcRightInt, srcBottomInt); const double srcBRA = 255.0; graySum += srcBR * (srcBottomWeight * srcRightWeight) * srcBRA; alphaSum += srcBRA * (srcBottomWeight * srcRightWeight); double area = (srcRight - srcLeft) * (srcBottom - srcTop); double alpha = alphaSum / area; double gray; if (alpha == 0) { gray = 0; } else { gray = graySum / alphaSum; } // add 0.5 so that rounding goes in the direction we want it to gray += 0.5; dstPtr[0] = (ushort)gray; ++dstPtr; } } }
public override unsafe void SuperSampleFitSurface(SurfaceBase source) { Rectangle dstRoi2 = Rectangle.Intersect(source.Bounds, Bounds); int srcHeight = source.Height; int srcWidth = source.Width; long srcStride = source.Stride; int height = this.height; int width = this.width; for (int dstY = dstRoi2.Top; dstY < dstRoi2.Bottom; ++dstY) { double srcTop = (double)(dstY * srcHeight) / (double)height; double srcTopFloor = Math.Floor(srcTop); double srcTopWeight = 1 - (srcTop - srcTopFloor); int srcTopInt = (int)srcTopFloor; double srcBottom = (double)((dstY + 1) * srcHeight) / (double)height; double srcBottomFloor = Math.Floor(srcBottom - 0.00001); double srcBottomWeight = srcBottom - srcBottomFloor; int srcBottomInt = (int)srcBottomFloor; ColorBgra16 *dstPtr = (ColorBgra16 *)GetPointAddressUnchecked(dstRoi2.Left, dstY); for (int dstX = dstRoi2.Left; dstX < dstRoi2.Right; ++dstX) { double srcLeft = (double)(dstX * srcWidth) / (double)width; double srcLeftFloor = Math.Floor(srcLeft); double srcLeftWeight = 1 - (srcLeft - srcLeftFloor); int srcLeftInt = (int)srcLeftFloor; double srcRight = (double)((dstX + 1) * srcWidth) / (double)width; double srcRightFloor = Math.Floor(srcRight - 0.00001); double srcRightWeight = srcRight - srcRightFloor; int srcRightInt = (int)srcRightFloor; double blueSum = 0; double greenSum = 0; double redSum = 0; double alphaSum = 0; // left fractional edge ColorBgra16 *srcLeftPtr = (ColorBgra16 *)source.GetPointAddressUnchecked(srcLeftInt, srcTopInt + 1); for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY) { double a = srcLeftPtr->A; blueSum += srcLeftPtr->B * srcLeftWeight * a; greenSum += srcLeftPtr->G * srcLeftWeight * a; redSum += srcLeftPtr->R * srcLeftWeight * a; alphaSum += srcLeftPtr->A * srcLeftWeight; srcLeftPtr = (ColorBgra16 *)((byte *)srcLeftPtr + srcStride); } // right fractional edge ColorBgra16 *srcRightPtr = (ColorBgra16 *)source.GetPointAddressUnchecked(srcRightInt, srcTopInt + 1); for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY) { double a = srcRightPtr->A; blueSum += srcRightPtr->B * srcRightWeight * a; greenSum += srcRightPtr->G * srcRightWeight * a; redSum += srcRightPtr->R * srcRightWeight * a; alphaSum += srcRightPtr->A * srcRightWeight; srcRightPtr = (ColorBgra16 *)((byte *)srcRightPtr + srcStride); } // top fractional edge ColorBgra16 *srcTopPtr = (ColorBgra16 *)source.GetPointAddressUnchecked(srcLeftInt + 1, srcTopInt); for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX) { double a = srcTopPtr->A; blueSum += srcTopPtr->B * srcTopWeight * a; greenSum += srcTopPtr->G * srcTopWeight * a; redSum += srcTopPtr->R * srcTopWeight * a; alphaSum += srcTopPtr->A * srcTopWeight; ++srcTopPtr; } // bottom fractional edge ColorBgra16 *srcBottomPtr = (ColorBgra16 *)source.GetPointAddressUnchecked(srcLeftInt + 1, srcBottomInt); for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX) { double a = srcBottomPtr->A; blueSum += srcBottomPtr->B * srcBottomWeight * a; greenSum += srcBottomPtr->G * srcBottomWeight * a; redSum += srcBottomPtr->R * srcBottomWeight * a; alphaSum += srcBottomPtr->A * srcBottomWeight; ++srcBottomPtr; } // center area for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY) { ColorBgra16 *srcPtr = (ColorBgra16 *)source.GetPointAddressUnchecked(srcLeftInt + 1, srcY); for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX) { double a = srcPtr->A; blueSum += (double)srcPtr->B * a; greenSum += (double)srcPtr->G * a; redSum += (double)srcPtr->R * a; alphaSum += (double)srcPtr->A; ++srcPtr; } } // four corner pixels ColorBgra16 srcTL = *(ColorBgra16 *)source.GetPointAddress(srcLeftInt, srcTopInt); double srcTLA = srcTL.A; blueSum += srcTL.B * (srcTopWeight * srcLeftWeight) * srcTLA; greenSum += srcTL.G * (srcTopWeight * srcLeftWeight) * srcTLA; redSum += srcTL.R * (srcTopWeight * srcLeftWeight) * srcTLA; alphaSum += srcTL.A * (srcTopWeight * srcLeftWeight); ColorBgra16 srcTR = *(ColorBgra16 *)source.GetPointAddress(srcRightInt, srcTopInt); double srcTRA = srcTR.A; blueSum += srcTR.B * (srcTopWeight * srcRightWeight) * srcTRA; greenSum += srcTR.G * (srcTopWeight * srcRightWeight) * srcTRA; redSum += srcTR.R * (srcTopWeight * srcRightWeight) * srcTRA; alphaSum += srcTR.A * (srcTopWeight * srcRightWeight); ColorBgra16 srcBL = *(ColorBgra16 *)source.GetPointAddress(srcLeftInt, srcBottomInt); double srcBLA = srcBL.A; blueSum += srcBL.B * (srcBottomWeight * srcLeftWeight) * srcBLA; greenSum += srcBL.G * (srcBottomWeight * srcLeftWeight) * srcBLA; redSum += srcBL.R * (srcBottomWeight * srcLeftWeight) * srcBLA; alphaSum += srcBL.A * (srcBottomWeight * srcLeftWeight); ColorBgra16 srcBR = *(ColorBgra16 *)source.GetPointAddress(srcRightInt, srcBottomInt); double srcBRA = srcBR.A; blueSum += srcBR.B * (srcBottomWeight * srcRightWeight) * srcBRA; greenSum += srcBR.G * (srcBottomWeight * srcRightWeight) * srcBRA; redSum += srcBR.R * (srcBottomWeight * srcRightWeight) * srcBRA; alphaSum += srcBR.A * (srcBottomWeight * srcRightWeight); double area = (srcRight - srcLeft) * (srcBottom - srcTop); double alpha = alphaSum / area; 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 so that rounding goes in the direction we want it to blue += 0.5; green += 0.5; red += 0.5; alpha += 0.5; dstPtr->Bgra = (ulong)blue + ((ulong)green << 16) + ((ulong)red << 32) + ((ulong)alpha << 48); ++dstPtr; } } }