public void CopySurface(SurfaceBase source) { if (width == source.width && height == source.height && stride == source.stride && (width * bytesPerPixel) == stride) { unsafe { BGRASurfaceMemory.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) { BGRASurfaceMemory.Copy(GetRowAddressUnchecked(y), source.GetRowAddressUnchecked(y), (ulong)copyWidth * (ulong)bytesPerPixel); } } } }
private static IntPtr Allocate(long bytes, bool allowRetry) { IntPtr block; try { if (bytes >= largeBlockThreshold) { block = BGRASurfaceMemory.AllocateLarge((ulong)bytes); } else { block = BGRASurfaceMemory.Allocate((ulong)bytes); } } catch (OutOfMemoryException) { if (allowRetry) { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); GC.WaitForPendingFinalizers(); return(Allocate(bytes, false)); } else { throw; } } return(block); }
private void Dispose(bool disposing) { if (!disposed) { disposed = true; if (disposing) { } if (valid && parentBlock == null) { if (length >= largeBlockThreshold) { BGRASurfaceMemory.FreeLarge(new IntPtr(voidStar), (ulong)length); } else { BGRASurfaceMemory.Free(new IntPtr(voidStar)); } } parentBlock = null; voidStar = null; valid = false; } }
/// <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++) { BGRASurfaceMemory.Copy(surface.GetRowAddressUnchecked(y), scan0 + (y * stride), length); } } finally { temp.UnlockBits(data); } } return(surface); }
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); }
protected override unsafe void BicubicFitSurfaceUnchecked(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 = 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); } rColCache = (double *)rColCacheIP.ToPointer(); ushort *srcRowPtr = (ushort *)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 graySum = 0; double alphaSum = 0; double totalWeight = 0; ushort *srcPtr = (ushort *)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]; const double a0 = 255.0; const double a1 = 255.0; const double a2 = 255.0; const double a3 = 255.0; alphaSum += (a0 * w0) + (a1 * w1) + (a2 * w2) + (a3 * w3); totalWeight += w0 + w1 + w2 + w3; graySum += (a0 * srcPtr[0] * w0) + (a1 * srcPtr[1] * w1) + (a2 * srcPtr[2] * w2) + (a3 * srcPtr[3] * w3); srcPtr = (ushort *)((byte *)srcPtr + srcStride); } double alpha = alphaSum / totalWeight; double gray; if (alpha == 0) { gray = 0; } else { gray = graySum / alphaSum; // add 0.5 to ensure truncation to uint results in rounding alpha += 0.5; gray += 0.5; } *dstPtr = (ushort)gray; ++dstPtr; rColCache += 4; } // for (dstX... } // for (dstY... BGRASurfaceMemory.Free(rColCacheIP); }