PageRenderTime 50ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Core/Utility.cs

https://bitbucket.org/tcz001/openpdn
C# | 3273 lines | 2568 code | 519 blank | 186 comment | 377 complexity | 4946d19edb99d6fa1f3119903511463b MD5 | raw file
Possible License(s): Unlicense

Large files files are truncated, but you can click here to view the full file

  1. /////////////////////////////////////////////////////////////////////////////////
  2. // Paint.NET //
  3. // Copyright (C) dotPDN LLC, Rick Brewster, Tom Jackson, and contributors. //
  4. // Portions Copyright (C) Microsoft Corporation. All Rights Reserved. //
  5. // See src/Resources/Files/License.txt for full licensing and attribution //
  6. // details. //
  7. // . //
  8. /////////////////////////////////////////////////////////////////////////////////
  9. using Microsoft.Win32;
  10. using PaintDotNet.Threading;
  11. using PaintDotNet.SystemLayer;
  12. using System;
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using System.ComponentModel;
  16. using System.Diagnostics;
  17. using System.Drawing;
  18. using System.Drawing.Drawing2D;
  19. using System.Drawing.Imaging;
  20. using System.Globalization;
  21. using System.IO;
  22. using System.Net;
  23. using System.Reflection;
  24. using System.Runtime.InteropServices;
  25. using System.Runtime.Serialization;
  26. using System.Runtime.Serialization.Formatters.Binary;
  27. using System.Text;
  28. using System.Threading;
  29. using System.Windows.Forms;
  30. namespace PaintDotNet
  31. {
  32. /// <summary>
  33. /// Defines miscellaneous constants and static functions.
  34. /// </summary>
  35. /// // TODO: refactor into mini static classes
  36. public sealed class Utility
  37. {
  38. private Utility()
  39. {
  40. }
  41. internal static bool IsNumber(float x)
  42. {
  43. return x >= float.MinValue && x <= float.MaxValue;
  44. }
  45. internal static bool IsNumber(double x)
  46. {
  47. return x >= double.MinValue && x <= double.MaxValue;
  48. }
  49. internal static int Min(int val0, params int[] vals)
  50. {
  51. int min = val0;
  52. for (int i = 0; i < vals.Length; ++i)
  53. {
  54. if (vals[i] < min)
  55. {
  56. min = vals[i];
  57. }
  58. }
  59. return min;
  60. }
  61. internal static int Max(int val0, params int[] vals)
  62. {
  63. int max = val0;
  64. for (int i = 0; i < vals.Length; ++i)
  65. {
  66. if (vals[i] > max)
  67. {
  68. max = vals[i];
  69. }
  70. }
  71. return max;
  72. }
  73. public static PointF[] GetRgssOffsets(int quality)
  74. {
  75. unsafe
  76. {
  77. int sampleCount = quality * quality;
  78. PointF[] samplesArray = new PointF[sampleCount];
  79. fixed (PointF* pSamplesArray = samplesArray)
  80. {
  81. GetRgssOffsets(pSamplesArray, sampleCount, quality);
  82. }
  83. return samplesArray;
  84. }
  85. }
  86. public static unsafe void GetRgssOffsets(PointF* samplesArray, int sampleCount, int quality)
  87. {
  88. if (sampleCount < 1)
  89. {
  90. throw new ArgumentOutOfRangeException("sampleCount", "sampleCount must be [0, int.MaxValue]");
  91. }
  92. if (sampleCount != quality * quality)
  93. {
  94. throw new ArgumentOutOfRangeException("sampleCount != (quality * quality)");
  95. }
  96. if (sampleCount == 1)
  97. {
  98. samplesArray[0] = new PointF(0.0f, 0.0f);
  99. }
  100. else
  101. {
  102. for (int i = 0; i < sampleCount; ++i)
  103. {
  104. double y = (i + 1d) / (sampleCount + 1d);
  105. double x = y * quality;
  106. x -= (int)x;
  107. samplesArray[i] = new PointF((float)(x - 0.5d), (float)(y - 0.5d));
  108. }
  109. }
  110. }
  111. public static bool IsObsolete(Type type, bool inherit)
  112. {
  113. object[] attrs = type.GetCustomAttributes(typeof(ObsoleteAttribute), inherit);
  114. return (attrs.Length != 0);
  115. }
  116. public static void DrawDropShadow1px(Graphics g, Rectangle rect)
  117. {
  118. Brush b0 = new SolidBrush(Color.FromArgb(15, Color.Black));
  119. Brush b1 = new SolidBrush(Color.FromArgb(47, Color.Black));
  120. Pen p2 = new Pen(Color.FromArgb(63, Color.Black));
  121. g.FillRectangle(b0, rect.Left, rect.Top, 1, 1);
  122. g.FillRectangle(b1, rect.Left + 1, rect.Top, 1, 1);
  123. g.FillRectangle(b1, rect.Left, rect.Top + 1, 1, 1);
  124. g.FillRectangle(b0, rect.Right - 1, rect.Top, 1, 1);
  125. g.FillRectangle(b1, rect.Right - 2, rect.Top, 1, 1);
  126. g.FillRectangle(b1, rect.Right - 1, rect.Top + 1, 1, 1);
  127. g.FillRectangle(b0, rect.Left, rect.Bottom - 1, 1, 1);
  128. g.FillRectangle(b1, rect.Left + 1, rect.Bottom - 1, 1, 1);
  129. g.FillRectangle(b1, rect.Left, rect.Bottom - 2, 1, 1);
  130. g.FillRectangle(b0, rect.Right - 1, rect.Bottom - 1, 1, 1);
  131. g.FillRectangle(b1, rect.Right - 2, rect.Bottom - 1, 1, 1);
  132. g.FillRectangle(b1, rect.Right - 1, rect.Bottom - 2, 1, 1);
  133. g.DrawLine(p2, rect.Left + 2, rect.Top, rect.Right - 3, rect.Top);
  134. g.DrawLine(p2, rect.Left, rect.Top + 2, rect.Left, rect.Bottom - 3);
  135. g.DrawLine(p2, rect.Left + 2, rect.Bottom - 1, rect.Right - 3, rect.Bottom - 1);
  136. g.DrawLine(p2, rect.Right - 1, rect.Top + 2, rect.Right - 1, rect.Bottom - 3);
  137. b0.Dispose();
  138. b0 = null;
  139. b1.Dispose();
  140. b1 = null;
  141. p2.Dispose();
  142. p2 = null;
  143. }
  144. public static Keys LetterOrDigitCharToKeys(char c)
  145. {
  146. if (c >= 'a' && c <= 'z')
  147. {
  148. return (Keys)((int)(c - 'a') + (int)Keys.A);
  149. }
  150. else if (c >= 'A' && c <= 'Z')
  151. {
  152. return (Keys)((int)(c - 'A') + (int)Keys.A);
  153. }
  154. else if (c >= '0' && c <= '9')
  155. {
  156. return (Keys)((int)(c - '0') + (int)Keys.D0);
  157. }
  158. else
  159. {
  160. return Keys.None;
  161. }
  162. }
  163. public static Control FindFocus()
  164. {
  165. foreach (Form form in Application.OpenForms)
  166. {
  167. Control focused = FindFocus(form);
  168. if (focused != null)
  169. {
  170. return focused;
  171. }
  172. }
  173. return null;
  174. }
  175. private static Control FindFocus(Control c)
  176. {
  177. if (c.Focused)
  178. {
  179. return c;
  180. }
  181. foreach (Control child in c.Controls)
  182. {
  183. Control f = FindFocus(child);
  184. if (f != null)
  185. {
  186. return f;
  187. }
  188. }
  189. return null;
  190. }
  191. public static void DrawColorRectangle(Graphics g, Rectangle rect, Color color, bool drawBorder)
  192. {
  193. int inflateAmt = drawBorder ? -2 : 0;
  194. Rectangle colorRectangle = Rectangle.Inflate(rect, inflateAmt, inflateAmt);
  195. Brush colorBrush = new LinearGradientBrush(colorRectangle, Color.FromArgb(255, color), color, 90.0f, false);
  196. HatchBrush backgroundBrush = new HatchBrush(HatchStyle.LargeCheckerBoard, Color.FromArgb(191, 191, 191), Color.FromArgb(255, 255, 255));
  197. if (drawBorder)
  198. {
  199. g.DrawRectangle(Pens.Black, rect.Left, rect.Top, rect.Width - 1, rect.Height - 1);
  200. g.DrawRectangle(Pens.White, rect.Left + 1, rect.Top + 1, rect.Width - 3, rect.Height - 3);
  201. }
  202. PixelOffsetMode oldPOM = g.PixelOffsetMode;
  203. g.PixelOffsetMode = PixelOffsetMode.Half;
  204. g.FillRectangle(backgroundBrush, colorRectangle);
  205. g.FillRectangle(colorBrush, colorRectangle);
  206. g.PixelOffsetMode = oldPOM;
  207. backgroundBrush.Dispose();
  208. colorBrush.Dispose();
  209. }
  210. public static Size ComputeThumbnailSize(Size originalSize, int maxEdgeLength)
  211. {
  212. Size thumbSize;
  213. if (originalSize.Width > originalSize.Height)
  214. {
  215. int longSide = Math.Min(originalSize.Width, maxEdgeLength);
  216. thumbSize = new Size(longSide, Math.Max(1, (originalSize.Height * longSide) / originalSize.Width));
  217. }
  218. else if (originalSize.Height > originalSize.Width)
  219. {
  220. int longSide = Math.Min(originalSize.Height, maxEdgeLength);
  221. thumbSize = new Size(Math.Max(1, (originalSize.Width * longSide) / originalSize.Height), longSide);
  222. }
  223. else // if (docSize.Width == docSize.Height)
  224. {
  225. int longSide = Math.Min(originalSize.Width, maxEdgeLength);
  226. thumbSize = new Size(longSide, longSide);
  227. }
  228. return thumbSize;
  229. }
  230. public static bool IsClipboardImageAvailable()
  231. {
  232. try
  233. {
  234. return System.Windows.Forms.Clipboard.ContainsImage() ||
  235. System.Windows.Forms.Clipboard.ContainsData(DataFormats.EnhancedMetafile);
  236. }
  237. catch (ExternalException)
  238. {
  239. return false;
  240. }
  241. }
  242. public static Font CreateFont(string name, float size, FontStyle style)
  243. {
  244. Font returnFont;
  245. try
  246. {
  247. returnFont = new Font(name, size, style);
  248. }
  249. catch (Exception)
  250. {
  251. returnFont = new Font(FontFamily.GenericSansSerif, size);
  252. }
  253. return returnFont;
  254. }
  255. public static Font CreateFont(string name, float size, string backupName, float backupSize, FontStyle style)
  256. {
  257. Font returnFont;
  258. try
  259. {
  260. returnFont = new Font(name, size, style);
  261. }
  262. catch (Exception)
  263. {
  264. returnFont = CreateFont(backupName, backupSize, style);
  265. }
  266. return returnFont;
  267. }
  268. public static readonly Color TransparentKey = Color.FromArgb(192, 192, 192);
  269. public static string WebExceptionToErrorMessage(WebException wex)
  270. {
  271. string errorMessage;
  272. switch (wex.Status)
  273. {
  274. case WebExceptionStatus.ProtocolError:
  275. string format = PdnResources.GetString("WebExceptionStatus.ProtocolError.Format");
  276. HttpStatusCode statusCode = ((HttpWebResponse)wex.Response).StatusCode;
  277. errorMessage = string.Format(format, statusCode.ToString(), (int)statusCode);
  278. break;
  279. default:
  280. string stringName = "WebExceptionStatus." + wex.Status.ToString();
  281. errorMessage = PdnResources.GetString(stringName);
  282. break;
  283. }
  284. return errorMessage;
  285. }
  286. private static bool allowGCFullCollect = true;
  287. public static bool AllowGCFullCollect
  288. {
  289. get
  290. {
  291. return allowGCFullCollect;
  292. }
  293. set
  294. {
  295. allowGCFullCollect = value;
  296. }
  297. }
  298. public static void GCFullCollect()
  299. {
  300. if (AllowGCFullCollect)
  301. {
  302. GC.Collect();
  303. GC.WaitForPendingFinalizers();
  304. GC.Collect();
  305. GC.WaitForPendingFinalizers();
  306. }
  307. }
  308. private static int defaultSimplificationFactor = 50;
  309. public static int DefaultSimplificationFactor
  310. {
  311. get
  312. {
  313. return defaultSimplificationFactor;
  314. }
  315. set
  316. {
  317. defaultSimplificationFactor = value;
  318. }
  319. }
  320. public static bool IsArrowKey(Keys keyData)
  321. {
  322. Keys key = keyData & Keys.KeyCode;
  323. if (key == Keys.Up || key == Keys.Down || key == Keys.Left || key == Keys.Right)
  324. {
  325. return true;
  326. }
  327. else
  328. {
  329. return false;
  330. }
  331. }
  332. public static bool DoesControlHaveMouseCaptured(Control control)
  333. {
  334. bool result = false;
  335. result |= control.Capture;
  336. foreach (Control c in control.Controls)
  337. {
  338. result |= DoesControlHaveMouseCaptured(c);
  339. }
  340. return result;
  341. }
  342. public static void SplitRectangle(Rectangle rect, Rectangle[] rects)
  343. {
  344. int height = rect.Height;
  345. for (int i = 0; i < rects.Length; ++i)
  346. {
  347. Rectangle newRect = Rectangle.FromLTRB(rect.Left,
  348. rect.Top + ((height * i) / rects.Length),
  349. rect.Right,
  350. rect.Top + ((height * (i + 1)) / rects.Length));
  351. rects[i] = newRect;
  352. }
  353. }
  354. public static long TicksToMs(long ticks)
  355. {
  356. return ticks / 10000;
  357. }
  358. public static string GetStaticName(Type type)
  359. {
  360. PropertyInfo pi = type.GetProperty("StaticName", BindingFlags.Static | BindingFlags.Public | BindingFlags.GetProperty);
  361. return (string)pi.GetValue(null, null);
  362. }
  363. public static readonly float[][] Identity5x5F = new float[][] {
  364. new float[] { 1, 0, 0, 0, 0 },
  365. new float[] { 0, 1, 0, 0, 0 },
  366. new float[] { 0, 0, 1, 0, 0 },
  367. new float[] { 0, 0, 0, 1, 0 },
  368. new float[] { 0, 0, 0, 0, 1 }
  369. };
  370. public static readonly ColorMatrix IdentityColorMatrix = new ColorMatrix(Identity5x5F);
  371. [ThreadStatic]
  372. private static Matrix identityMatrix = null;
  373. public static Matrix IdentityMatrix
  374. {
  375. get
  376. {
  377. if (identityMatrix == null)
  378. {
  379. identityMatrix = new Matrix();
  380. identityMatrix.Reset();
  381. }
  382. return identityMatrix;
  383. }
  384. }
  385. /// <summary>
  386. /// Rounds an integer to the smallest power of 2 that is greater
  387. /// than or equal to it.
  388. /// </summary>
  389. public static int Log2RoundUp(int x)
  390. {
  391. if (x == 0)
  392. {
  393. return 1;
  394. }
  395. if (x == 1)
  396. {
  397. return 1;
  398. }
  399. return 1 << (1 + HighestBit(x - 1));
  400. }
  401. private static int HighestBit(int x)
  402. {
  403. if (x == 0)
  404. {
  405. return 0;
  406. }
  407. int b = 0;
  408. int hi = 0;
  409. while (b <= 30)
  410. {
  411. if ((x & (1 << b)) != 0)
  412. {
  413. hi = b;
  414. }
  415. ++b;
  416. }
  417. return hi;
  418. }
  419. private int CountBits(int x)
  420. {
  421. uint y = (uint)x;
  422. int count = 0;
  423. for (int bit = 0; bit < 32; ++bit)
  424. {
  425. if ((y & ((uint)1 << bit)) != 0)
  426. {
  427. ++count;
  428. }
  429. }
  430. return count;
  431. }
  432. public static string RemoveSpaces(string s)
  433. {
  434. StringBuilder sb = new StringBuilder();
  435. foreach (char c in s)
  436. {
  437. if (!char.IsWhiteSpace(c))
  438. {
  439. sb.Append(c);
  440. }
  441. }
  442. return sb.ToString();
  443. }
  444. public static int Max(int[,] array)
  445. {
  446. int max = int.MinValue;
  447. for (int i = array.GetLowerBound(0); i <= array.GetUpperBound(0); ++i)
  448. {
  449. for (int j = array.GetLowerBound(1); j <= array.GetUpperBound(1); ++j)
  450. {
  451. if (array[i,j] > max)
  452. {
  453. max = array[i,j];
  454. }
  455. }
  456. }
  457. return max;
  458. }
  459. public static int Sum(int[][] array)
  460. {
  461. int sum = 0;
  462. for (int i = 0; i < array.Length; ++i)
  463. {
  464. int[] row = array[i];
  465. for (int j = 0; j < row.Length; ++j)
  466. {
  467. sum += row[j];
  468. }
  469. }
  470. return sum;
  471. }
  472. // TODO: obsolete these NUD funcitons, move them into PdnNumericUpDown
  473. public static void ClipNumericUpDown(NumericUpDown upDown)
  474. {
  475. if (upDown.Value < upDown.Minimum)
  476. {
  477. upDown.Value = upDown.Minimum;
  478. }
  479. else if (upDown.Value > upDown.Maximum)
  480. {
  481. upDown.Value = upDown.Maximum;
  482. }
  483. }
  484. public static bool GetUpDownValueFromText(NumericUpDown nud, out double val)
  485. {
  486. if (nud.Text == string.Empty)
  487. {
  488. val = 0;
  489. return false;
  490. }
  491. else
  492. {
  493. try
  494. {
  495. if (nud.DecimalPlaces == 0)
  496. {
  497. val = (double)int.Parse(nud.Text);
  498. }
  499. else
  500. {
  501. val = double.Parse(nud.Text);
  502. }
  503. }
  504. catch
  505. {
  506. val = 0;
  507. return false;
  508. }
  509. return true;
  510. }
  511. }
  512. public static bool CheckNumericUpDown(NumericUpDown upDown)
  513. {
  514. int a;
  515. bool result = int.TryParse(upDown.Text, out a);
  516. if (result && (a <= (int)upDown.Maximum) && (a >= (int)upDown.Minimum))
  517. {
  518. return true;
  519. }
  520. else
  521. {
  522. return false;
  523. }
  524. }
  525. public static void SetNumericUpDownValue(NumericUpDown upDown, decimal newValue)
  526. {
  527. if (upDown.Value != newValue)
  528. {
  529. upDown.Value = newValue;
  530. }
  531. }
  532. public static void SetNumericUpDownValue(NumericUpDown upDown, int newValue)
  533. {
  534. SetNumericUpDownValue(upDown, (decimal)newValue);
  535. }
  536. public static string SizeStringFromBytes(long bytes)
  537. {
  538. double bytesDouble = (double)bytes;
  539. string toStringFormat;
  540. string formatString;
  541. if (bytesDouble > (1024 * 1024 * 1024))
  542. {
  543. // Gigs
  544. bytesDouble /= 1024 * 1024 * 1024;
  545. toStringFormat = "F1";
  546. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.GBFormat");
  547. }
  548. else if (bytesDouble > (1024 * 1024))
  549. {
  550. // Megs
  551. bytesDouble /= 1024 * 1024;
  552. toStringFormat = "F1";
  553. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.MBFormat");
  554. }
  555. else if (bytesDouble > (1024))
  556. {
  557. // K
  558. bytesDouble /= 1024;
  559. toStringFormat = "F1";
  560. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.KBFormat");
  561. }
  562. else
  563. {
  564. // Bytes
  565. toStringFormat = "F0";
  566. formatString = PdnResources.GetString("Utility.SizeStringFromBytes.BytesFormat");
  567. }
  568. string bytesString = bytesDouble.ToString(toStringFormat);
  569. string sizeString = string.Format(formatString, bytesString);
  570. return sizeString;
  571. }
  572. public static void ShowWiaError(IWin32Window owner)
  573. {
  574. // WIA requires Windows XP SP1 or later, or Windows Server 2003
  575. // So if we know they're on WS2k3, we tell them to enable WIA.
  576. // If they're on XP or later, tell them that WIA isn't available.
  577. // Otherwise we tell them they need XP SP1 (for the Win2K folks).
  578. if (OS.Type == OSType.Server)
  579. {
  580. Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.EnableMe"));
  581. }
  582. else
  583. {
  584. Utility.ErrorBox(owner, PdnResources.GetString("WIA.Error.UnableToLoad"));
  585. }
  586. }
  587. public static void ShowNonAdminErrorBox(IWin32Window parent)
  588. {
  589. ErrorBox(parent, PdnResources.GetString("NonAdminErrorBox.Message"));
  590. }
  591. public static void ErrorBox(IWin32Window parent, string message)
  592. {
  593. MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Error);
  594. }
  595. public static DialogResult ErrorBoxOKCancel(IWin32Window parent, string message)
  596. {
  597. return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
  598. }
  599. public static void InfoBox(IWin32Window parent, string message)
  600. {
  601. MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OK, MessageBoxIcon.Information);
  602. }
  603. public static DialogResult InfoBoxOKCancel(IWin32Window parent, string message)
  604. {
  605. return MessageBox.Show(parent, message, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Information);
  606. }
  607. public static DialogResult AskOKCancel(IWin32Window parent, string question)
  608. {
  609. return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
  610. }
  611. public static DialogResult AskYesNo(IWin32Window parent, string question)
  612. {
  613. return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNo, MessageBoxIcon.Question);
  614. }
  615. public static DialogResult AskYesNoCancel(IWin32Window parent, string question)
  616. {
  617. return MessageBox.Show(parent, question, PdnInfo.GetBareProductName(), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
  618. }
  619. public static Icon ImageToIcon(Image image)
  620. {
  621. return ImageToIcon(image, Utility.TransparentKey);
  622. }
  623. public static Icon ImageToIcon(Image image, bool disposeImage)
  624. {
  625. return ImageToIcon(image, Utility.TransparentKey, disposeImage);
  626. }
  627. public static Icon ImageToIcon(Image image, Color seeThru)
  628. {
  629. return ImageToIcon(image, seeThru, false);
  630. }
  631. /// <summary>
  632. /// Converts an Image to an Icon.
  633. /// </summary>
  634. /// <param name="image">The Image to convert to an icon. Must be an appropriate icon size (32x32, 16x16, etc).</param>
  635. /// <param name="seeThru">The color that will be treated as transparent in the icon.</param>
  636. /// <param name="disposeImage">Whether or not to dispose the passed-in Image.</param>
  637. /// <returns>An Icon representation of the Image.</returns>
  638. public static Icon ImageToIcon(Image image, Color seeThru, bool disposeImage)
  639. {
  640. Bitmap bitmap = new Bitmap(image);
  641. for (int y = 0; y < bitmap.Height; ++y)
  642. {
  643. for (int x = 0; x < bitmap.Width; ++x)
  644. {
  645. if (bitmap.GetPixel(x, y) == seeThru)
  646. {
  647. bitmap.SetPixel(x, y, Color.FromArgb(0));
  648. }
  649. }
  650. }
  651. Icon icon = Icon.FromHandle(bitmap.GetHicon());
  652. bitmap.Dispose();
  653. if (disposeImage)
  654. {
  655. image.Dispose();
  656. }
  657. return icon;
  658. }
  659. public static Icon BitmapToIcon(Bitmap bitmap, bool disposeBitmap)
  660. {
  661. Icon icon = Icon.FromHandle(bitmap.GetHicon());
  662. if (disposeBitmap)
  663. {
  664. bitmap.Dispose();
  665. }
  666. return icon;
  667. }
  668. public static Icon SurfaceToIcon(Surface surface, bool disposeSurface)
  669. {
  670. Bitmap bitmap = surface.CreateAliasedBitmap();
  671. Icon icon = Icon.FromHandle(bitmap.GetHicon());
  672. bitmap.Dispose();
  673. if (disposeSurface)
  674. {
  675. surface.Dispose();
  676. }
  677. return icon;
  678. }
  679. public static Point GetRectangleCenter(Rectangle rect)
  680. {
  681. return new Point((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
  682. }
  683. public static PointF GetRectangleCenter(RectangleF rect)
  684. {
  685. return new PointF((rect.Left + rect.Right) / 2, (rect.Top + rect.Bottom) / 2);
  686. }
  687. public static Scanline[] GetRectangleScans(Rectangle rect)
  688. {
  689. Scanline[] scans = new Scanline[rect.Height];
  690. for (int y = 0; y < rect.Height; ++y)
  691. {
  692. scans[y] = new Scanline(rect.X, rect.Y + y, rect.Width);
  693. }
  694. return scans;
  695. }
  696. public static Scanline[] GetRegionScans(Rectangle[] region)
  697. {
  698. int scanCount = 0;
  699. for (int i = 0; i < region.Length; ++i)
  700. {
  701. scanCount += region[i].Height;
  702. }
  703. Scanline[] scans = new Scanline[scanCount];
  704. int scanIndex = 0;
  705. foreach (Rectangle rect in region)
  706. {
  707. for (int y = 0; y < rect.Height; ++y)
  708. {
  709. scans[scanIndex] = new Scanline(rect.X, rect.Y + y, rect.Width);
  710. ++scanIndex;
  711. }
  712. }
  713. return scans;
  714. }
  715. public static Rectangle[] ScanlinesToRectangles(Scanline[] scans)
  716. {
  717. return ScanlinesToRectangles(scans, 0, scans.Length);
  718. }
  719. public static Rectangle[] ScanlinesToRectangles(Scanline[] scans, int startIndex, int length)
  720. {
  721. Rectangle[] rects = new Rectangle[length];
  722. for (int i = 0; i < length; ++i)
  723. {
  724. Scanline scan = scans[i + startIndex];
  725. rects[i] = new Rectangle(scan.X, scan.Y, scan.Length, 1);
  726. }
  727. return rects;
  728. }
  729. /// <summary>
  730. /// Found on Google Groups when searching for "Region.Union" while looking
  731. /// for bugs:
  732. /// ---
  733. /// Hello,
  734. ///
  735. /// I did not run your code, but I know Region.Union is flawed in both 1.0 and
  736. /// 1.1, so I assume it is in the gdi+ unmanged code dll. The best workaround,
  737. /// in terms of speed, is to use a PdnGraphicsPath, but it must be a path with
  738. /// FillMode = FillMode.Winding. You add the rectangles to the path, then you do
  739. /// union onto an empty region with the path. The important point is to do only
  740. /// one union call on a given empty region. We created a "super region" object
  741. /// to hide all these bugs and optimize clipping operations. In fact, it is much
  742. /// faster to use the path than to call Region.Union for each rectangle.
  743. ///
  744. /// Too bad about Region.Union. A lot of people will hit this bug, as it is
  745. /// essential in high-performance animation.
  746. ///
  747. /// Regards,
  748. /// Frank Hileman
  749. /// Prodige Software Corporation
  750. /// ---
  751. /// </summary>
  752. /// <param name="rectsF"></param>
  753. /// <param name="startIndex"></param>
  754. /// <param name="length"></param>
  755. /// <returns></returns>
  756. public static PdnRegion RectanglesToRegion(RectangleF[] rectsF, int startIndex, int length)
  757. {
  758. PdnRegion region;
  759. if (rectsF == null || rectsF.Length == 0 || length == 0)
  760. {
  761. region = PdnRegion.CreateEmpty();
  762. }
  763. else
  764. {
  765. using (PdnGraphicsPath path = new PdnGraphicsPath())
  766. {
  767. path.FillMode = FillMode.Winding;
  768. if (startIndex == 0 && length == rectsF.Length)
  769. {
  770. path.AddRectangles(rectsF);
  771. }
  772. else
  773. {
  774. for (int i = startIndex; i < startIndex + length; ++i)
  775. {
  776. path.AddRectangle(rectsF[i]);
  777. }
  778. }
  779. region = new PdnRegion(path);
  780. }
  781. }
  782. return region;
  783. }
  784. public static PdnRegion RectanglesToRegion(RectangleF[] rectsF)
  785. {
  786. return RectanglesToRegion(rectsF, 0, rectsF != null ? rectsF.Length : 0);
  787. }
  788. public static PdnRegion RectanglesToRegion(RectangleF[] rectsF1, RectangleF[] rectsF2, params RectangleF[][] rectsFA)
  789. {
  790. using (PdnGraphicsPath path = new PdnGraphicsPath())
  791. {
  792. path.FillMode = FillMode.Winding;
  793. if (rectsF1 != null && rectsF1.Length > 0)
  794. {
  795. path.AddRectangles(rectsF1);
  796. }
  797. if (rectsF2 != null && rectsF2.Length > 0)
  798. {
  799. path.AddRectangles(rectsF2);
  800. }
  801. foreach (RectangleF[] rectsF in rectsFA)
  802. {
  803. if (rectsF != null && rectsF.Length > 0)
  804. {
  805. path.AddRectangles(rectsF);
  806. }
  807. }
  808. return new PdnRegion(path);
  809. }
  810. }
  811. public static PdnRegion RectanglesToRegion(Rectangle[] rects, int startIndex, int length)
  812. {
  813. PdnRegion region;
  814. if (length == 0)
  815. {
  816. region = PdnRegion.CreateEmpty();
  817. }
  818. else
  819. {
  820. using (PdnGraphicsPath path = new PdnGraphicsPath())
  821. {
  822. path.FillMode = FillMode.Winding;
  823. if (startIndex == 0 && length == rects.Length)
  824. {
  825. path.AddRectangles(rects);
  826. }
  827. else
  828. {
  829. for (int i = startIndex; i < startIndex + length; ++i)
  830. {
  831. path.AddRectangle(rects[i]);
  832. }
  833. }
  834. region = new PdnRegion(path);
  835. path.Dispose();
  836. }
  837. }
  838. return region;
  839. }
  840. public static PdnRegion RectanglesToRegion(Rectangle[] rects)
  841. {
  842. return RectanglesToRegion(rects, 0, rects.Length);
  843. }
  844. public static int GetRegionArea(RectangleF[] rectsF)
  845. {
  846. int area = 0;
  847. foreach (RectangleF rectF in rectsF)
  848. {
  849. Rectangle rect = Rectangle.Truncate(rectF);
  850. area += rect.Width * rect.Height;
  851. }
  852. return area;
  853. }
  854. public static RectangleF RectangleFromCenter(PointF center, float halfSize)
  855. {
  856. RectangleF ret = new RectangleF(center.X, center.Y, 0, 0);
  857. ret.Inflate(halfSize, halfSize);
  858. return ret;
  859. }
  860. public static List<PointF> PointListToPointFList(List<Point> ptList)
  861. {
  862. List<PointF> ret = new List<PointF>(ptList.Count);
  863. for (int i = 0; i < ptList.Count; ++i)
  864. {
  865. ret.Add((PointF)ptList[i]);
  866. }
  867. return ret;
  868. }
  869. public static PointF[] PointArrayToPointFArray(Point[] ptArray)
  870. {
  871. PointF[] ret = new PointF[ptArray.Length];
  872. for (int i = 0; i < ret.Length; ++i)
  873. {
  874. ret[i] = (PointF)ptArray[i];
  875. }
  876. return ret;
  877. }
  878. public static Rectangle[] InflateRectangles(Rectangle[] rects, int amount)
  879. {
  880. Rectangle[] inflated = new Rectangle[rects.Length];
  881. for (int i = 0; i < rects.Length; ++i)
  882. {
  883. inflated[i] = Rectangle.Inflate(rects[i], amount, amount);
  884. }
  885. return inflated;
  886. }
  887. public static void InflateRectanglesInPlace(Rectangle[] rects, int amount)
  888. {
  889. for (int i = 0; i < rects.Length; ++i)
  890. {
  891. rects[i].Inflate(amount, amount);
  892. }
  893. }
  894. public static RectangleF[] InflateRectangles(RectangleF[] rectsF, int amount)
  895. {
  896. RectangleF[] inflated = new RectangleF[rectsF.Length];
  897. for (int i = 0; i < rectsF.Length; ++i)
  898. {
  899. inflated[i] = RectangleF.Inflate(rectsF[i], amount, amount);
  900. }
  901. return inflated;
  902. }
  903. public static void InflateRectanglesInPlace(RectangleF[] rectsF, float amount)
  904. {
  905. for (int i = 0; i < rectsF.Length; ++i)
  906. {
  907. rectsF[i].Inflate(amount, amount);
  908. }
  909. }
  910. public static Rectangle PointsToConstrainedRectangle(Point a, Point b)
  911. {
  912. Rectangle rect = Utility.PointsToRectangle(a, b);
  913. int minWH = Math.Min(rect.Width, rect.Height);
  914. rect.Width = minWH;
  915. rect.Height = minWH;
  916. if (rect.Y != a.Y)
  917. {
  918. rect.Location = new Point(rect.X, a.Y - minWH);
  919. }
  920. if (rect.X != a.X)
  921. {
  922. rect.Location = new Point(a.X - minWH, rect.Y);
  923. }
  924. return rect;
  925. }
  926. public static RectangleF PointsToConstrainedRectangle(PointF a, PointF b)
  927. {
  928. RectangleF rect = Utility.PointsToRectangle(a, b);
  929. float minWH = Math.Min(rect.Width, rect.Height);
  930. rect.Width = minWH;
  931. rect.Height = minWH;
  932. if (rect.Y != a.Y)
  933. {
  934. rect.Location = new PointF(rect.X, a.Y - minWH);
  935. }
  936. if (rect.X != a.X)
  937. {
  938. rect.Location = new PointF(a.X - minWH, rect.Y);
  939. }
  940. return rect;
  941. }
  942. /// <summary>
  943. /// Takes two points and creates a bounding rectangle from them.
  944. /// </summary>
  945. /// <param name="a">One corner of the rectangle.</param>
  946. /// <param name="b">The other corner of the rectangle.</param>
  947. /// <returns>A Rectangle instance that bounds the two points.</returns>
  948. public static Rectangle PointsToRectangle(Point a, Point b)
  949. {
  950. int x = Math.Min(a.X, b.X);
  951. int y = Math.Min(a.Y, b.Y);
  952. int width = Math.Abs(a.X - b.X) + 1;
  953. int height = Math.Abs(a.Y - b.Y) + 1;
  954. return new Rectangle(x, y, width, height);
  955. }
  956. public static RectangleF PointsToRectangle(PointF a, PointF b)
  957. {
  958. float x = Math.Min(a.X, b.X);
  959. float y = Math.Min(a.Y, b.Y);
  960. float width = Math.Abs(a.X - b.X) + 1;
  961. float height = Math.Abs(a.Y - b.Y) + 1;
  962. return new RectangleF(x, y, width, height);
  963. }
  964. public static Rectangle PointsToRectangleExclusive(Point a, Point b)
  965. {
  966. int x = Math.Min(a.X, b.X);
  967. int y = Math.Min(a.Y, b.Y);
  968. int width = Math.Abs(a.X - b.X);
  969. int height = Math.Abs(a.Y - b.Y);
  970. return new Rectangle(x, y, width, height);
  971. }
  972. public static RectangleF PointsToRectangleExclusive(PointF a, PointF b)
  973. {
  974. float x = Math.Min(a.X, b.X);
  975. float y = Math.Min(a.Y, b.Y);
  976. float width = Math.Abs(a.X - b.X);
  977. float height = Math.Abs(a.Y - b.Y);
  978. return new RectangleF(x, y, width, height);
  979. }
  980. public static RectangleF[] PointsToRectangles(PointF[] pointsF)
  981. {
  982. if (pointsF.Length == 0)
  983. {
  984. return new RectangleF[] { };
  985. }
  986. if (pointsF.Length == 1)
  987. {
  988. return new RectangleF[] { new RectangleF(pointsF[0].X, pointsF[0].Y, 1, 1) };
  989. }
  990. RectangleF[] rectsF = new RectangleF[pointsF.Length - 1];
  991. for (int i = 0; i < pointsF.Length - 1; ++i)
  992. {
  993. rectsF[i] = PointsToRectangle(pointsF[i], pointsF[i + 1]);
  994. }
  995. return rectsF;
  996. }
  997. public static Rectangle[] PointsToRectangles(Point[] points)
  998. {
  999. if (points.Length == 0)
  1000. {
  1001. return new Rectangle[] { };
  1002. }
  1003. if (points.Length == 1)
  1004. {
  1005. return new Rectangle[] { new Rectangle(points[0].X, points[0].Y, 1, 1) };
  1006. }
  1007. Rectangle[] rects = new Rectangle[points.Length - 1];
  1008. for (int i = 0; i < points.Length - 1; ++i)
  1009. {
  1010. rects[i] = PointsToRectangle(points[i], points[i + 1]);
  1011. }
  1012. return rects;
  1013. }
  1014. /// <summary>
  1015. /// Converts a RectangleF to RectangleF by rounding down the Location and rounding
  1016. /// up the Size.
  1017. /// </summary>
  1018. public static Rectangle RoundRectangle(RectangleF rectF)
  1019. {
  1020. float left = (float)Math.Floor(rectF.Left);
  1021. float top = (float)Math.Floor(rectF.Top);
  1022. float right = (float)Math.Ceiling(rectF.Right);
  1023. float bottom = (float)Math.Ceiling(rectF.Bottom);
  1024. return Rectangle.Truncate(RectangleF.FromLTRB(left, top, right, bottom));
  1025. }
  1026. public static Stack Reverse(Stack reverseMe)
  1027. {
  1028. Stack reversed = new Stack();
  1029. foreach (object o in reverseMe)
  1030. {
  1031. reversed.Push(o);
  1032. }
  1033. return reversed;
  1034. }
  1035. public static void SerializeObjectToStream(object graph, Stream stream)
  1036. {
  1037. new BinaryFormatter().Serialize(stream, graph);
  1038. }
  1039. public static object DeserializeObjectFromStream(Stream stream)
  1040. {
  1041. return new BinaryFormatter().Deserialize(stream);
  1042. }
  1043. [Obsolete("Use rect.Contains() instead", true)]
  1044. public static bool IsPointInRectangle(Point pt, Rectangle rect)
  1045. {
  1046. return rect.Contains(pt);
  1047. }
  1048. [Obsolete("Use rect.Contains() instead", true)]
  1049. public static bool IsPointInRectangle(int x, int y, Rectangle rect)
  1050. {
  1051. return rect.Contains(x, y);
  1052. }
  1053. public static Bitmap FullCloneBitmap(Bitmap cloneMe)
  1054. {
  1055. Bitmap bitmap = new Bitmap(cloneMe.Width, cloneMe.Height, cloneMe.PixelFormat);
  1056. using (Graphics g = Graphics.FromImage(bitmap))
  1057. {
  1058. g.DrawImage(cloneMe, 0, 0, cloneMe.Width, cloneMe.Height);
  1059. }
  1060. return bitmap;
  1061. }
  1062. /// <summary>
  1063. /// Allows you to find the bounding box for a Region object without requiring
  1064. /// the presence of a Graphics object.
  1065. /// (Region.GetBounds takes a Graphics instance as its only parameter.)
  1066. /// </summary>
  1067. /// <param name="region">The region you want to find a bounding box for.</param>
  1068. /// <returns>A RectangleF structure that surrounds the Region.</returns>
  1069. public static Rectangle GetRegionBounds(PdnRegion region)
  1070. {
  1071. Rectangle[] rects = region.GetRegionScansReadOnlyInt();
  1072. return GetRegionBounds(rects, 0, rects.Length);
  1073. }
  1074. /// <summary>
  1075. /// Allows you to find the bounding box for a "region" that is described as an
  1076. /// array of bounding boxes.
  1077. /// </summary>
  1078. /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
  1079. /// <returns>A RectangleF structure that surrounds the Region.</returns>
  1080. public static RectangleF GetRegionBounds(RectangleF[] rectsF, int startIndex, int length)
  1081. {
  1082. if (rectsF.Length == 0)
  1083. {
  1084. return RectangleF.Empty;
  1085. }
  1086. float left = rectsF[startIndex].Left;
  1087. float top = rectsF[startIndex].Top;
  1088. float right = rectsF[startIndex].Right;
  1089. float bottom = rectsF[startIndex].Bottom;
  1090. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1091. {
  1092. RectangleF rectF = rectsF[i];
  1093. if (rectF.Left < left)
  1094. {
  1095. left = rectF.Left;
  1096. }
  1097. if (rectF.Top < top)
  1098. {
  1099. top = rectF.Top;
  1100. }
  1101. if (rectF.Right > right)
  1102. {
  1103. right = rectF.Right;
  1104. }
  1105. if (rectF.Bottom > bottom)
  1106. {
  1107. bottom = rectF.Bottom;
  1108. }
  1109. }
  1110. return RectangleF.FromLTRB(left, top, right, bottom);
  1111. }
  1112. public static RectangleF GetTraceBounds(PointF[] pointsF, int startIndex, int length)
  1113. {
  1114. if (pointsF.Length == 0)
  1115. {
  1116. return RectangleF.Empty;
  1117. }
  1118. float left = pointsF[startIndex].X;
  1119. float top = pointsF[startIndex].Y;
  1120. float right = 1 + pointsF[startIndex].X;
  1121. float bottom = 1 + pointsF[startIndex].Y;
  1122. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1123. {
  1124. PointF pointF = pointsF[i];
  1125. if (pointF.X < left)
  1126. {
  1127. left = pointF.X;
  1128. }
  1129. if (pointF.Y < top)
  1130. {
  1131. top = pointF.Y;
  1132. }
  1133. if (pointF.X > right)
  1134. {
  1135. right = pointF.X;
  1136. }
  1137. if (pointF.Y > bottom)
  1138. {
  1139. bottom = pointF.Y;
  1140. }
  1141. }
  1142. return RectangleF.FromLTRB(left, top, right, bottom);
  1143. }
  1144. public static Rectangle GetTraceBounds(Point[] points, int startIndex, int length)
  1145. {
  1146. if (points.Length == 0)
  1147. {
  1148. return Rectangle.Empty;
  1149. }
  1150. int left = points[startIndex].X;
  1151. int top = points[startIndex].Y;
  1152. int right = 1 + points[startIndex].X;
  1153. int bottom = 1 + points[startIndex].Y;
  1154. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1155. {
  1156. Point point = points[i];
  1157. if (point.X < left)
  1158. {
  1159. left = point.X;
  1160. }
  1161. if (point.Y < top)
  1162. {
  1163. top = point.Y;
  1164. }
  1165. if (point.X > right)
  1166. {
  1167. right = point.X;
  1168. }
  1169. if (point.Y > bottom)
  1170. {
  1171. bottom = point.Y;
  1172. }
  1173. }
  1174. return Rectangle.FromLTRB(left, top, right, bottom);
  1175. }
  1176. /// <summary>
  1177. /// Allows you to find the bounding box for a "region" that is described as an
  1178. /// array of bounding boxes.
  1179. /// </summary>
  1180. /// <param name="rectsF">The "region" you want to find a bounding box for.</param>
  1181. /// <returns>A RectangleF structure that surrounds the Region.</returns>
  1182. public static Rectangle GetRegionBounds(Rectangle[] rects, int startIndex, int length)
  1183. {
  1184. if (rects.Length == 0)
  1185. {
  1186. return Rectangle.Empty;
  1187. }
  1188. int left = rects[startIndex].Left;
  1189. int top = rects[startIndex].Top;
  1190. int right = rects[startIndex].Right;
  1191. int bottom = rects[startIndex].Bottom;
  1192. for (int i = startIndex + 1; i < startIndex + length; ++i)
  1193. {
  1194. Rectangle rect = rects[i];
  1195. if (rect.Left < left)
  1196. {
  1197. left = rect.Left;
  1198. }
  1199. if (rect.Top < top)
  1200. {
  1201. top = rect.Top;
  1202. }
  1203. if (rect.Right > right)
  1204. {
  1205. right = rect.Right;
  1206. }
  1207. if (rect.Bottom > bottom)
  1208. {
  1209. bottom = rect.Bottom;
  1210. }
  1211. }
  1212. return Rectangle.FromLTRB(left, top, right, bottom);
  1213. }
  1214. public static RectangleF GetRegionBounds(RectangleF[] rectsF)
  1215. {
  1216. return GetRegionBounds(rectsF, 0, rectsF.Length);
  1217. }
  1218. public static Rectangle GetRegionBounds(Rectangle[] rects)
  1219. {
  1220. return GetRegionBounds(rects, 0, rects.Length);
  1221. }
  1222. private static float DistanceSquared(RectangleF[] rectsF, int indexA, int indexB)
  1223. {
  1224. PointF centerA = new PointF(rectsF[indexA].Left + (rectsF[indexA].Width / 2), rectsF[indexA].Top + (rectsF[indexA].Height / 2));
  1225. PointF centerB = new PointF(rectsF[indexB].Left + (rectsF[indexB].Width / 2), rectsF[indexB].Top + (rectsF[indexB].Height / 2));
  1226. return ((centerA.X - centerB.X) * (centerA.X - centerB.X)) +
  1227. ((centerA.Y - centerB.Y) * (centerA.Y - centerB.Y));
  1228. }
  1229. /// <summary>
  1230. /// Simplifies a Region into N number of bounding boxes.
  1231. /// </summary>
  1232. /// <param name="region">The Region to simplify.</param>
  1233. /// <param name="complexity">The maximum number of bounding boxes to return, or 0 for however many are necessary (equivalent to using Region.GetRegionScans).</param>
  1234. /// <returns></returns>
  1235. public static Rectangle[] SimplifyRegion(PdnRegion region, int complexity)
  1236. {
  1237. Rectangle[] rects = region.GetRegionScansReadOnlyInt();
  1238. return SimplifyRegion(rects, complexity);
  1239. }
  1240. public static Rectangle[] SimplifyRegion(Rectangle[] rects, int complexity)
  1241. {
  1242. if (complexity == 0 || rects.Length < complexity)
  1243. {
  1244. return (Rectangle[])rects.Clone();
  1245. }
  1246. Rectangle[] boxes = new Rectangle[complexity];
  1247. for (int i = 0; i < complexity; ++i)
  1248. {
  1249. int startIndex = (i * rects.Length) / complexity;
  1250. int length = Math.Min(rects.Length, ((i + 1) * rects.Length) / complexity) - startIndex;
  1251. boxes[i] = GetRegionBounds(rects, startIndex, length);
  1252. }
  1253. return boxes;
  1254. }
  1255. public static RectangleF[] SimplifyTrace(PointF[] pointsF, int complexity)
  1256. {
  1257. if (complexity == 0 ||
  1258. (pointsF.Length - 1) < complexity)
  1259. {
  1260. return PointsToRectangles(pointsF);
  1261. }
  1262. RectangleF[] boxes = new RectangleF[complexity];
  1263. int parLength = pointsF.Length - 1; // "(points as Rectangles).Length"
  1264. for (int i = 0; i < complexity; ++i)
  1265. {
  1266. int startIndex = (i * parLength) / complexity;
  1267. int length = Math.Min(parLength, ((i + 1) * parLength) / complexity) - sta

Large files files are truncated, but you can click here to view the full file