فهرست منبع

Added automated caching mechanism for Shared Image API #1156

Marcin Ziąbek 9 ماه پیش
والد
کامیت
9e701542ff

+ 0 - 1
Source/QuestPDF/Fluent/ImageExtensions.cs

@@ -149,7 +149,6 @@ namespace QuestPDF.Fluent
         public static ImageDescriptor Image(this IContainer parent, string filePath)
         {
             var image = Infrastructure.Image.FromFile(filePath);
-            image.IsShared = false;
             return parent.Image(image);
         }
         

+ 3 - 27
Source/QuestPDF/Infrastructure/Image.cs

@@ -83,7 +83,7 @@ namespace QuestPDF.Infrastructure
         public static Image FromBinaryData(byte[] imageBytes)
         {
             using var imageData = SkData.FromBinary(imageBytes);
-            return DecodeImage(imageData);
+            return StaticImageCache.DecodeImage(imageData);
         }
 
         /// <summary>
@@ -93,18 +93,7 @@ namespace QuestPDF.Infrastructure
         /// <include file='../Resources/Documentation.xml' path='documentation/doc[@for="image.remarks"]/*' />
         public static Image FromFile(string filePath)
         {
-            if (!File.Exists(filePath))
-            {
-                var fallbackPath = Path.Combine(Helpers.Helpers.ApplicationFilesPath, filePath);
-                
-                if (!File.Exists(fallbackPath))
-                    throw new DocumentComposeException($"Cannot load provided image, file not found: ${filePath}");
-                
-                filePath = fallbackPath;
-            }
-            
-            using var imageData = SkData.FromFile(filePath);
-            return DecodeImage(imageData);
+            return StaticImageCache.Load(filePath);
         }
 
         /// <summary>
@@ -115,20 +104,7 @@ namespace QuestPDF.Infrastructure
         public static Image FromStream(Stream stream)
         {
             using var imageData = SkData.FromStream(stream);
-            return DecodeImage(imageData);
-        }
-        
-        private static Image DecodeImage(SkData imageData)
-        {
-            try
-            {
-                var image = SkImage.FromData(imageData);
-                return new Image(image);
-            }
-            catch
-            {
-                throw new DocumentComposeException("Cannot decode the provided image.");
-            }
+            return StaticImageCache.DecodeImage(imageData);
         }
 
         #endregion

+ 86 - 0
Source/QuestPDF/Infrastructure/StaticImageCache.cs

@@ -0,0 +1,86 @@
+using System.Collections.Concurrent;
+using System.IO;
+using System.Linq;
+using QuestPDF.Drawing.Exceptions;
+using QuestPDF.Skia;
+
+namespace QuestPDF.Infrastructure;
+
+static class StaticImageCache
+{
+    private static bool CacheIsEnabled { get; set; } = true;
+    private static ConcurrentDictionary<string, Image> Items { get; set; } = new();
+
+    private const int MaxCacheSize = 25_000_000;
+    private const int MaxItemSize = 1_000_000;
+    
+    public static Image Load(string filePath)
+    {
+        var isPathRooted = Path.IsPathRooted(filePath);
+        
+        // check fallback path
+        if (!File.Exists(filePath))
+        {
+            var fallbackPath = Path.Combine(Helpers.Helpers.ApplicationFilesPath, filePath);
+
+            if (!File.Exists(fallbackPath))
+                throw new DocumentComposeException($"Cannot load provided image, file not found: {filePath}");   
+
+            filePath = fallbackPath;
+        }
+        
+        if (isPathRooted)
+            return LoadImage(filePath, false);
+        
+        
+        // check file size
+        var fileInfo = new FileInfo(filePath);
+        
+        if (fileInfo.Length > MaxItemSize)
+            return LoadImage(filePath, false);
+
+        
+        // check if the image is already in cache
+        if (Items.TryGetValue(filePath, out var cacheItem))
+            return cacheItem;
+        
+        
+        // if cache is larger than expected, the usage might be different from loading static images
+        if (!CacheIsEnabled)
+            return LoadImage(filePath, false);
+        
+        
+        // create new cache item and add it to the cache
+        var image = LoadImage(filePath, true);
+        Items.TryAdd(filePath, image);
+        
+        
+        // check cache size
+        CacheIsEnabled = Items.Values.Sum(x => x.SkImage.EncodedDataSize) < MaxCacheSize;
+        
+        
+        // return cached value
+        return image;
+    }
+    
+    private static Image LoadImage(string filePath, bool isShared)
+    {
+        using var imageData = SkData.FromFile(filePath);
+        var image = DecodeImage(imageData);
+        image.IsShared = isShared;
+        return image;
+    }
+    
+    public static Image DecodeImage(SkData imageData)
+    {
+        try
+        {
+            var image = SkImage.FromData(imageData);
+            return new Image(image);
+        }
+        catch
+        {
+            throw new DocumentComposeException("Cannot decode the provided image.");
+        }
+    }
+}