Surface.cs 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105
  1. using SmartCoalApplication.SystemLayer;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Drawing;
  5. using System.Drawing.Imaging;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace SmartCoalApplication.Core
  10. {
  11. [Serializable]
  12. public sealed class Surface : IDisposable, ICloneable
  13. {
  14. /// <summary>
  15. /// 图像内存块
  16. /// </summary>
  17. private MemoryBlock scan0;
  18. /// <summary>
  19. /// 宽
  20. /// </summary>
  21. private int width;
  22. /// <summary>
  23. /// 高
  24. /// </summary>
  25. private int height;
  26. /// <summary>
  27. /// 扫描宽度
  28. /// </summary>
  29. private int stride;
  30. /// <summary>
  31. /// 释放标记
  32. /// </summary>
  33. private bool disposed = false;
  34. /// <summary>
  35. /// 存储打开时图片的格式
  36. /// </summary>
  37. private PixelFormat pixelFormat = PixelFormat.Format32bppArgb;
  38. /// <summary>
  39. /// 缩略图
  40. /// </summary>
  41. private Bitmap thumbnail;
  42. /// <summary>
  43. /// 原图的备份
  44. /// </summary>
  45. private Bitmap thumborigin;
  46. /// <summary>
  47. /// 创建原图的备份
  48. /// </summary>
  49. public void CreateThumborigin()
  50. {
  51. this.thumborigin = CreateAliasedBitmap();
  52. }
  53. public Bitmap Thumborigin
  54. {
  55. get
  56. {
  57. return this.thumborigin;
  58. }
  59. set
  60. {
  61. this.thumborigin = value;
  62. }
  63. }
  64. public Bitmap Thumbnail
  65. {
  66. get
  67. {
  68. return this.thumbnail;
  69. }
  70. }
  71. /// <summary>
  72. /// 创建缩略图
  73. /// </summary>
  74. public void CreateThumbnail()
  75. {
  76. Bitmap origin = CreateAliasedBitmap();
  77. Bitmap bitmap = null;
  78. if (origin.Width > origin.Height)
  79. {
  80. bitmap = MakeThumbnail(CreateAliasedBitmap(), 90, 90, "W");
  81. }
  82. else if (origin.Height > origin.Width)
  83. {
  84. bitmap = MakeThumbnail(CreateAliasedBitmap(), 90, 90, "H");
  85. }
  86. else
  87. {
  88. bitmap = MakeThumbnail(CreateAliasedBitmap(), 90, 90, "W");
  89. }
  90. this.thumbnail = bitmap;
  91. }
  92. public PixelFormat PixelFormat
  93. {
  94. get
  95. {
  96. return this.pixelFormat;
  97. }
  98. set
  99. {
  100. this.pixelFormat = value;
  101. }
  102. }
  103. public bool IsDisposed
  104. {
  105. get
  106. {
  107. return this.disposed;
  108. }
  109. }
  110. public MemoryBlock Scan0
  111. {
  112. get
  113. {
  114. if (this.disposed)
  115. {
  116. throw new ObjectDisposedException("Surface");
  117. }
  118. return this.scan0;
  119. }
  120. }
  121. public int Width
  122. {
  123. get
  124. {
  125. return this.width;
  126. }
  127. }
  128. public int Height
  129. {
  130. get
  131. {
  132. return this.height;
  133. }
  134. }
  135. public int Stride
  136. {
  137. get
  138. {
  139. return this.stride;
  140. }
  141. }
  142. public Size Size
  143. {
  144. get
  145. {
  146. return new Size(this.width, this.height);
  147. }
  148. }
  149. public Rectangle Bounds
  150. {
  151. get
  152. {
  153. return new Rectangle(0, 0, width, height);
  154. }
  155. }
  156. public Surface(Size size)
  157. : this(size.Width, size.Height)
  158. {
  159. }
  160. public Surface(int width, int height)
  161. {
  162. int stride;
  163. long bytes;
  164. try
  165. {
  166. stride = checked(width * ColorBgra.SizeOf);
  167. bytes = (long)height * (long)stride;
  168. }
  169. catch (OverflowException ex)
  170. {
  171. throw new OutOfMemoryException("Dimensions are too large - not enough memory, width=" + width.ToString() + ", height=" + height.ToString(), ex);
  172. }
  173. MemoryBlock scan0 = new MemoryBlock(width, height);
  174. Create(width, height, stride, scan0);
  175. }
  176. private Surface(int width, int height, int stride, MemoryBlock scan0)
  177. {
  178. Create(width, height, stride, scan0);
  179. }
  180. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "width")]
  181. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "height")]
  182. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "stride")]
  183. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "scan0")]
  184. private void Create(int width, int height, int stride, MemoryBlock scan0)
  185. {
  186. this.width = width;
  187. this.height = height;
  188. this.stride = stride;
  189. this.scan0 = scan0;
  190. }
  191. ~Surface()
  192. {
  193. Dispose(false);
  194. }
  195. public Surface CreateWindow(Rectangle bounds)
  196. {
  197. return CreateWindow(bounds.X, bounds.Y, bounds.Width, bounds.Height);
  198. }
  199. public Surface CreateWindow(int x, int y, int windowWidth, int windowHeight)
  200. {
  201. if (disposed)
  202. {
  203. throw new ObjectDisposedException("Surface");
  204. }
  205. if (windowHeight == 0)
  206. {
  207. throw new ArgumentOutOfRangeException("windowHeight", "must be greater than zero");
  208. }
  209. Rectangle original = this.Bounds;
  210. Rectangle sub = new Rectangle(x, y, windowWidth, windowHeight);
  211. Rectangle clipped = Rectangle.Intersect(original, sub);
  212. if (clipped != sub)
  213. {
  214. throw new ArgumentOutOfRangeException("bounds", new Rectangle(x, y, windowWidth, windowHeight),
  215. "bounds parameters must be a subset of this Surface's bounds");
  216. }
  217. long offset = ((long)stride * (long)y) + ((long)ColorBgra.SizeOf * (long)x);
  218. long length = ((windowHeight - 1) * (long)stride) + (long)windowWidth * (long)ColorBgra.SizeOf;
  219. MemoryBlock block = new MemoryBlock(this.scan0, offset, length);
  220. return new Surface(windowWidth, windowHeight, this.stride, block);
  221. }
  222. public long GetRowByteOffset(int y)
  223. {
  224. if (y < 0 || y >= height)
  225. {
  226. throw new ArgumentOutOfRangeException("y", "Out of bounds: y=" + y.ToString());
  227. }
  228. return (long)y * (long)stride;
  229. }
  230. public OpenCvSharp.Mat CreatedAliasedMat(OpenCvSharp.Mat mat)
  231. {
  232. if (mat == null)//<-CreateAliasedBitmap
  233. return Tools.ToMat(this.CreateAliasedBitmap());// OpenCvSharp.Extensions.BitmapConverter.ToMat(this.CreateAliasedBitmap());
  234. return mat/*.Clone()*/;//待测试
  235. }
  236. public unsafe long GetRowByteOffsetUnchecked(int yline)
  237. {
  238. return (long)yline * (long)stride;
  239. }
  240. public unsafe ColorBgra* GetRowAddress(int yline)
  241. {
  242. return (ColorBgra*)(((byte*)scan0.VoidStar) + GetRowByteOffset(yline));
  243. }
  244. public unsafe ColorBgra* GetRowAddressUnchecked(int yline)
  245. {
  246. return (ColorBgra*)(((byte*)scan0.VoidStar) + GetRowByteOffsetUnchecked(yline));
  247. }
  248. public long GetColumnByteOffsetUnchecked(int x)
  249. {
  250. return (long)x * (long)ColorBgra.SizeOf;
  251. }
  252. public long GetPointByteOffsetUnchecked(int x, int y)
  253. {
  254. return GetRowByteOffsetUnchecked(y) + GetColumnByteOffsetUnchecked(x);
  255. }
  256. public ColorBgra GetPoint(int x, int y)
  257. {
  258. return this[x, y];
  259. }
  260. public unsafe ColorBgra* GetPointAddress(int x, int y)
  261. {
  262. if (x < 0 || x >= Width)
  263. {
  264. throw new ArgumentOutOfRangeException("x", "Out of bounds: x=" + x.ToString());
  265. }
  266. return GetRowAddress(y) + x;
  267. }
  268. public unsafe ColorBgra* GetPointAddress(Point pt)
  269. {
  270. return GetPointAddress(pt.X, pt.Y);
  271. }
  272. public unsafe ColorBgra* GetPointAddressUnchecked(int x, int y)
  273. {
  274. return unchecked(x + (ColorBgra*)(((byte*)scan0.VoidStar) + (y * stride)));
  275. }
  276. public bool IsVisible(int x, int y)
  277. {
  278. return x >= 0 && x < width && y >= 0 && y < height;
  279. }
  280. public bool IsRowVisible(int y)
  281. {
  282. return y >= 0 && y < Height;
  283. }
  284. public bool IsColumnVisible(int x)
  285. {
  286. return x >= 0 && x < Width;
  287. }
  288. public ColorBgra this[int x, int y]
  289. {
  290. get
  291. {
  292. if (disposed)
  293. {
  294. throw new ObjectDisposedException("Surface");
  295. }
  296. if (x < 0 || y < 0 || x >= this.width || y >= this.height)
  297. {
  298. throw new ArgumentOutOfRangeException("(x,y)", new Point(x, y), "Coordinates out of range, max=" + new Size(width - 1, height - 1).ToString());
  299. }
  300. unsafe
  301. {
  302. return *GetPointAddressUnchecked(x, y);
  303. }
  304. }
  305. set
  306. {
  307. if (disposed)
  308. {
  309. throw new ObjectDisposedException("Surface");
  310. }
  311. if (x < 0 || y < 0 || x >= this.width || y >= this.height)
  312. {
  313. throw new ArgumentOutOfRangeException("(x,y)", new Point(x, y), "Coordinates out of range, max=" + new Size(width - 1, height - 1).ToString());
  314. }
  315. unsafe
  316. {
  317. *GetPointAddressUnchecked(x, y) = value;
  318. }
  319. }
  320. }
  321. public Bitmap CreateAliasedBitmap(bool alpha)
  322. {
  323. return CreateAliasedBitmap(this.Bounds, alpha);
  324. }
  325. public Bitmap CreateAliasedBitmap()
  326. {
  327. return CreateAliasedBitmap(this.Bounds);
  328. }
  329. public Bitmap CreateAliasedBitmap(Rectangle bounds)
  330. {
  331. return CreateAliasedBitmap(bounds, true);
  332. }
  333. public Bitmap CreateAliasedBitmap(Rectangle bounds, bool alpha)
  334. {
  335. if (disposed)
  336. {
  337. throw new ObjectDisposedException("Surface");
  338. }
  339. if (bounds.IsEmpty)
  340. {
  341. throw new ArgumentOutOfRangeException();
  342. }
  343. Rectangle clipped = Rectangle.Intersect(this.Bounds, bounds);
  344. if (clipped != bounds)
  345. {
  346. throw new ArgumentOutOfRangeException();
  347. }
  348. unsafe
  349. {
  350. return new Bitmap(bounds.Width, bounds.Height, stride, alpha ? PixelFormat.Format32bppArgb : PixelFormat.Format32bppRgb,
  351. new IntPtr((void*)((byte*)scan0.VoidStar + GetPointByteOffsetUnchecked(bounds.X, bounds.Y))));
  352. }
  353. }
  354. public static Surface CopyFromBitmap(Bitmap bitmap)
  355. {
  356. Surface surface = new Surface(bitmap.Width, bitmap.Height);
  357. BitmapData bd = bitmap.LockBits(surface.Bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  358. unsafe
  359. {
  360. for (int y = 0; y < bd.Height; ++y)
  361. {
  362. Memory.Copy((void*)surface.GetRowAddress(y),
  363. (byte*)bd.Scan0.ToPointer() + (y * bd.Stride), (ulong)bd.Width * ColorBgra.SizeOf);
  364. }
  365. }
  366. bitmap.UnlockBits(bd);
  367. return surface;
  368. }
  369. public void CopySurface(Surface source)
  370. {
  371. if (disposed)
  372. {
  373. throw new ObjectDisposedException("Surface");
  374. }
  375. if (this.stride == source.stride &&
  376. (this.width * ColorBgra.SizeOf) == this.stride &&
  377. this.width == source.width &&
  378. this.height == source.height)
  379. {
  380. unsafe
  381. {
  382. Memory.Copy(this.scan0.VoidStar,
  383. source.scan0.VoidStar,
  384. ((ulong)(height - 1) * (ulong)stride) + ((ulong)width * (ulong)ColorBgra.SizeOf));
  385. }
  386. }
  387. else
  388. {
  389. int copyWidth = Math.Min(width, source.width);
  390. int copyHeight = Math.Min(height, source.height);
  391. unsafe
  392. {
  393. for (int y = 0; y < copyHeight; ++y)
  394. {
  395. Memory.Copy(GetRowAddressUnchecked(y), source.GetRowAddressUnchecked(y), (ulong)copyWidth * (ulong)ColorBgra.SizeOf);
  396. }
  397. }
  398. }
  399. }
  400. object ICloneable.Clone()
  401. {
  402. return Clone();
  403. }
  404. public Surface Clone()
  405. {
  406. if (disposed)
  407. {
  408. throw new ObjectDisposedException("Surface");
  409. }
  410. Surface ret = new Surface(this.Size);
  411. ret.CopySurface(this);
  412. return ret;
  413. }
  414. public void Clear()
  415. {
  416. Clear(ColorBgra.FromBgra(255, 255, 255, 255));
  417. }
  418. public void Clear(ColorBgra color)
  419. {
  420. //new UnaryPixelOps.Constant(color).Apply(this, this.Bounds);
  421. }
  422. public void SuperSamplingFitSurface(Surface source, Rectangle dstRoi)
  423. {
  424. if (source.Width == Width && source.Height == Height)
  425. {
  426. CopySurface(source);
  427. }
  428. else if (source.Width <= Width || source.Height <= Height)
  429. {
  430. if (source.width < 2 || source.height < 2 || this.width < 2 || this.height < 2)
  431. {
  432. this.NearestNeighborFitSurface(source, dstRoi);
  433. }
  434. else
  435. {
  436. this.BicubicFitSurface(source, dstRoi);
  437. }
  438. }
  439. else unsafe
  440. {
  441. Rectangle dstRoi2 = Rectangle.Intersect(dstRoi, this.Bounds);
  442. for (int dstY = dstRoi2.Top; dstY < dstRoi2.Bottom; ++dstY)
  443. {
  444. double srcTop = (double)(dstY * source.height) / (double)height;
  445. double srcTopFloor = Math.Floor(srcTop);
  446. double srcTopWeight = 1 - (srcTop - srcTopFloor);
  447. int srcTopInt = (int)srcTopFloor;
  448. double srcBottom = (double)((dstY + 1) * source.height) / (double)height;
  449. double srcBottomFloor = Math.Floor(srcBottom - 0.00001);
  450. double srcBottomWeight = srcBottom - srcBottomFloor;
  451. int srcBottomInt = (int)srcBottomFloor;
  452. ColorBgra* dstPtr = this.GetPointAddressUnchecked(dstRoi2.Left, dstY);
  453. for (int dstX = dstRoi2.Left; dstX < dstRoi2.Right; ++dstX)
  454. {
  455. double srcLeft = (double)(dstX * source.width) / (double)width;
  456. double srcLeftFloor = Math.Floor(srcLeft);
  457. double srcLeftWeight = 1 - (srcLeft - srcLeftFloor);
  458. int srcLeftInt = (int)srcLeftFloor;
  459. double srcRight = (double)((dstX + 1) * source.width) / (double)width;
  460. double srcRightFloor = Math.Floor(srcRight - 0.00001);
  461. double srcRightWeight = srcRight - srcRightFloor;
  462. int srcRightInt = (int)srcRightFloor;
  463. double blueSum = 0;
  464. double greenSum = 0;
  465. double redSum = 0;
  466. double alphaSum = 0;
  467. // left fractional edge
  468. ColorBgra* srcLeftPtr = source.GetPointAddressUnchecked(srcLeftInt, srcTopInt + 1);
  469. for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
  470. {
  471. double a = srcLeftPtr->A;
  472. blueSum += srcLeftPtr->B * srcLeftWeight * a;
  473. greenSum += srcLeftPtr->G * srcLeftWeight * a;
  474. redSum += srcLeftPtr->R * srcLeftWeight * a;
  475. alphaSum += srcLeftPtr->A * srcLeftWeight;
  476. srcLeftPtr = (ColorBgra*)((byte*)srcLeftPtr + source.stride);
  477. }
  478. // right fractional edge
  479. ColorBgra* srcRightPtr = source.GetPointAddressUnchecked(srcRightInt, srcTopInt + 1);
  480. for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
  481. {
  482. double a = srcRightPtr->A;
  483. blueSum += srcRightPtr->B * srcRightWeight * a;
  484. greenSum += srcRightPtr->G * srcRightWeight * a;
  485. redSum += srcRightPtr->R * srcRightWeight * a;
  486. alphaSum += srcRightPtr->A * srcRightWeight;
  487. srcRightPtr = (ColorBgra*)((byte*)srcRightPtr + source.stride);
  488. }
  489. // top fractional edge
  490. ColorBgra* srcTopPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcTopInt);
  491. for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
  492. {
  493. double a = srcTopPtr->A;
  494. blueSum += srcTopPtr->B * srcTopWeight * a;
  495. greenSum += srcTopPtr->G * srcTopWeight * a;
  496. redSum += srcTopPtr->R * srcTopWeight * a;
  497. alphaSum += srcTopPtr->A * srcTopWeight;
  498. ++srcTopPtr;
  499. }
  500. // bottom fractional edge
  501. ColorBgra* srcBottomPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcBottomInt);
  502. for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
  503. {
  504. double a = srcBottomPtr->A;
  505. blueSum += srcBottomPtr->B * srcBottomWeight * a;
  506. greenSum += srcBottomPtr->G * srcBottomWeight * a;
  507. redSum += srcBottomPtr->R * srcBottomWeight * a;
  508. alphaSum += srcBottomPtr->A * srcBottomWeight;
  509. ++srcBottomPtr;
  510. }
  511. // center area
  512. for (int srcY = srcTopInt + 1; srcY < srcBottomInt; ++srcY)
  513. {
  514. ColorBgra* srcPtr = source.GetPointAddressUnchecked(srcLeftInt + 1, srcY);
  515. for (int srcX = srcLeftInt + 1; srcX < srcRightInt; ++srcX)
  516. {
  517. double a = srcPtr->A;
  518. blueSum += (double)srcPtr->B * a;
  519. greenSum += (double)srcPtr->G * a;
  520. redSum += (double)srcPtr->R * a;
  521. alphaSum += (double)srcPtr->A;
  522. ++srcPtr;
  523. }
  524. }
  525. // four corner pixels
  526. ColorBgra srcTL = source.GetPoint(srcLeftInt, srcTopInt);
  527. double srcTLA = srcTL.A;
  528. blueSum += srcTL.B * (srcTopWeight * srcLeftWeight) * srcTLA;
  529. greenSum += srcTL.G * (srcTopWeight * srcLeftWeight) * srcTLA;
  530. redSum += srcTL.R * (srcTopWeight * srcLeftWeight) * srcTLA;
  531. alphaSum += srcTL.A * (srcTopWeight * srcLeftWeight);
  532. ColorBgra srcTR = source.GetPoint(srcRightInt, srcTopInt);
  533. double srcTRA = srcTR.A;
  534. blueSum += srcTR.B * (srcTopWeight * srcRightWeight) * srcTRA;
  535. greenSum += srcTR.G * (srcTopWeight * srcRightWeight) * srcTRA;
  536. redSum += srcTR.R * (srcTopWeight * srcRightWeight) * srcTRA;
  537. alphaSum += srcTR.A * (srcTopWeight * srcRightWeight);
  538. ColorBgra srcBL = source.GetPoint(srcLeftInt, srcBottomInt);
  539. double srcBLA = srcBL.A;
  540. blueSum += srcBL.B * (srcBottomWeight * srcLeftWeight) * srcBLA;
  541. greenSum += srcBL.G * (srcBottomWeight * srcLeftWeight) * srcBLA;
  542. redSum += srcBL.R * (srcBottomWeight * srcLeftWeight) * srcBLA;
  543. alphaSum += srcBL.A * (srcBottomWeight * srcLeftWeight);
  544. ColorBgra srcBR = source.GetPoint(srcRightInt, srcBottomInt);
  545. double srcBRA = srcBR.A;
  546. blueSum += srcBR.B * (srcBottomWeight * srcRightWeight) * srcBRA;
  547. greenSum += srcBR.G * (srcBottomWeight * srcRightWeight) * srcBRA;
  548. redSum += srcBR.R * (srcBottomWeight * srcRightWeight) * srcBRA;
  549. alphaSum += srcBR.A * (srcBottomWeight * srcRightWeight);
  550. double area = (srcRight - srcLeft) * (srcBottom - srcTop);
  551. double alpha = alphaSum / area;
  552. double blue;
  553. double green;
  554. double red;
  555. if (alpha == 0)
  556. {
  557. blue = 0;
  558. green = 0;
  559. red = 0;
  560. }
  561. else
  562. {
  563. blue = blueSum / alphaSum;
  564. green = greenSum / alphaSum;
  565. red = redSum / alphaSum;
  566. }
  567. // add 0.5 so that rounding goes in the direction we want it to
  568. blue += 0.5;
  569. green += 0.5;
  570. red += 0.5;
  571. alpha += 0.5;
  572. dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
  573. ++dstPtr;
  574. }
  575. }
  576. }
  577. }
  578. public void NearestNeighborFitSurface(Surface source, Rectangle dstRoi)
  579. {
  580. Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);
  581. unsafe
  582. {
  583. for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
  584. {
  585. int srcY = (dstY * source.height) / height;
  586. ColorBgra* srcRow = source.GetRowAddressUnchecked(srcY);
  587. ColorBgra* dstPtr = this.GetPointAddressUnchecked(roi.Left, dstY);
  588. for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
  589. {
  590. int srcX = (dstX * source.width) / width;
  591. *dstPtr = *(srcRow + srcX);
  592. ++dstPtr;
  593. }
  594. }
  595. }
  596. }
  597. private double CubeClamped(double x)
  598. {
  599. if (x >= 0)
  600. {
  601. return x * x * x;
  602. }
  603. else
  604. {
  605. return 0;
  606. }
  607. }
  608. private double R(double x)
  609. {
  610. return (CubeClamped(x + 2) - (4 * CubeClamped(x + 1)) + (6 * CubeClamped(x)) - (4 * CubeClamped(x - 1))) / 6;
  611. }
  612. public void BicubicFitSurface(Surface source, Rectangle dstRoi)
  613. {
  614. float leftF = (1 * (float)(width - 1)) / (float)(source.width - 1);
  615. float topF = (1 * (height - 1)) / (float)(source.height - 1);
  616. float rightF = ((float)(source.width - 3) * (float)(width - 1)) / (float)(source.width - 1);
  617. float bottomF = ((float)(source.Height - 3) * (float)(height - 1)) / (float)(source.height - 1);
  618. int left = (int)Math.Ceiling((double)leftF);
  619. int top = (int)Math.Ceiling((double)topF);
  620. int right = (int)Math.Floor((double)rightF);
  621. int bottom = (int)Math.Floor((double)bottomF);
  622. Rectangle[] rois = new Rectangle[] {
  623. Rectangle.FromLTRB(left, top, right, bottom),
  624. new Rectangle(0, 0, width, top),
  625. new Rectangle(0, top, left, height - top),
  626. new Rectangle(right, top, width - right, height - top),
  627. new Rectangle(left, bottom, right - left, height - bottom)
  628. };
  629. for (int i = 0; i < rois.Length; ++i)
  630. {
  631. rois[i].Intersect(dstRoi);
  632. if (rois[i].Width > 0 && rois[i].Height > 0)
  633. {
  634. if (i == 0)
  635. {
  636. BicubicFitSurfaceUnchecked(source, rois[i]);
  637. }
  638. else
  639. {
  640. BicubicFitSurfaceChecked(source, rois[i]);
  641. }
  642. }
  643. }
  644. }
  645. private void BicubicFitSurfaceChecked(Surface source, Rectangle dstRoi)
  646. {
  647. if (this.width < 2 || this.height < 2 || source.width < 2 || source.height < 2)
  648. {
  649. SuperSamplingFitSurface(source, dstRoi);
  650. }
  651. else
  652. {
  653. unsafe
  654. {
  655. Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);
  656. Rectangle roiIn = Rectangle.Intersect(dstRoi, new Rectangle(1, 1, width - 1, height - 1));
  657. IntPtr rColCacheIP = Memory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
  658. double* rColCache = (double*)rColCacheIP.ToPointer();
  659. // Precompute and then cache the value of R() for each column
  660. for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
  661. {
  662. double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
  663. double srcColumnFloor = Math.Floor(srcColumn);
  664. double srcColumnFrac = srcColumn - srcColumnFloor;
  665. int srcColumnInt = (int)srcColumn;
  666. for (int m = -1; m <= 2; ++m)
  667. {
  668. int index = (m + 1) + ((dstX - roi.Left) * 4);
  669. double x = m - srcColumnFrac;
  670. rColCache[index] = R(x);
  671. }
  672. }
  673. // Set this up so we can cache the R()'s for every row
  674. double* rRowCache = stackalloc double[4];
  675. for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
  676. {
  677. double srcRow = (double)(dstY * (source.height - 1)) / (double)(height - 1);
  678. double srcRowFloor = (double)Math.Floor(srcRow);
  679. double srcRowFrac = srcRow - srcRowFloor;
  680. int srcRowInt = (int)srcRow;
  681. ColorBgra* dstPtr = this.GetPointAddressUnchecked(roi.Left, dstY);
  682. // Compute the R() values for this row
  683. for (int n = -1; n <= 2; ++n)
  684. {
  685. double x = srcRowFrac - n;
  686. rRowCache[n + 1] = R(x);
  687. }
  688. // See Perf Note below
  689. //int nFirst = Math.Max(-srcRowInt, -1);
  690. //int nLast = Math.Min(source.height - srcRowInt - 1, 2);
  691. for (int dstX = roi.Left; dstX < roi.Right; dstX++)
  692. {
  693. double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
  694. double srcColumnFloor = Math.Floor(srcColumn);
  695. double srcColumnFrac = srcColumn - srcColumnFloor;
  696. int srcColumnInt = (int)srcColumn;
  697. double blueSum = 0;
  698. double greenSum = 0;
  699. double redSum = 0;
  700. double alphaSum = 0;
  701. double totalWeight = 0;
  702. // See Perf Note below
  703. //int mFirst = Math.Max(-srcColumnInt, -1);
  704. //int mLast = Math.Min(source.width - srcColumnInt - 1, 2);
  705. ColorBgra* srcPtr = source.GetPointAddressUnchecked(srcColumnInt - 1, srcRowInt - 1);
  706. for (int n = -1; n <= 2; ++n)
  707. {
  708. int srcY = srcRowInt + n;
  709. for (int m = -1; m <= 2; ++m)
  710. {
  711. // Perf Note: It actually benchmarks faster on my system to do
  712. // a bounds check for every (m,n) than it is to limit the loop
  713. // to nFirst-Last and mFirst-mLast.
  714. // I'm leaving the code above, albeit commented out, so that
  715. // benchmarking between these two can still be performed.
  716. if (source.IsVisible(srcColumnInt + m, srcY))
  717. {
  718. double w0 = rColCache[(m + 1) + (4 * (dstX - roi.Left))];
  719. double w1 = rRowCache[n + 1];
  720. double w = w0 * w1;
  721. blueSum += srcPtr->B * w * srcPtr->A;
  722. greenSum += srcPtr->G * w * srcPtr->A;
  723. redSum += srcPtr->R * w * srcPtr->A;
  724. alphaSum += srcPtr->A * w;
  725. totalWeight += w;
  726. }
  727. ++srcPtr;
  728. }
  729. srcPtr = (ColorBgra*)((byte*)(srcPtr - 4) + source.stride);
  730. }
  731. double alpha = alphaSum / totalWeight;
  732. double blue;
  733. double green;
  734. double red;
  735. if (alpha == 0)
  736. {
  737. blue = 0;
  738. green = 0;
  739. red = 0;
  740. }
  741. else
  742. {
  743. blue = blueSum / alphaSum;
  744. green = greenSum / alphaSum;
  745. red = redSum / alphaSum;
  746. // add 0.5 to ensure truncation to uint results in rounding
  747. alpha += 0.5;
  748. blue += 0.5;
  749. green += 0.5;
  750. red += 0.5;
  751. }
  752. dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
  753. ++dstPtr;
  754. } // for (dstX...
  755. } // for (dstY...
  756. Memory.Free(rColCacheIP);
  757. } // unsafe
  758. }
  759. }
  760. public void BicubicFitSurfaceUnchecked(Surface source, Rectangle dstRoi)
  761. {
  762. if (this.width < 2 || this.height < 2 || source.width < 2 || source.height < 2)
  763. {
  764. SuperSamplingFitSurface(source, dstRoi);
  765. }
  766. else
  767. {
  768. unsafe
  769. {
  770. Rectangle roi = Rectangle.Intersect(dstRoi, this.Bounds);
  771. Rectangle roiIn = Rectangle.Intersect(dstRoi, new Rectangle(1, 1, width - 1, height - 1));
  772. IntPtr rColCacheIP = Memory.Allocate(4 * (ulong)roi.Width * (ulong)sizeof(double));
  773. double* rColCache = (double*)rColCacheIP.ToPointer();
  774. // Precompute and then cache the value of R() for each column
  775. for (int dstX = roi.Left; dstX < roi.Right; ++dstX)
  776. {
  777. double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
  778. double srcColumnFloor = Math.Floor(srcColumn);
  779. double srcColumnFrac = srcColumn - srcColumnFloor;
  780. int srcColumnInt = (int)srcColumn;
  781. for (int m = -1; m <= 2; ++m)
  782. {
  783. int index = (m + 1) + ((dstX - roi.Left) * 4);
  784. double x = m - srcColumnFrac;
  785. rColCache[index] = R(x);
  786. }
  787. }
  788. // Set this up so we can cache the R()'s for every row
  789. double* rRowCache = stackalloc double[4];
  790. for (int dstY = roi.Top; dstY < roi.Bottom; ++dstY)
  791. {
  792. double srcRow = (double)(dstY * (source.height - 1)) / (double)(height - 1);
  793. double srcRowFloor = Math.Floor(srcRow);
  794. double srcRowFrac = srcRow - srcRowFloor;
  795. int srcRowInt = (int)srcRow;
  796. ColorBgra* dstPtr = this.GetPointAddressUnchecked(roi.Left, dstY);
  797. // Compute the R() values for this row
  798. for (int n = -1; n <= 2; ++n)
  799. {
  800. double x = srcRowFrac - n;
  801. rRowCache[n + 1] = R(x);
  802. }
  803. rColCache = (double*)rColCacheIP.ToPointer();
  804. ColorBgra* srcRowPtr = source.GetRowAddressUnchecked(srcRowInt - 1);
  805. for (int dstX = roi.Left; dstX < roi.Right; dstX++)
  806. {
  807. double srcColumn = (double)(dstX * (source.width - 1)) / (double)(width - 1);
  808. double srcColumnFloor = Math.Floor(srcColumn);
  809. double srcColumnFrac = srcColumn - srcColumnFloor;
  810. int srcColumnInt = (int)srcColumn;
  811. double blueSum = 0;
  812. double greenSum = 0;
  813. double redSum = 0;
  814. double alphaSum = 0;
  815. double totalWeight = 0;
  816. ColorBgra* srcPtr = srcRowPtr + srcColumnInt - 1;
  817. for (int n = 0; n <= 3; ++n)
  818. {
  819. double w0 = rColCache[0] * rRowCache[n];
  820. double w1 = rColCache[1] * rRowCache[n];
  821. double w2 = rColCache[2] * rRowCache[n];
  822. double w3 = rColCache[3] * rRowCache[n];
  823. double a0 = srcPtr[0].A;
  824. double a1 = srcPtr[1].A;
  825. double a2 = srcPtr[2].A;
  826. double a3 = srcPtr[3].A;
  827. alphaSum += (a0 * w0) + (a1 * w1) + (a2 * w2) + (a3 * w3);
  828. totalWeight += w0 + w1 + w2 + w3;
  829. blueSum += (a0 * srcPtr[0].B * w0) + (a1 * srcPtr[1].B * w1) + (a2 * srcPtr[2].B * w2) + (a3 * srcPtr[3].B * w3);
  830. greenSum += (a0 * srcPtr[0].G * w0) + (a1 * srcPtr[1].G * w1) + (a2 * srcPtr[2].G * w2) + (a3 * srcPtr[3].G * w3);
  831. redSum += (a0 * srcPtr[0].R * w0) + (a1 * srcPtr[1].R * w1) + (a2 * srcPtr[2].R * w2) + (a3 * srcPtr[3].R * w3);
  832. srcPtr = (ColorBgra*)((byte*)srcPtr + source.stride);
  833. }
  834. double alpha = alphaSum / totalWeight;
  835. double blue;
  836. double green;
  837. double red;
  838. if (alpha == 0)
  839. {
  840. blue = 0;
  841. green = 0;
  842. red = 0;
  843. }
  844. else
  845. {
  846. blue = blueSum / alphaSum;
  847. green = greenSum / alphaSum;
  848. red = redSum / alphaSum;
  849. // add 0.5 to ensure truncation to uint results in rounding
  850. alpha += 0.5;
  851. blue += 0.5;
  852. green += 0.5;
  853. red += 0.5;
  854. }
  855. dstPtr->Bgra = (uint)blue + ((uint)green << 8) + ((uint)red << 16) + ((uint)alpha << 24);
  856. ++dstPtr;
  857. rColCache += 4;
  858. } // for (dstX...
  859. } // for (dstY...
  860. Memory.Free(rColCacheIP);
  861. } // unsafe
  862. }
  863. }
  864. /// <summary>
  865. /// Releases all resources held by this Surface object.
  866. /// </summary>
  867. public void Dispose()
  868. {
  869. Dispose(true);
  870. GC.SuppressFinalize(this);
  871. }
  872. private void Dispose(bool disposing)
  873. {
  874. if (!disposed)
  875. {
  876. disposed = true;
  877. if (disposing)
  878. {
  879. scan0.Dispose();
  880. scan0 = null;
  881. }
  882. }
  883. }
  884. ///<summary>
  885. /// 生成缩略图
  886. /// </summary>
  887. /// <param name="originalImage">源图片</param>
  888. /// <param name="width">缩略图宽度</param>
  889. /// <param name="height">缩略图高度</param>
  890. /// <param name="mode">生成缩略图的方式</param>
  891. public Bitmap MakeThumbnail(Image originalImage, int swidth, int sheight, string mode)
  892. {
  893. int towidth = swidth;
  894. int toheight = sheight;
  895. int x = 0;
  896. int y = 0;
  897. int ow = originalImage.Width;
  898. int oh = originalImage.Height;
  899. switch (mode)
  900. {
  901. case "HW"://指定高宽缩放(可能变形)
  902. break;
  903. case "W"://指定宽,高按比例
  904. toheight = originalImage.Height * swidth / originalImage.Width;
  905. break;
  906. case "H"://指定高,宽按比例
  907. towidth = originalImage.Width * sheight / originalImage.Height;
  908. break;
  909. case "Cut"://指定高宽裁减(不变形)
  910. if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
  911. {
  912. oh = originalImage.Height;
  913. ow = originalImage.Height * towidth / toheight;
  914. y = 0;
  915. x = (originalImage.Width - ow) / 2;
  916. }
  917. else
  918. {
  919. ow = originalImage.Width;
  920. oh = originalImage.Width * sheight / towidth;
  921. x = 0;
  922. y = (originalImage.Height - oh) / 2;
  923. }
  924. break;
  925. default:
  926. break;
  927. }
  928. //新建一个bmp图片
  929. Bitmap bitmap = new System.Drawing.Bitmap(towidth, toheight);
  930. //新建一个画板
  931. Graphics g = System.Drawing.Graphics.FromImage(bitmap);
  932. //设置高质量插值法
  933. g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
  934. //设置高质量,低速度呈现平滑程度
  935. g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
  936. //清空画布并以透明背景色填充
  937. g.Clear(Color.Transparent);
  938. //在指定位置并且按指定大小绘制原图片的指定部分
  939. g.DrawImage(originalImage, new Rectangle(0, 0, towidth, toheight),
  940. new Rectangle(x, y, ow, oh),
  941. GraphicsUnit.Pixel);
  942. return bitmap;
  943. }
  944. }
  945. }