1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105 |
- using SmartCoalApplication.SystemLayer;
- using System;
- using System.Collections.Generic;
- using System.Drawing;
- using System.Drawing.Imaging;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace SmartCoalApplication.Core
- {
- [Serializable]
- public sealed class Surface : IDisposable, ICloneable
- {
- /// <summary>
- /// 图像内存块
- /// </summary>
- private MemoryBlock scan0;
- /// <summary>
- /// 宽
- /// </summary>
- private int width;
- /// <summary>
- /// 高
- /// </summary>
- private int height;
- /// <summary>
- /// 扫描宽度
- /// </summary>
- private int stride;
- /// <summary>
- /// 释放标记
- /// </summary>
- private bool disposed = false;
- /// <summary>
- /// 存储打开时图片的格式
- /// </summary>
- private PixelFormat pixelFormat = PixelFormat.Format32bppArgb;
- /// <summary>
- /// 缩略图
- /// </summary>
- private Bitmap thumbnail;
- /// <summary>
- /// 原图的备份
- /// </summary>
- private Bitmap thumborigin;
- /// <summary>
- /// 创建原图的备份
- /// </summary>
- public void CreateThumborigin()
- {
- this.thumborigin = CreateAliasedBitmap();
- }
- public Bitmap Thumborigin
- {
- get
- {
- return this.thumborigin;
- }
- set
- {
- this.thumborigin = value;
- }
- }
- public Bitmap Thumbnail
- {
- get
- {
- return this.thumbnail;
- }
- }
- /// <summary>
- /// 创建缩略图
- /// </summary>
- public void CreateThumbnail()
- {
- Bitmap origin = CreateAliasedBitmap();
- Bitmap bitmap = null;
- if (origin.Width > origin.Height)
- {
- bitmap = MakeThumbnail(CreateAliasedBitmap(), 90, 90, "W");
- }
- else if (origin.Height > origin.Width)
- {
- bitmap = MakeThumbnail(CreateAliasedBitmap(), 90, 90, "H");
- }
- else
- {
- bitmap = MakeThumbnail(CreateAliasedBitmap(), 90, 90, "W");
- }
- this.thumbnail = bitmap;
- }
- public PixelFormat PixelFormat
- {
- get
- {
- return this.pixelFormat;
- }
- set
- {
- this.pixelFormat = value;
- }
- }
- public bool IsDisposed
- {
- get
- {
- return this.disposed;
- }
- }
- public MemoryBlock Scan0
- {
- get
- {
- if (this.disposed)
- {
- throw new ObjectDisposedException("Surface");
- }
- return this.scan0;
- }
- }
- public int Width
- {
- get
- {
- return this.width;
- }
- }
- public int Height
- {
- get
- {
- return this.height;
- }
- }
- public int Stride
- {
- get
- {
- return this.stride;
- }
- }
- public Size Size
- {
- get
- {
- return new Size(this.width, this.height);
- }
- }
- public Rectangle Bounds
- {
- get
- {
- return new Rectangle(0, 0, width, height);
- }
- }
- public Surface(Size size)
- : this(size.Width, size.Height)
- {
- }
- public Surface(int width, int height)
- {
- int stride;
- long bytes;
- try
- {
- stride = checked(width * ColorBgra.SizeOf);
- bytes = (long)height * (long)stride;
- }
- catch (OverflowException ex)
- {
- throw new OutOfMemoryException("Dimensions are too large - not enough memory, width=" + width.ToString() + ", height=" + height.ToString(), ex);
- }
- MemoryBlock scan0 = new MemoryBlock(width, height);
- Create(width, height, stride, scan0);
- }
- private Surface(int width, int height, int stride, MemoryBlock scan0)
- {
- Create(width, height, stride, scan0);
- }
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "width")]
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "height")]
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "stride")]
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "scan0")]
- private void Create(int width, int height, int stride, MemoryBlock scan0)
- {
- this.width = width;
- this.height = height;
- this.stride = stride;
- this.scan0 = scan0;
- }
- ~Surface()
- {
- Dispose(false);
- }
- public Surface CreateWindow(Rectangle bounds)
- {
- return CreateWindow(bounds.X, bounds.Y, bounds.Width, bounds.Height);
- }
- public Surface CreateWindow(int x, int y, int windowWidth, int windowHeight)
- {
- if (disposed)
- {
- throw new ObjectDisposedException("Surface");
- }
- if (windowHeight == 0)
- {
- throw new ArgumentOutOfRangeException("windowHeight", "must be greater than zero");
- }
- Rectangle original = this.Bounds;
- Rectangle sub = new Rectangle(x, y, windowWidth, windowHeight);
- Rectangle clipped = Rectangle.Intersect(original, sub);
- if (clipped != sub)
- {
- throw new ArgumentOutOfRangeException("bounds", new Rectangle(x, y, windowWidth, windowHeight),
- "bounds parameters must be a subset of this Surface's bounds");
- }
- long offset = ((long)stride * (long)y) + ((long)ColorBgra.SizeOf * (long)x);
- long length = ((windowHeight - 1) * (long)stride) + (long)windowWidth * (long)ColorBgra.SizeOf;
- MemoryBlock block = new MemoryBlock(this.scan0, offset, length);
- return new Surface(windowWidth, windowHeight, this.stride, block);
- }
- public long GetRowByteOffset(int y)
- {
- if (y < 0 || y >= height)
- {
- throw new ArgumentOutOfRangeException("y", "Out of bounds: y=" + y.ToString());
- }
- return (long)y * (long)stride;
- }
- public OpenCvSharp.Mat CreatedAliasedMat(OpenCvSharp.Mat mat)
- {
- if (mat == null)//<-CreateAliasedBitmap
- return Tools.ToMat(this.CreateAliasedBitmap());// OpenCvSharp.Extensions.BitmapConverter.ToMat(this.CreateAliasedBitmap());
- return mat/*.Clone()*/;//待测试
- }
- public unsafe long GetRowByteOffsetUnchecked(int yline)
- {
- return (long)yline * (long)stride;
- }
- public unsafe ColorBgra* GetRowAddress(int yline)
- {
- return (ColorBgra*)(((byte*)scan0.VoidStar) + GetRowByteOffset(yline));
- }
- public unsafe ColorBgra* GetRowAddressUnchecked(int yline)
- {
- return (ColorBgra*)(((byte*)scan0.VoidStar) + GetRowByteOffsetUnchecked(yline));
- }
- public long GetColumnByteOffsetUnchecked(int x)
- {
- return (long)x * (long)ColorBgra.SizeOf;
- }
- public long GetPointByteOffsetUnchecked(int x, int y)
- {
- return GetRowByteOffsetUnchecked(y) + GetColumnByteOffsetUnchecked(x);
- }
- public ColorBgra GetPoint(int x, int y)
- {
- return this[x, y];
- }
- public unsafe ColorBgra* GetPointAddress(int x, int y)
- {
- if (x < 0 || x >= Width)
- {
- throw new ArgumentOutOfRangeException("x", "Out of bounds: x=" + x.ToString());
- }
- return GetRowAddress(y) + x;
- }
- public unsafe ColorBgra* GetPointAddress(Point pt)
- {
- return GetPointAddress(pt.X, pt.Y);
- }
- public unsafe ColorBgra* GetPointAddressUnchecked(int x, int y)
- {
- return unchecked(x + (ColorBgra*)(((byte*)scan0.VoidStar) + (y * stride)));
- }
- public bool IsVisible(int x, int y)
- {
- return x >= 0 && x < width && y >= 0 && y < height;
- }
- public bool IsRowVisible(int y)
- {
- return y >= 0 && y < Height;
- }
- public bool IsColumnVisible(int x)
- {
- return x >= 0 && x < Width;
- }
- public ColorBgra this[int x, int y]
- {
- get
- {
- if (disposed)
- {
- throw new ObjectDisposedException("Surface");
- }
- if (x < 0 || y < 0 || x >= this.width || y >= this.height)
- {
- throw new ArgumentOutOfRangeException("(x,y)", new Point(x, y), "Coordinates out of range, max=" + new Size(width - 1, height - 1).ToString());
- }
- unsafe
- {
- return *GetPointAddressUnchecked(x, y);
- }
- }
- set
- {
- if (disposed)
- {
- throw new ObjectDisposedException("Surface");
- }
- if (x < 0 || y < 0 || x >= this.width || y >= this.height)
- {
- throw new ArgumentOutOfRangeException("(x,y)", new Point(x, y), "Coordinates out of range, max=" + new Size(width - 1, height - 1).ToString());
- }
- unsafe
- {
- *GetPointAddressUnchecked(x, y) = value;
- }
- }
- }
- public Bitmap CreateAliasedBitmap(bool alpha)
- {
- return CreateAliasedBitmap(this.Bounds, alpha);
- }
- public Bitmap CreateAliasedBitmap()
- {
- return CreateAliasedBitmap(this.Bounds);
- }
- public Bitmap CreateAliasedBitmap(Rectangle bounds)
- {
- return CreateAliasedBitmap(bounds, true);
- }
- public Bitmap CreateAliasedBitmap(Rectangle bounds, bool alpha)
- {
- if (disposed)
- {
- throw new ObjectDisposedException("Surface");
- }
- if (bounds.IsEmpty)
- {
- throw new ArgumentOutOfRangeException();
- }
- Rectangle clipped = Rectangle.Intersect(this.Bounds, bounds);
- if (clipped != bounds)
- {
- throw new ArgumentOutOfRangeException();
- }
- unsafe
- {
- return new Bitmap(bounds.Width, bounds.Height, stride, alpha ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppRgb,
- new IntPtr((void*)((byte*)scan0.VoidStar + GetPointByteOffsetUnchecked(bounds.X, bounds.Y))));
- }
- }
- public static Surface CopyFromBitmap(Bitmap bitmap)
- {
- Surface surface = new Surface(bitmap.Width, bitmap.Height);
- BitmapData bd = bitmap.LockBits(surface.Bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
- unsafe
- {
- for (int y = 0; y < bd.Height; ++y)
- {
- Memory.Copy((void*)surface.GetRowAddress(y),
- (byte*)bd.Scan0.ToPointer() + (y * bd.Stride), (ulong)bd.Width * ColorBgra.SizeOf);
- }
- }
- bitmap.UnlockBits(bd);
- return surface;
- }
- public void CopySurface(Surface source)
- {
- if (disposed)
- {
- throw new ObjectDisposedException("Surface");
- }
- if (this.stride == source.stride &&
- (this.width * ColorBgra.SizeOf) == this.stride &&
- this.width == source.width &&
- this.height == source.height)
- {
- unsafe
- {
- Memory.Copy(this.scan0.VoidStar,
- source.scan0.VoidStar,
- ((ulong)(height - 1) * (ulong)stride) + ((ulong)width * (ulong)ColorBgra.SizeOf));
- }
- }
- else
- {
- int copyWidth = Math.Min(width, source.width);
- int copyHeight = Math.Min(height, source.height);
- unsafe
- {
- for (int y = 0; y < copyHeight; ++y)
- {
- Memory.Copy(GetRowAddressUnchecked(y), source.GetRowAddressUnchecked(y), (ulong)copyWidth * (ulong)ColorBgra.SizeOf);
- }
- }
- }
- }
- object ICloneable.Clone()
- {
- return Clone();
- }
- public Surface Clone()
- {
- if (disposed)
- {
- throw new ObjectDisposedException("Surface");
- }
- Surface ret = new Surface(this.Size);
- ret.CopySurface(this);
- return ret;
- }
- public void Clear()
- {
- Clear(ColorBgra.FromBgra(255, 255, 255, 255));
- }
- public void Clear(ColorBgra color)
- {
- //new UnaryPixelOps.Constant(color).Apply(this, this.Bounds);
- }
- public void SuperSamplingFitSurface(Surface source, Rectangle dstRoi)
- {
- if (source.Width == Width && source.Height == Height)
- {
- CopySurface(source);
- }
- else if (source.Width <= Width || source.Height <= Height)
- {
- if (source.width < 2 || source.height < 2 || this.width < 2 || this.height < 2)
- {
- this.NearestNeighborFitSurface(source, dstRoi);
- }
- else
- {
- this.BicubicFitSurface(source, dstRoi);
- }
- }
- else unsafe
- {
- Rectangle dstRoi2 = Rectangle.Intersect(dstRoi, this.Bounds);
- for (int dstY = dstRoi2.Top; dstY < dstRoi2.Bottom; ++dstY)
- {
- double srcTop = (double)(dstY * source.height) / (double)height;
- double srcTopFloor = Math.Floor(srcTop);
- double srcTopWeight = 1 - (srcTop - srcTopFloor);
- int srcTopInt = (int)srcTopFloor;
- double srcBottom = (double)((dstY + 1) * source.height) / (double)height;
- double srcBottomFloor = Math.Floor(srcBottom - 0.00001);
- double srcBottomWeight = srcBottom - srcBottomFloor;
- int srcBottomInt = (int)srcBottomFloor;
- ColorBgra* dstPtr = this.GetPointAddressUnchecked(dstRoi2.Left, dstY);
- for (int dstX = dstRoi2.Left; dstX < dstRoi2.Right; ++dstX)
- {
- double srcLeft = (double)(dstX * source.width) / (double)width;
- double srcLeftFloor = Math.Floor(srcLeft);
- double srcLeftWeight = 1 - (srcLeft - srcLeftFloor);
- int srcLeftInt = (int)srcLeftFloor;
- double srcRight = (double)((dstX + 1) * source.width) / (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
- ColorBgra* srcLeftPtr = 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 = (ColorBgra*)((byte*)srcLeftPtr + source.stride);
- }
- // right fractional edge
- ColorBgra* srcRightPtr = 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 = (ColorBgra*)((byte*)srcRightPtr + source.stride);
- }
- // top fractional edge
- ColorBgra* srcTopPtr = 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
- ColorBgra* srcBottomPtr = 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)
- {
- ColorBgra* srcPtr = 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
- ColorBgra srcTL = source.GetPoint(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);
- ColorBgra srcTR = source.GetPoint(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);
- ColorBgra srcBL = source.GetPoint(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);
- ColorBgra srcBR = source.GetPoint(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 = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
- ++dstPtr;
- }
- }
- }
- }
- public void NearestNeighborFitSurface(Surface source, Rectangle dstRoi)
- {
- Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);
- unsafe
- {
- for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
- {
- int srcY = (dstY * source.height) / height;
- ColorBgra* srcRow = source.GetRowAddressUnchecked(srcY);
- ColorBgra* dstPtr = this.GetPointAddressUnchecked(roi.Left, dstY);
- for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
- {
- int srcX = (dstX * source.width) / width;
- *dstPtr = *(srcRow + srcX);
- ++dstPtr;
- }
- }
- }
- }
- private double CubeClamped(double x)
- {
- if (x >= 0)
- {
- return x * x * x;
- }
- else
- {
- return 0;
- }
- }
- private double R(double x)
- {
- return (CubeClamped(x + 2) - (4 * CubeClamped(x + 1)) + (6 * CubeClamped(x)) - (4 * CubeClamped(x - 1))) / 6;
- }
- public void BicubicFitSurface(Surface source, Rectangle dstRoi)
- {
- float leftF = (1 * (float)(width - 1)) / (float)(source.width - 1);
- float topF = (1 * (height - 1)) / (float)(source.height - 1);
- float rightF = ((float)(source.width - 3) * (float)(width - 1)) / (float)(source.width - 1);
- float bottomF = ((float)(source.Height - 3) * (float)(height - 1)) / (float)(source.height - 1);
- int left = (int)Math.Ceiling((double)leftF);
- int top = (int)Math.Ceiling((double)topF);
- int right = (int)Math.Floor((double)rightF);
- int bottom = (int)Math.Floor((double)bottomF);
- Rectangle[] rois = new Rectangle[] {
- Rectangle.FromLTRB(left, top, right, bottom),
- new Rectangle(0, 0, width, top),
- new Rectangle(0, top, left, height - top),
- new Rectangle(right, top, width - right, height - top),
- new Rectangle(left, bottom, right - left, height - bottom)
- };
- for (int i = 0; i < rois.Length; ++i)
- {
- rois[i].Intersect(dstRoi);
- if (rois[i].Width > 0 && rois[i].Height > 0)
- {
- if (i == 0)
- {
- BicubicFitSurfaceUnchecked(source, rois[i]);
- }
- else
- {
- BicubicFitSurfaceChecked(source, rois[i]);
- }
- }
- }
- }
- private void BicubicFitSurfaceChecked(Surface source, Rectangle dstRoi)
- {
- if (this.width < 2 || this.height < 2 || source.width < 2 || source.height < 2)
- {
- SuperSamplingFitSurface(source, dstRoi);
- }
- else
- {
- unsafe
- {
- Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);
- Rectangle roiIn = Rectangle.Intersect(dstRoi, new Rectangle(1, 1, width - 1, height - 1));
- IntPtr rColCacheIP = Memory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
- double* rColCache = (double*)rColCacheIP.ToPointer();
- // Precompute and then cache the value of R() for each column
- for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
- {
- double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
- double srcColumnFloor = Math.Floor(srcColumn);
- double srcColumnFrac = srcColumn - srcColumnFloor;
- int srcColumnInt = (int)srcColumn;
- 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 * (source.height - 1)) / (double)(height - 1);
- double srcRowFloor = (double)Math.Floor(srcRow);
- double srcRowFrac = srcRow - srcRowFloor;
- int srcRowInt = (int)srcRow;
- ColorBgra* dstPtr = this.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 * (source.width - 1)) / (double)(width - 1);
- double srcColumnFloor = Math.Floor(srcColumn);
- double srcColumnFrac = srcColumn - srcColumnFloor;
- 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);
- ColorBgra* srcPtr = 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 = (ColorBgra*)((byte*)(srcPtr - 4) + source.stride);
- }
- 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 uint results in rounding
- alpha += 0.5;
- blue += 0.5;
- green += 0.5;
- red += 0.5;
- }
- dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
- ++dstPtr;
- } // for (dstX...
- } // for (dstY...
- Memory.Free(rColCacheIP);
- } // unsafe
- }
- }
- public void BicubicFitSurfaceUnchecked(Surface source, Rectangle dstRoi)
- {
- if (this.width < 2 || this.height < 2 || source.width < 2 || source.height < 2)
- {
- SuperSamplingFitSurface(source, dstRoi);
- }
- else
- {
- unsafe
- {
- Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);
- Rectangle roiIn = Rectangle.Intersect(dstRoi, new Rectangle(1, 1, width - 1, height - 1));
- IntPtr rColCacheIP = Memory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
- double* rColCache = (double*)rColCacheIP.ToPointer();
- // Precompute and then cache the value of R() for each column
- for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
- {
- double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
- double srcColumnFloor = Math.Floor(srcColumn);
- double srcColumnFrac = srcColumn - srcColumnFloor;
- int srcColumnInt = (int)srcColumn;
- 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 * (source.height - 1)) / (double)(height - 1);
- double srcRowFloor = Math.Floor(srcRow);
- double srcRowFrac = srcRow - srcRowFloor;
- int srcRowInt = (int)srcRow;
- ColorBgra* dstPtr = this.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();
- ColorBgra* srcRowPtr = source.GetRowAddressUnchecked(srcRowInt - 1);
- for (int dstX = roi.Left; dstX < roi.Right; dstX++)
- {
- double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
- double srcColumnFloor = Math.Floor(srcColumn);
- double srcColumnFrac = srcColumn - srcColumnFloor;
- int srcColumnInt = (int)srcColumn;
- double blueSum = 0;
- double greenSum = 0;
- double redSum = 0;
- double alphaSum = 0;
- double totalWeight = 0;
- ColorBgra* 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 = (ColorBgra*)((byte*)srcPtr + source.stride);
- }
- 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 uint results in rounding
- alpha += 0.5;
- blue += 0.5;
- green += 0.5;
- red += 0.5;
- }
- dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
- ++dstPtr;
- rColCache += 4;
- } // for (dstX...
- } // for (dstY...
- Memory.Free(rColCacheIP);
- } // unsafe
- }
- }
- /// <summary>
- /// Releases all resources held by this Surface object.
- /// </summary>
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- private void Dispose(bool disposing)
- {
- if (!disposed)
- {
- disposed = true;
- if (disposing)
- {
- scan0.Dispose();
- scan0 = null;
- }
- }
- }
- ///<summary>
- /// 生成缩略图
- /// </summary>
- /// <param name="originalImage">源图片</param>
- /// <param name="width">缩略图宽度</param>
- /// <param name="height">缩略图高度</param>
- /// <param name="mode">生成缩略图的方式</param>
- public Bitmap MakeThumbnail(Image originalImage, int swidth, int sheight, string mode)
- {
- int towidth = swidth;
- int toheight = sheight;
- int x = 0;
- int y = 0;
- int ow = originalImage.Width;
- int oh = originalImage.Height;
- switch (mode)
- {
- case "HW"://指定高宽缩放(可能变形)
- break;
- case "W"://指定宽,高按比例
- toheight = originalImage.Height * swidth / originalImage.Width;
- break;
- case "H"://指定高,宽按比例
- towidth = originalImage.Width * sheight / originalImage.Height;
- break;
- case "Cut"://指定高宽裁减(不变形)
- if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
- {
- oh = originalImage.Height;
- ow = originalImage.Height * towidth / toheight;
- y = 0;
- x = (originalImage.Width - ow) / 2;
- }
- else
- {
- ow = originalImage.Width;
- oh = originalImage.Width * sheight / towidth;
- x = 0;
- y = (originalImage.Height - oh) / 2;
- }
- break;
- default:
- break;
- }
- //新建一个bmp图片
- Bitmap bitmap = new System.Drawing.Bitmap(towidth, toheight);
- //新建一个画板
- Graphics g = System.Drawing.Graphics.FromImage(bitmap);
- //设置高质量插值法
- g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
- //设置高质量,低速度呈现平滑程度
- g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
- //清空画布并以透明背景色填充
- g.Clear(Color.Transparent);
- //在指定位置并且按指定大小绘制原图片的指定部分
- g.DrawImage(originalImage, new Rectangle(0, 0, towidth, toheight),
- new Rectangle(x, y, ow, oh),
- GraphicsUnit.Pixel);
- return bitmap;
- }
- }
- }
|