فهرست منبع

Added support for lazily loading images into memory

Vicente Penades 2 سال پیش
والد
کامیت
3fd1ea9eac
3فایلهای تغییر یافته به همراه47 افزوده شده و 27 حذف شده
  1. 36 20
      src/SharpGLTF.Core/Memory/MemoryImage.cs
  2. 7 5
      src/SharpGLTF.Core/Schema2/gltf.Images.cs
  3. 4 2
      src/SharpGLTF.Core/Schema2/gltf.Root.cs

+ 36 - 20
src/SharpGLTF.Core/Memory/MemoryImage.cs

@@ -2,7 +2,9 @@
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
+
 using BYTES = System.ArraySegment<System.Byte>;
+using LAZYBYTES = System.Lazy<System.ArraySegment<System.Byte>>;
 
 namespace SharpGLTF.Memory
 {
@@ -103,27 +105,20 @@ namespace SharpGLTF.Memory
             return true;
         }
 
-        public MemoryImage(BYTES image)
-        {
-            Guard.IsTrue(_IsImage(image), nameof(image), GuardError_MustBeValidImage);
-
-            _Image = image;
-            _SourcePathHint = null;
-        }
+        public MemoryImage(BYTES image) 
+            : this(_ToLazy(image), null) { }
 
         public MemoryImage(Byte[] image)
-        {
-            if (image != null) Guard.IsTrue(_IsImage(image), nameof(image), GuardError_MustBeValidImage);
+            : this(_ToLazy(image), null) { }
 
-            _Image = image == null ? default : new BYTES(image);
-            _SourcePathHint = null;
-        }
+        public MemoryImage(Func<BYTES> factory)
+            : this(new LAZYBYTES(factory), null) { }
 
         public MemoryImage(string filePath)
         {
             if (string.IsNullOrEmpty(filePath))
             {
-                _Image = default;
+                _LazyImage = _ToLazy(default(BYTES));
                 _SourcePathHint = null;
             }
             else
@@ -134,28 +129,49 @@ namespace SharpGLTF.Memory
 
                 Guard.IsTrue(_IsImage(data), nameof(filePath), GuardError_MustBeValidImage);
 
-                _Image = new BYTES(data);
+                _LazyImage = _ToLazy(data);
                 _SourcePathHint = filePath;
             }
-        }
+        }        
+
+        internal MemoryImage(Byte[] image, string filePath)
+            : this(_ToLazy(image), filePath) { }
 
         internal MemoryImage(BYTES image, string filePath)
-            : this(image)
+            : this(_ToLazy(image), filePath) { }
+
+        internal MemoryImage(MemoryImage image, string filePath)
         {
-            _SourcePathHint = filePath;
+            _LazyImage = image._LazyImage;
+            _SourcePathHint = filePath ?? image._SourcePathHint;
         }
 
-        internal MemoryImage(Byte[] image, string filePath)
-            : this(image)
+        internal MemoryImage(LAZYBYTES image, string filePath)
         {
+            _LazyImage = image;
             _SourcePathHint = filePath;
+        }        
+
+        private static LAZYBYTES _ToLazy(Byte[] bytes)
+        {
+            return _ToLazy(new BYTES(bytes));
+        }
+        private static LAZYBYTES _ToLazy(BYTES bytes)
+        {
+            #if NETSTANDARD2_0
+            return new LAZYBYTES(()=> bytes);
+            #else
+            return new LAZYBYTES(bytes);
+            #endif
         }
 
         #endregion
 
         #region data
 
-        private readonly BYTES _Image;
+        private readonly LAZYBYTES _LazyImage;
+
+        private BYTES _Image => _LazyImage == null ? default : _LazyImage.Value;
 
         /// <remarks>
         /// This field must NOT be used for equality checks, it has the same face value as a code comment.

+ 7 - 5
src/SharpGLTF.Core/Schema2/gltf.Images.cs

@@ -55,15 +55,17 @@ namespace SharpGLTF.Schema2
         }
 
         /// <summary>
-        /// When set to a FileName or a relative File Path, it will be used to write the texture.
+        /// When set to a FileName or a relative File Path,
+        /// it will be used as the file name of the texture being written.<br/>
+        /// When null, a default file name will be used.
         /// </summary>
-        /// <remarks>
+        /// <remarks>        
         /// <para>
-        /// When null, the default file name will be used.
+        /// if not sure about the image extension, using .* as extension will replace
+        /// the extension with the appropiate one at the time of writing.
         /// </para>
         /// <para>
-        /// if not sure about the image extension, using "name.*" as extension will replace
-        /// the extension with the appropiate one before writing.
+        /// For more advanced scenarios, you can also use: <see cref="WriteSettings.ImageWriteCallback"/>
         /// </para>
         /// </remarks>
         public String AlternateWriteFileName { get; set; }

+ 4 - 2
src/SharpGLTF.Core/Schema2/gltf.Root.cs

@@ -71,12 +71,14 @@ namespace SharpGLTF.Schema2
             rcontext.Validation = Validation.ValidationMode.Skip;
             var cloned = rcontext.ReadSchema2("$$$deepclone$$$.gltf");
 
-            // Restore MemoryImage source URIs (they're not cloned as part of the serialization)
+            // Restore MemoryImage's source URIs hints
+            // and Image's AlternateWriteFileName
+            // (they're not cloned as part of the serialization)
             foreach (var srcImg in this.LogicalImages)
             {
                 var dstImg = cloned.LogicalImages[srcImg.LogicalIndex];
                 var img = dstImg.Content;
-                dstImg.Content = new Memory.MemoryImage(img._GetBuffer(), srcImg.Content.SourcePath);
+                dstImg.Content = new Memory.MemoryImage(img, srcImg.Content.SourcePath);
                 dstImg.AlternateWriteFileName = srcImg.AlternateWriteFileName;
             }