StaticImageCache.cs 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. using System.Collections.Concurrent;
  2. using System.IO;
  3. using System.Linq;
  4. using QuestPDF.Drawing.Exceptions;
  5. using QuestPDF.Skia;
  6. namespace QuestPDF.Infrastructure;
  7. static class StaticImageCache
  8. {
  9. private static bool CacheIsEnabled { get; set; } = true;
  10. private static ConcurrentDictionary<string, Image> Items { get; set; } = new();
  11. private const int MaxCacheSize = 25_000_000;
  12. private const int MaxItemSize = 1_000_000;
  13. public static Image Load(string filePath)
  14. {
  15. var isPathRooted = Path.IsPathRooted(filePath);
  16. // check fallback path
  17. if (!File.Exists(filePath))
  18. {
  19. var fallbackPath = Path.Combine(Helpers.Helpers.ApplicationFilesPath, filePath);
  20. if (!File.Exists(fallbackPath))
  21. throw new DocumentComposeException($"Cannot load provided image, file not found: {filePath}");
  22. filePath = fallbackPath;
  23. }
  24. if (isPathRooted)
  25. return LoadImage(filePath, false);
  26. // check file size
  27. var fileInfo = new FileInfo(filePath);
  28. if (fileInfo.Length > MaxItemSize)
  29. return LoadImage(filePath, false);
  30. // check if the image is already in cache
  31. if (Items.TryGetValue(filePath, out var cacheItem))
  32. return cacheItem;
  33. // if cache is larger than expected, the usage might be different from loading static images
  34. if (!CacheIsEnabled)
  35. return LoadImage(filePath, false);
  36. // create new cache item and add it to the cache
  37. var image = LoadImage(filePath, true);
  38. Items.TryAdd(filePath, image);
  39. // check cache size
  40. CacheIsEnabled = Items.Values.Sum(x => x.SkImage.EncodedDataSize) < MaxCacheSize;
  41. // return cached value
  42. return image;
  43. }
  44. private static Image LoadImage(string filePath, bool isShared)
  45. {
  46. using var imageData = SkData.FromFile(filePath);
  47. return DecodeImage(imageData, isShared);
  48. }
  49. public static Image DecodeImage(SkData imageData, bool isShared)
  50. {
  51. try
  52. {
  53. var skImage = SkImage.FromData(imageData);
  54. var image = new Image(skImage);
  55. image.IsShared = isShared;
  56. return image;
  57. }
  58. catch
  59. {
  60. throw new DocumentComposeException("Cannot decode the provided image.");
  61. }
  62. }
  63. }