ImageUtils.cs 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036
  1. using InABox.Core;
  2. using Syncfusion.Pdf.Parsing;
  3. using System.Drawing.Drawing2D;
  4. using System.Drawing.Imaging;
  5. using System.Globalization;
  6. using System.IO;
  7. using System.Runtime.InteropServices;
  8. using System.Windows;
  9. using System.Windows.Interop;
  10. using System.Windows.Media;
  11. using System.Windows.Media.Imaging;
  12. using System.Xml.Linq;
  13. using ColorHelper;
  14. using Color = System.Drawing.Color;
  15. using Pen = System.Drawing.Pen;
  16. using PixelFormat = System.Drawing.Imaging.PixelFormat;
  17. using Point = System.Drawing.Point;
  18. using Size = System.Drawing.Size;
  19. using System.Windows.Controls;
  20. using System.Drawing;
  21. using System.Collections.Generic;
  22. using System;
  23. using System.Linq;
  24. using Syncfusion.Pdf.Graphics;
  25. using Syncfusion.Pdf;
  26. using System.Diagnostics.CodeAnalysis;
  27. namespace InABox.WPF
  28. {
  29. public static class ImageUtils
  30. {
  31. // https://en.wikipedia.org/wiki/List_of_file_signatures
  32. /* Bytes in c# have a range of 0 to 255 so each byte can be represented as
  33. * a two digit hex string. */
  34. private static readonly Dictionary<ImageFormat, string[][]> SignatureTable = new()
  35. {
  36. {
  37. ImageFormat.Jpeg,
  38. new[]
  39. {
  40. new[] { "FF", "D8", "FF", "DB" },
  41. new[] { "FF", "D8", "FF", "EE" },
  42. new[] { "FF", "D8", "FF", "E0", "00", "10", "4A", "46", "49", "46", "00", "01" }
  43. }
  44. },
  45. {
  46. ImageFormat.Gif,
  47. new[]
  48. {
  49. new[] { "47", "49", "46", "38", "37", "61" },
  50. new[] { "47", "49", "46", "38", "39", "61" }
  51. }
  52. },
  53. {
  54. ImageFormat.Png,
  55. new[]
  56. {
  57. new[] { "89", "50", "4E", "47", "0D", "0A", "1A", "0A" }
  58. }
  59. },
  60. {
  61. ImageFormat.Bmp,
  62. new[]
  63. {
  64. new[] { "42", "4D" }
  65. }
  66. }
  67. };
  68. public static Size Adjust(this Size src, double maxWidth, double maxHeight, bool enlarge = false)
  69. {
  70. maxWidth = enlarge ? maxWidth : Math.Min(maxWidth, src.Width);
  71. maxHeight = enlarge ? maxHeight : Math.Min(maxHeight, src.Height);
  72. var rnd = Math.Min((decimal)maxWidth / src.Width, (decimal)maxHeight / src.Height);
  73. return new Size((int)Math.Round(src.Width * rnd), (int)Math.Round(src.Height * rnd));
  74. }
  75. public static Bitmap AsGrayScale(this Bitmap source)
  76. {
  77. //create a blank bitmap the same size as original
  78. var newBitmap = new Bitmap(source.Width, source.Height);
  79. //get a graphics object from the new image
  80. var g = Graphics.FromImage(newBitmap);
  81. //create the grayscale ColorMatrix
  82. var colorMatrix = new ColorMatrix(
  83. new[]
  84. {
  85. new[] { .3f, .3f, .3f, 0, 0 },
  86. new[] { .59f, .59f, .59f, 0, 0 },
  87. new[] { .11f, .11f, .11f, 0, 0 },
  88. new float[] { 0, 0, 0, 1, 0 },
  89. new float[] { 0, 0, 0, 0, 1 }
  90. });
  91. //create some image attributes
  92. var attributes = new ImageAttributes();
  93. //set the color matrix attribute
  94. attributes.SetColorMatrix(colorMatrix);
  95. //draw the original image on the new image
  96. //using the grayscale color matrix
  97. g.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height),
  98. 0, 0, source.Width, source.Height, GraphicsUnit.Pixel, attributes);
  99. //dispose the Graphics object
  100. g.Dispose();
  101. return newBitmap;
  102. }
  103. public static BitmapImage AsBitmapImage(this Bitmap src, int height, int width, bool transparent = true)
  104. {
  105. var resized = new Bitmap(src, new Size(width, height));
  106. return AsBitmapImage(resized, transparent);
  107. }
  108. public static BitmapImage AsBitmapImage(this Bitmap src, Color transparent)
  109. {
  110. src.MakeTransparent(transparent);
  111. return src.AsBitmapImage();
  112. }
  113. public static Bitmap ChangeColor(this Bitmap image, Color fromColor, Color toColor)
  114. {
  115. var attributes = new ImageAttributes();
  116. attributes.SetRemapTable(new ColorMap[]
  117. {
  118. new()
  119. {
  120. OldColor = fromColor,
  121. NewColor = toColor
  122. }
  123. }, ColorAdjustType.Bitmap);
  124. using (var g = Graphics.FromImage(image))
  125. {
  126. g.DrawImage(
  127. image,
  128. new Rectangle(Point.Empty, image.Size),
  129. 0, 0, image.Width, image.Height,
  130. GraphicsUnit.Pixel,
  131. attributes);
  132. }
  133. return image;
  134. }
  135. public static Bitmap Fade(this Bitmap source, float opacity)
  136. {
  137. var result = new Bitmap(source.Width, source.Height);
  138. //create a graphics object from the image
  139. using (var gfx = Graphics.FromImage(result))
  140. {
  141. if (opacity < 1.0)
  142. gfx.Clear(Color.White);
  143. //create a color matrix object
  144. var matrix = new ColorMatrix();
  145. //set the opacity
  146. matrix.Matrix33 = opacity;
  147. //create image attributes
  148. var attributes = new ImageAttributes();
  149. //set the color(opacity) of the image
  150. attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);
  151. //now draw the image
  152. gfx.DrawImage(source, new Rectangle(0, 0, source.Width, source.Height), 0, 0, source.Width, source.Height, GraphicsUnit.Pixel,
  153. attributes);
  154. }
  155. return result;
  156. }
  157. public static BitmapImage AsBitmapImage(this Bitmap src, Color replace, Color with)
  158. {
  159. return src.ChangeColor(replace, with).AsBitmapImage(false);
  160. }
  161. public static Bitmap AsBitmap(this BitmapImage bitmapImage)
  162. {
  163. using (var outStream = new MemoryStream())
  164. {
  165. BitmapEncoder enc = new BmpBitmapEncoder();
  166. enc.Frames.Add(BitmapFrame.Create(bitmapImage));
  167. enc.Save(outStream);
  168. var bitmap = new Bitmap(outStream);
  169. return new Bitmap(bitmap);
  170. }
  171. }
  172. public static Bitmap AsBitmap(this BitmapSource source)
  173. {
  174. var width = source.PixelWidth;
  175. var height = source.PixelHeight;
  176. var stride = width * ((source.Format.BitsPerPixel + 7) / 8);
  177. var ptr = IntPtr.Zero;
  178. try
  179. {
  180. ptr = Marshal.AllocHGlobal(height * stride);
  181. source.CopyPixels(new Int32Rect(0, 0, width, height), ptr, height * stride, stride);
  182. using (var btm = new Bitmap(width, height, stride, PixelFormat.Format1bppIndexed, ptr))
  183. {
  184. return new Bitmap(btm);
  185. }
  186. }
  187. finally
  188. {
  189. if (ptr != IntPtr.Zero)
  190. Marshal.FreeHGlobal(ptr);
  191. }
  192. }
  193. public static Bitmap AsBitmap2(this BitmapSource source)
  194. {
  195. var bmp = new Bitmap(
  196. source.PixelWidth,
  197. source.PixelHeight,
  198. PixelFormat.Format32bppPArgb);
  199. var data = bmp.LockBits(
  200. new Rectangle(Point.Empty, bmp.Size),
  201. ImageLockMode.WriteOnly,
  202. PixelFormat.Format32bppPArgb);
  203. source.CopyPixels(
  204. Int32Rect.Empty,
  205. data.Scan0,
  206. data.Height * data.Stride,
  207. data.Stride);
  208. bmp.UnlockBits(data);
  209. return bmp;
  210. }
  211. public static BitmapImage? BitmapImageFromBase64(string base64)
  212. {
  213. return BitmapImageFromBytes(Convert.FromBase64String(base64));
  214. }
  215. public static BitmapImage? BitmapImageFromBytes(byte[] data)
  216. {
  217. var imageSource = new BitmapImage();
  218. if(data.Length > 0)
  219. {
  220. using (var ms = new MemoryStream(data))
  221. {
  222. imageSource.BeginInit();
  223. imageSource.StreamSource = ms;
  224. imageSource.CacheOption = BitmapCacheOption.OnLoad;
  225. imageSource.EndInit();
  226. }
  227. return imageSource;
  228. }
  229. return null;
  230. }
  231. public static BitmapImage? BitmapImageFromStream(Stream data)
  232. {
  233. var imageSource = new BitmapImage();
  234. imageSource.BeginInit();
  235. imageSource.StreamSource = data;
  236. imageSource.CacheOption = BitmapCacheOption.OnLoad;
  237. imageSource.EndInit();
  238. return imageSource;
  239. }
  240. public static BitmapImage AsBitmapImage(this Bitmap src, bool transparent = true)
  241. {
  242. if (transparent)
  243. {
  244. var pixel = src.GetPixel(0, 0);
  245. if(pixel.A == byte.MaxValue)
  246. {
  247. src.MakeTransparent(pixel);
  248. }
  249. }
  250. var bitmapImage = new BitmapImage();
  251. using (var memory = new MemoryStream())
  252. {
  253. src.Save(memory, ImageFormat.Png);
  254. memory.Position = 0;
  255. bitmapImage.BeginInit();
  256. bitmapImage.StreamSource = memory;
  257. bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
  258. bitmapImage.EndInit();
  259. }
  260. return bitmapImage;
  261. }
  262. public static BitmapSource AsBitmapSource(this Metafile metafile, int width, int height, Color background)
  263. {
  264. var src = new Bitmap(metafile.Width, metafile.Height);
  265. src.SetResolution(metafile.HorizontalResolution, metafile.VerticalResolution);
  266. using (var g = Graphics.FromImage(src))
  267. {
  268. g.DrawImage(metafile, 0, 0, metafile.Width, metafile.Height);
  269. }
  270. var scale = Math.Min(width / (float)metafile.Width, height / (float)metafile.Height);
  271. var scaleWidth = src.Width * scale;
  272. var scaleHeight = src.Height * scale;
  273. var xoffset = (width - scaleWidth) / 2.0F;
  274. var yoffset = (height - scaleHeight) / 2.0F;
  275. using (var bmp = new Bitmap(width, height))
  276. {
  277. bmp.SetResolution(metafile.HorizontalResolution, metafile.VerticalResolution);
  278. using (var g = Graphics.FromImage(bmp))
  279. {
  280. g.InterpolationMode = InterpolationMode.High;
  281. g.CompositingQuality = CompositingQuality.HighQuality;
  282. g.SmoothingMode = SmoothingMode.AntiAlias;
  283. g.FillRectangle(new SolidBrush(background), new RectangleF(0, 0, width, height));
  284. g.DrawImage(src, xoffset, yoffset, scaleWidth, scaleHeight);
  285. }
  286. bmp.Save("c:\\development\\emf2bmp.png");
  287. return Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
  288. }
  289. }
  290. public static Bitmap BitmapSourceToBitmap(BitmapSource source)
  291. {
  292. if (source == null)
  293. return null;
  294. var pixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppArgb; //Bgr32 equiv default
  295. if (source.Format == PixelFormats.Bgr24)
  296. pixelFormat = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
  297. else if (source.Format == PixelFormats.Pbgra32)
  298. pixelFormat = System.Drawing.Imaging.PixelFormat.Format32bppPArgb;
  299. else if (source.Format == PixelFormats.Prgba64)
  300. pixelFormat = System.Drawing.Imaging.PixelFormat.Format64bppPArgb;
  301. Bitmap bmp = new Bitmap(
  302. source.PixelWidth,
  303. source.PixelHeight,
  304. pixelFormat);
  305. BitmapData data = bmp.LockBits(
  306. new Rectangle(System.Drawing.Point.Empty, bmp.Size),
  307. ImageLockMode.WriteOnly,
  308. pixelFormat);
  309. source.CopyPixels(
  310. Int32Rect.Empty,
  311. data.Scan0,
  312. data.Height * data.Stride,
  313. data.Stride);
  314. bmp.UnlockBits(data);
  315. return bmp;
  316. }
  317. public static BitmapImage ToBitmapImage(this Bitmap bitmap)
  318. {
  319. using (var memory = new MemoryStream())
  320. {
  321. bitmap.Save(memory, ImageFormat.Png);
  322. memory.Position = 0;
  323. var bitmapImage = new BitmapImage();
  324. bitmapImage.BeginInit();
  325. bitmapImage.StreamSource = memory;
  326. bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
  327. bitmapImage.EndInit();
  328. bitmapImage.Freeze();
  329. return bitmapImage;
  330. }
  331. }
  332. /// <summary>
  333. /// Load an image from image data; this will return <see langword="null"/> if <paramref name="imageData"/> is <see langword="null"/> or empty.
  334. /// </summary>
  335. /// <param name="imageData"></param>
  336. /// <returns></returns>
  337. public static BitmapImage? LoadImage(byte[]? imageData)
  338. {
  339. if(imageData is null || imageData.Length == 0)
  340. {
  341. return null;
  342. }
  343. var result = new BitmapImage();
  344. result.LoadImage(imageData);
  345. return result;
  346. }
  347. private static void LoadImage(this BitmapImage image, byte[] imageData)
  348. {
  349. using (var mem = new MemoryStream(imageData))
  350. {
  351. mem.Position = 0;
  352. image.BeginInit();
  353. image.CreateOptions = BitmapCreateOptions.PreservePixelFormat;
  354. image.CacheOption = BitmapCacheOption.OnLoad;
  355. image.UriSource = null;
  356. image.StreamSource = mem;
  357. image.EndInit();
  358. }
  359. image.Freeze();
  360. }
  361. public static Bitmap? MergeBitmaps(IEnumerable<Bitmap> bitmaps, int padding)
  362. {
  363. if (!bitmaps.Any())
  364. return null;
  365. var totalwidth = bitmaps.Aggregate(0, (total, next) => total + next.Width + (total > 0 ? padding : 0) );
  366. var maxheight = bitmaps.Aggregate(0, (max, next) => Math.Max(next.Height,max) );
  367. Bitmap result = new Bitmap(totalwidth, maxheight);
  368. using (Graphics g = Graphics.FromImage(result))
  369. {
  370. g.Clear(Color.Transparent);
  371. int left = 0;
  372. foreach (var bitmap in bitmaps)
  373. {
  374. g.DrawImage(bitmap, left, 0);
  375. left += bitmap.Width + padding;
  376. }
  377. }
  378. return result;
  379. }
  380. public static byte[] ToArray<T>(this BitmapImage image) where T : BitmapEncoder, new()
  381. {
  382. byte[] data;
  383. var encoder = new T();
  384. encoder.Frames.Add(BitmapFrame.Create(image));
  385. using (var ms = new MemoryStream())
  386. {
  387. encoder.Save(ms);
  388. data = ms.ToArray();
  389. }
  390. return data;
  391. }
  392. public static BitmapImage Resize(this BitmapImage image, int height, int width)
  393. {
  394. var buffer = image.ToArray<BmpBitmapEncoder>();
  395. var ms = new MemoryStream(buffer);
  396. var result = new BitmapImage();
  397. result.BeginInit();
  398. result.CacheOption = BitmapCacheOption.None;
  399. result.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
  400. result.DecodePixelWidth = width;
  401. result.DecodePixelHeight = height;
  402. result.StreamSource = ms;
  403. result.Rotation = Rotation.Rotate0;
  404. result.EndInit();
  405. buffer = null;
  406. return result;
  407. }
  408. public static Bitmap Resize(this Bitmap bitmap, int width, int height)
  409. {
  410. if ((width == bitmap.Width) && (height == bitmap.Height))
  411. return bitmap;
  412. return new Bitmap(bitmap,new Size(width,height));
  413. }
  414. public static BitmapImage Scale(this BitmapImage image, int maxheight, int maxwidth)
  415. {
  416. var scaleHeight = maxheight / (float)image.Height;
  417. var scaleWidth = maxwidth / (float)image.Width;
  418. var scale = Math.Min(scaleHeight, scaleWidth);
  419. return image.Resize((int)(image.Height * scale), (int)(image.Width * scale));
  420. }
  421. public static Bitmap BitmapFromColor(Color color, int width, int height, Color frame)
  422. {
  423. var result = new Bitmap(width, height);
  424. var g = Graphics.FromImage(result);
  425. g.Clear(color);
  426. if (frame != Color.Transparent)
  427. g.DrawRectangle(new Pen(new SolidBrush(frame), 1), new Rectangle(0, 0, width-1, height-1));
  428. return result;
  429. }
  430. public static Bitmap BitmapFromColor(System.Windows.Media.Color color, int width, int height, System.Windows.Media.Color frame)
  431. {
  432. var result = new Bitmap(width, height);
  433. var g = Graphics.FromImage(result);
  434. g.Clear(Color.FromArgb(color.A,color.R,color.G,color.B));
  435. if (frame != Colors.Transparent)
  436. g.DrawRectangle(new Pen(new SolidBrush(Color.FromArgb(frame.A,frame.R,frame.G,frame.B)), 1F), new Rectangle(0, 0, width-1, height-1));
  437. return result;
  438. }
  439. public static Color MixColors(this Color color1, double factor, Color color2)
  440. {
  441. if (factor < 0) throw new Exception($"Factor {factor} must be >= 0.");
  442. if (factor > 1) throw new Exception($"Factor {factor} must be <= 1.");
  443. if (factor == 0) return color2;
  444. if (factor == 1) return color1;
  445. var factor1 = 1 - factor;
  446. return Color.FromArgb(
  447. (byte)(color1.A * factor + color2.A * factor1),
  448. (byte)(color1.R * factor + color2.R * factor1),
  449. (byte)(color1.G * factor + color2.G * factor1),
  450. (byte)(color1.B * factor + color2.B * factor1));
  451. }
  452. public static System.Windows.Media.Color MixColors(this System.Windows.Media.Color color1, double factor, System.Windows.Media.Color color2)
  453. {
  454. if (factor < 0) throw new Exception($"Factor {factor} must be >= 0.");
  455. if (factor > 1) throw new Exception($"Factor {factor} must be <= 1.");
  456. if (factor == 0) return color2;
  457. if (factor == 1) return color1;
  458. var factor1 = 1 - factor;
  459. return System.Windows.Media.Color.FromArgb(
  460. (byte)(color1.A * factor + color2.A * factor1),
  461. (byte)(color1.R * factor + color2.R * factor1),
  462. (byte)(color1.G * factor + color2.G * factor1),
  463. (byte)(color1.B * factor + color2.B * factor1));
  464. }
  465. public static string ColorToString(Color color)
  466. {
  467. return string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}",
  468. color.A,
  469. color.R,
  470. color.G,
  471. color.B
  472. );
  473. }
  474. public static Color StringToColor(string colorcode)
  475. {
  476. var col = Color.Transparent;
  477. if (!string.IsNullOrEmpty(colorcode))
  478. {
  479. var code = colorcode.Replace("#", "");
  480. if (code.Length == 6)
  481. col = Color.FromArgb(255,
  482. byte.Parse(code.Substring(0, 2), NumberStyles.HexNumber),
  483. byte.Parse(code.Substring(2, 2), NumberStyles.HexNumber),
  484. byte.Parse(code.Substring(4, 2), NumberStyles.HexNumber));
  485. else if (code.Length == 8)
  486. col = Color.FromArgb(
  487. byte.Parse(code.Substring(0, 2), NumberStyles.HexNumber),
  488. byte.Parse(code.Substring(2, 2), NumberStyles.HexNumber),
  489. byte.Parse(code.Substring(4, 2), NumberStyles.HexNumber),
  490. byte.Parse(code.Substring(6, 2), NumberStyles.HexNumber));
  491. }
  492. return col;
  493. }
  494. public static System.Windows.Media.Color StringToMediaColor(string colorcode)
  495. {
  496. var col = Colors.Transparent;
  497. if (!string.IsNullOrEmpty(colorcode))
  498. {
  499. var code = colorcode.Replace("#", "");
  500. if (code.Length == 6)
  501. col = System.Windows.Media.Color.FromArgb(255,
  502. byte.Parse(code.Substring(0, 2), NumberStyles.HexNumber),
  503. byte.Parse(code.Substring(2, 2), NumberStyles.HexNumber),
  504. byte.Parse(code.Substring(4, 2), NumberStyles.HexNumber));
  505. else if (code.Length == 8)
  506. col = System.Windows.Media.Color.FromArgb(
  507. byte.Parse(code.Substring(0, 2), NumberStyles.HexNumber),
  508. byte.Parse(code.Substring(2, 2), NumberStyles.HexNumber),
  509. byte.Parse(code.Substring(4, 2), NumberStyles.HexNumber),
  510. byte.Parse(code.Substring(6, 2), NumberStyles.HexNumber));
  511. }
  512. return col;
  513. }
  514. /// <summary>
  515. /// Creates color with corrected brightness.
  516. /// </summary>
  517. /// <param name="color">Color to correct.</param>
  518. /// <param name="correctionFactor">
  519. /// The brightness correction factor. Must be between -1 and 1.
  520. /// Negative values produce darker colors.
  521. /// </param>
  522. /// <returns>
  523. /// Corrected <see cref="Color" /> structure.
  524. /// </returns>
  525. public static System.Windows.Media.Color AdjustBrightness(this System.Windows.Media.Color color, float correctionFactor)
  526. {
  527. float red = color.R;
  528. float green = color.G;
  529. float blue = color.B;
  530. if (correctionFactor < 0)
  531. {
  532. correctionFactor = 1 + correctionFactor;
  533. red *= correctionFactor;
  534. green *= correctionFactor;
  535. blue *= correctionFactor;
  536. }
  537. else
  538. {
  539. red = (255 - red) * correctionFactor + red;
  540. green = (255 - green) * correctionFactor + green;
  541. blue = (255 - blue) * correctionFactor + blue;
  542. }
  543. return System.Windows.Media.Color.FromArgb(color.A, (byte)red, (byte)green, (byte)blue);
  544. }
  545. public static bool TryGetImageType(byte[] imageData, [NotNullWhen(true)] out ImageFormat? format)
  546. {
  547. foreach (var signatureEntry in SignatureTable)
  548. foreach (var signature in signatureEntry.Value)
  549. {
  550. var isMatch = true;
  551. for (var i = 0; i < signature.Length; i++)
  552. {
  553. var signatureByte = signature[i];
  554. // ToString("X") gets the hex representation and pads it to always be length 2
  555. var imageByte = imageData[i]
  556. .ToString("X2");
  557. if (signatureByte == imageByte)
  558. continue;
  559. isMatch = false;
  560. break;
  561. }
  562. if (isMatch)
  563. {
  564. format = signatureEntry.Key;
  565. return true;
  566. }
  567. }
  568. format = null;
  569. return false;
  570. }
  571. /// <summary>
  572. /// Takes a byte array and determines the image file type by
  573. /// comparing the first few bytes of the file to a list of known
  574. /// image file signatures.
  575. /// </summary>
  576. /// <param name="imageData">Byte array of the image data</param>
  577. /// <returns>ImageFormat corresponding to the image file format</returns>
  578. /// <exception cref="ArgumentException">Thrown if the image type can't be determined</exception>
  579. public static ImageFormat GetImageType(byte[] imageData)
  580. {
  581. if(TryGetImageType(imageData, out var format))
  582. {
  583. return format;
  584. }
  585. throw new ArgumentException("The byte array did not match any known image file signatures.");
  586. }
  587. public static System.Drawing.Bitmap Invert(this System.Drawing.Bitmap source)
  588. {
  589. Bitmap bmpDest = new Bitmap(source.Width,source.Height);
  590. ColorMatrix clrMatrix = new ColorMatrix(new float[][]
  591. {
  592. new float[] {-1, 0, 0, 0, 0},
  593. new float[] {0, -1, 0, 0, 0},
  594. new float[] {0, 0, -1, 0, 0},
  595. new float[] {0, 0, 0, 1, 0},
  596. new float[] {1, 1, 1, 0, 1}
  597. });
  598. using (ImageAttributes attrImage = new ImageAttributes())
  599. {
  600. attrImage.SetColorMatrix(clrMatrix);
  601. using (Graphics g = Graphics.FromImage(bmpDest))
  602. {
  603. g.DrawImage(source, new Rectangle(0, 0,
  604. source.Width, source.Height), 0, 0,
  605. source.Width, source.Height, GraphicsUnit.Pixel,
  606. attrImage);
  607. }
  608. }
  609. return bmpDest;
  610. }
  611. public static Font AdjustSize(this Font font, Graphics graphics, string text, int width)
  612. {
  613. Font result = null;
  614. for (int size = (int)font.Size; size > 0; size--)
  615. {
  616. result = new Font(font.Name, size, font.Style);
  617. SizeF adjustedSizeNew = graphics.MeasureString(text, result);
  618. if (width > Convert.ToInt32(adjustedSizeNew.Width))
  619. return result;
  620. }
  621. return result;
  622. }
  623. public static Bitmap WatermarkImage(this Bitmap image, String text, System.Windows.Media.Color color, int maxfontsize = 0)
  624. {
  625. return image.WatermarkImage(text, Color.FromArgb(color.A, color.R, color.G, color.B),maxfontsize);
  626. }
  627. public static Bitmap WatermarkImage(this Bitmap image, String text, Color color, int maxfontsize = 0)
  628. {
  629. int w = image.Width;
  630. int h = image.Height;
  631. Bitmap result = new System.Drawing.Bitmap(w, h);
  632. Graphics graphics = System.Drawing.Graphics.FromImage((System.Drawing.Image)result);
  633. graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
  634. graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
  635. graphics.Clear(System.Drawing.Color.Transparent);
  636. graphics.DrawImage(image, 0, 0, w, h);
  637. Font drawFont = new System.Drawing.Font("Arial", 96).AdjustSize(graphics,text,(int)(image.Width * 0.9F));
  638. if ((maxfontsize > 0) && (drawFont.Size > maxfontsize))
  639. drawFont = new System.Drawing.Font("Arial", maxfontsize);
  640. SolidBrush drawBrush = new System.Drawing.SolidBrush(color);
  641. StringFormat stringFormat = new StringFormat();
  642. stringFormat.Alignment = StringAlignment.Center;
  643. stringFormat.LineAlignment = StringAlignment.Center;
  644. graphics.DrawString(text, drawFont, drawBrush, new Rectangle(0,0,w,h), stringFormat);
  645. graphics.Dispose();
  646. return result;
  647. }
  648. private static System.Windows.Media.Color AdjustColor(System.Windows.Media.Color color, Action<HSL> action)
  649. {
  650. var hsl = ColorHelper.ColorConverter.RgbToHsl(new RGB(color.R,color.G,color.B));
  651. action(hsl);
  652. var rgb = ColorHelper.ColorConverter.HslToRgb(hsl);
  653. return System.Windows.Media.Color.FromArgb(color.A, rgb.R, rgb.G, rgb.B);
  654. }
  655. private static int AdjustPercentage(int original, int percentage)
  656. {
  657. int percent = Math.Min(100, Math.Max(-100, percentage));
  658. int newvalue = (percent < 0)
  659. ? (byte)((percent * original) / 100)
  660. : (byte)((percent * (100 - original)) / 100);
  661. return original + newvalue;
  662. }
  663. public static System.Windows.Media.Color AdjustHue(this System.Windows.Media.Color color, int degrees) =>
  664. AdjustColor(color, (hsl => hsl.H += degrees));
  665. public static System.Windows.Media.Color AdjustSaturation(this System.Windows.Media.Color color, int percentage) =>
  666. AdjustColor(color, (hsl =>
  667. {
  668. hsl.S = (byte)AdjustPercentage(hsl.S, percentage);
  669. }));
  670. public static System.Windows.Media.Color SetSaturation(this System.Windows.Media.Color color, int percentage) =>
  671. AdjustColor(color, (hsl => hsl.S = (byte)percentage));
  672. public static System.Windows.Media.Color AdjustLightness(this System.Windows.Media.Color color, int percentage) =>
  673. AdjustColor(color, (hsl =>
  674. {
  675. hsl.L = (byte)AdjustPercentage(hsl.L, percentage);
  676. }));
  677. public static System.Windows.Media.Color SetLightness(this System.Windows.Media.Color color, int percentage) =>
  678. AdjustColor(color, (hsl => hsl.L = (byte)percentage));
  679. public static System.Windows.Media.Color SetAlpha(this System.Windows.Media.Color color, byte alpha) =>
  680. System.Windows.Media.Color.FromArgb(alpha, color.R, color.G, color.B);
  681. public static HSL ToHSL(this System.Windows.Media.Color color)
  682. {
  683. return ColorHelper.ColorConverter.RgbToHsl(new RGB(color.R, color.G, color.B));
  684. }
  685. public static System.Windows.Media.Color ToColor(this HSL hsl)
  686. {
  687. var rgb = ColorHelper.ColorConverter.HslToRgb(hsl);
  688. return System.Windows.Media.Color.FromRgb(rgb.R, rgb.G, rgb.B);
  689. }
  690. public static HSL ToHSL(this System.Drawing.Color color)
  691. {
  692. return ColorHelper.ColorConverter.RgbToHsl(new RGB(color.R, color.G, color.B));
  693. }
  694. public static System.Windows.Media.Color GetForegroundColor(this System.Windows.Media.Color c, int threshold = 130)
  695. {
  696. var perceivedbrightness = (int)Math.Sqrt(
  697. c.R * c.R * .299 +
  698. c.G * c.G * .587 +
  699. c.B * c.B * .114);
  700. return perceivedbrightness >= threshold ? Colors.Black : Colors.White;
  701. }
  702. public static uint ToUint(this System.Drawing.Color color) => (uint)((color.A << 24) | (color.R << 16) | (color.G << 8) | (color.B << 0));
  703. public static uint ToUint(this System.Windows.Media.Color color) => (uint)((color.A << 24) | (color.R << 16) | (color.G << 8) | (color.B << 0));
  704. public enum ImageEncoding
  705. {
  706. JPEG
  707. }
  708. public static ImageCodecInfo? GetEncoder(ImageFormat format)
  709. {
  710. ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();
  711. foreach (ImageCodecInfo codec in codecs)
  712. {
  713. if (codec.FormatID == format.Guid)
  714. {
  715. return codec;
  716. }
  717. }
  718. return null;
  719. }
  720. public static byte[] GetPDFThumbnail(byte[] pdfData, int width, int height)
  721. {
  722. PdfLoadedDocument loadeddoc = new PdfLoadedDocument(pdfData);
  723. Bitmap image = loadeddoc.ExportAsImage(0, new SizeF(width, height), true);
  724. MemoryStream stream = new MemoryStream();
  725. image.Save(stream, ImageFormat.Jpeg);
  726. return stream.ToArray();
  727. }
  728. [System.Runtime.InteropServices.DllImport("gdi32.dll")]
  729. public static extern bool DeleteObject(IntPtr hObject);
  730. public static List<ImageSource> RenderPDFToImageSources(byte[] pdfData, ImageEncoding encoding = ImageEncoding.JPEG)
  731. {
  732. using var profiler = new Profiler(true);
  733. var rendered = new List<ImageSource>();
  734. var loadeddoc = new PdfLoadedDocument(pdfData);
  735. loadeddoc.FlattenAnnotations();
  736. var images = loadeddoc.ExportAsImage(0, loadeddoc.Pages.Count - 1);
  737. if (images != null)
  738. foreach (var image in images)
  739. {
  740. var hBitmap = image.GetHbitmap();
  741. try
  742. {
  743. var source = (ImageSource)Imaging.CreateBitmapSourceFromHBitmap(
  744. hBitmap,
  745. IntPtr.Zero,
  746. Int32Rect.Empty,
  747. BitmapSizeOptions.FromEmptyOptions());
  748. source.Freeze();
  749. rendered.Add(source);
  750. }
  751. finally
  752. {
  753. DeleteObject(hBitmap);
  754. }
  755. }
  756. return rendered;
  757. }
  758. public static List<byte[]> RenderPDFToImageBytes(byte[] pdfData, ImageEncoding encoding = ImageEncoding.JPEG)
  759. {
  760. var rendered = new List<byte[]>();
  761. PdfLoadedDocument loadeddoc = new PdfLoadedDocument(pdfData);
  762. loadeddoc.FlattenAnnotations();
  763. Bitmap[] images = loadeddoc.ExportAsImage(0, loadeddoc.Pages.Count - 1);
  764. var jpgEncoder = GetEncoder(ImageFormat.Jpeg)!;
  765. var quality = Encoder.Quality;
  766. var encodeParams = new EncoderParameters(1);
  767. encodeParams.Param[0] = new EncoderParameter(quality, 100L);
  768. if (images != null)
  769. foreach (var image in images)
  770. {
  771. using (var data = new MemoryStream())
  772. {
  773. image.Save(data, jpgEncoder, encodeParams);
  774. rendered.Add(data.ToArray());
  775. }
  776. }
  777. return rendered;
  778. }
  779. public static List<byte[]> RenderTextFileToImages(string textData)
  780. {
  781. var pdfDocument = new PdfDocument();
  782. var page = pdfDocument.Pages.Add();
  783. var font = new PdfStandardFont(PdfFontFamily.Courier, 14);
  784. var textElement = new PdfTextElement(textData, font);
  785. var layoutFormat = new PdfLayoutFormat
  786. {
  787. Layout = PdfLayoutType.Paginate,
  788. Break = PdfLayoutBreakType.FitPage
  789. };
  790. textElement.Draw(page, new RectangleF(0, 0, page.GetClientSize().Width, page.GetClientSize().Height), layoutFormat);
  791. using var docStream = new MemoryStream();
  792. pdfDocument.Save(docStream);
  793. var loadeddoc = new PdfLoadedDocument(docStream.ToArray());
  794. Bitmap[] bmpImages = loadeddoc.ExportAsImage(0, loadeddoc.Pages.Count - 1);
  795. var jpgEncoder = GetEncoder(ImageFormat.Jpeg)!;
  796. var quality = Encoder.Quality;
  797. var encodeParams = new EncoderParameters(1);
  798. encodeParams.Param[0] = new EncoderParameter(quality, 100L);
  799. var images = new List<byte[]>();
  800. if (bmpImages != null)
  801. foreach (var image in bmpImages)
  802. {
  803. using var data = new MemoryStream();
  804. image.Save(data, jpgEncoder, encodeParams);
  805. images.Add(data.ToArray());
  806. }
  807. return images;
  808. }
  809. public static ContentControl CreatePreviewWindowButtonContent(string caption, Bitmap bitmap)
  810. {
  811. Frame frame = new Frame();
  812. frame.Padding = new Thickness(0);
  813. frame.Margin = new Thickness(10, 10, 10, 5);
  814. Grid grid = new Grid();
  815. grid.Margin = new Thickness(0);
  816. grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
  817. grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
  818. var img = new System.Windows.Controls.Image
  819. {
  820. Source = bitmap.AsBitmapImage(),
  821. Height = 32.0F,
  822. Width = 32.0F,
  823. Margin = new Thickness(10)
  824. };
  825. img.SetValue(Grid.RowProperty, 0);
  826. img.Margin = new Thickness(0);
  827. grid.Children.Add(img);
  828. var txt = new System.Windows.Controls.TextBox();
  829. txt.IsEnabled = false;
  830. txt.Text = caption;
  831. txt.BorderThickness = new Thickness(0);
  832. txt.TextWrapping = TextWrapping.WrapWithOverflow;
  833. txt.MaxWidth = 90;
  834. txt.HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center;
  835. txt.SetValue(Grid.RowProperty, 1);
  836. grid.Children.Add(txt);
  837. frame.Content = grid;
  838. return frame;
  839. }
  840. public static String AsExtension(this ImageFormat format)
  841. {
  842. if (format.Equals(ImageFormat.Bmp) || format.Equals(ImageFormat.MemoryBmp))
  843. return "bmp";
  844. if (format.Equals(ImageFormat.Emf))
  845. return "emf";
  846. if (format.Equals(ImageFormat.Wmf))
  847. return "wmf";
  848. if (format.Equals(ImageFormat.Gif))
  849. return "gif";
  850. if (format.Equals(ImageFormat.Jpeg))
  851. return "jpeg";
  852. if (format.Equals(ImageFormat.Png))
  853. return "png";
  854. if (format.Equals(ImageFormat.Tiff))
  855. return "tiff";
  856. if (format.Equals(ImageFormat.Exif))
  857. return "exif";
  858. if (format.Equals(ImageFormat.Icon))
  859. return "ico";
  860. return "";
  861. }
  862. public static bool IsEqual(this BitmapImage? image1, BitmapImage? image2)
  863. {
  864. if (image1 == null || image2 == null)
  865. return false;
  866. return image1.ToBytes().SequenceEqual(image2.ToBytes());
  867. }
  868. public static byte[] ToBytes(this BitmapImage image)
  869. {
  870. byte[] data = new byte[] { };
  871. if (image != null)
  872. {
  873. try
  874. {
  875. var encoder = new BmpBitmapEncoder();
  876. encoder.Frames.Add(BitmapFrame.Create(image));
  877. using (MemoryStream ms = new MemoryStream())
  878. {
  879. encoder.Save(ms);
  880. data = ms.ToArray();
  881. }
  882. return data;
  883. }
  884. catch (Exception ex)
  885. {
  886. }
  887. }
  888. return data;
  889. }
  890. }
  891. }