Browse Source

WriteOnlyStream refactorization

Marcin Ziąbek 3 years ago
parent
commit
946fe91a98

+ 4 - 2
QuestPDF/Drawing/DocumentGenerator.cs

@@ -18,14 +18,16 @@ namespace QuestPDF.Drawing
         internal static void GeneratePdf(Stream stream, IDocument document)
         internal static void GeneratePdf(Stream stream, IDocument document)
         {
         {
             var metadata = document.GetMetadata();
             var metadata = document.GetMetadata();
-            var canvas = new PdfCanvas(stream, metadata);
+            var writeOnlyStream = new WriteOnlyStream(stream);
+            var canvas = new PdfCanvas(writeOnlyStream, metadata);
             RenderDocument(canvas, document);
             RenderDocument(canvas, document);
         }
         }
         
         
         internal static void GenerateXps(Stream stream, IDocument document)
         internal static void GenerateXps(Stream stream, IDocument document)
         {
         {
             var metadata = document.GetMetadata();
             var metadata = document.GetMetadata();
-            var canvas = new XpsCanvas(stream, metadata);
+            var writeOnlyStream = new WriteOnlyStream(stream);
+            var canvas = new XpsCanvas(writeOnlyStream, metadata);
             RenderDocument(canvas, document);
             RenderDocument(canvas, document);
         }
         }
         
         

+ 1 - 1
QuestPDF/Drawing/PdfCanvas.cs

@@ -7,7 +7,7 @@ namespace QuestPDF.Drawing
     internal class PdfCanvas : SkiaDocumentCanvasBase
     internal class PdfCanvas : SkiaDocumentCanvasBase
     {
     {
         public PdfCanvas(Stream stream, DocumentMetadata documentMetadata) 
         public PdfCanvas(Stream stream, DocumentMetadata documentMetadata) 
-            : base(SKDocument.CreatePdf(new WriteStreamWrapper(stream), MapMetadata(documentMetadata)))
+            : base(SKDocument.CreatePdf(stream, MapMetadata(documentMetadata)))
         {
         {
             
             
         }
         }

+ 1 - 1
QuestPDF/Drawing/XpsCanvas.cs

@@ -7,7 +7,7 @@ namespace QuestPDF.Drawing
     internal class XpsCanvas : SkiaDocumentCanvasBase
     internal class XpsCanvas : SkiaDocumentCanvasBase
     {
     {
         public XpsCanvas(Stream stream, DocumentMetadata documentMetadata) 
         public XpsCanvas(Stream stream, DocumentMetadata documentMetadata) 
-            : base(SKDocument.CreateXps(new WriteStreamWrapper(stream), documentMetadata.RasterDpi))
+            : base(SKDocument.CreateXps(stream, documentMetadata.RasterDpi))
         {
         {
             
             
         }
         }

+ 56 - 0
QuestPDF/Helpers/WriteOnlyStream.cs

@@ -0,0 +1,56 @@
+using System;
+using System.IO;
+
+namespace QuestPDF.Helpers
+{
+    /// <summary>
+    /// SkiaSharp calls the Position property when generating target document file.
+    /// If the output stream does not support the Position property, the NullReferenceException is thrown.
+    /// This wrapper fixes this issue by providing cached Position value (always the end of the stream / current length).
+    /// Example stream affected: HttpContext.Response.Body
+    /// </summary>
+    internal class WriteOnlyStream : Stream
+    {
+        private readonly Stream InnerStream;
+        private long StreamLength { get; set; }
+
+        public WriteOnlyStream(Stream stream)
+        {            
+            if (!stream.CanWrite)
+                throw new NotSupportedException("Stream cannot be written");
+
+            InnerStream = stream;
+        }
+
+        public override bool CanRead => false;
+
+        public override bool CanSeek => false;
+
+        public override bool CanWrite => true;
+
+        public override long Length => StreamLength;
+
+        public override long Position
+        { 
+            get => StreamLength; 
+            set => throw new NotImplementedException(); 
+        }
+
+        public override void Flush() => InnerStream.Flush();
+
+        public override int Read(byte[] buffer, int offset, int count) 
+            => throw new NotImplementedException();
+
+        public override long Seek(long offset, SeekOrigin origin) 
+            => throw new NotImplementedException();
+
+        public override void SetLength(long value) 
+            => throw new NotImplementedException();
+
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            InnerStream.Write(buffer, offset, count);
+            StreamLength += count;
+        }
+    }
+}

+ 0 - 53
QuestPDF/Helpers/WriteStreamWrapper.cs

@@ -1,53 +0,0 @@
-using System;
-using System.IO;
-
-namespace QuestPDF.Helpers
-{
-    internal class WriteStreamWrapper : Stream
-    {
-        private readonly Stream _innerStream;
-
-        private long _length;
-
-        public WriteStreamWrapper(Stream stream)
-        {            
-            if (!stream.CanWrite)
-            {
-                throw new NotSupportedException("Stream cannot be written");
-            }
-
-            _innerStream = stream;
-        }
-
-        public override bool CanRead => false;
-
-        public override bool CanSeek => false;
-
-        public override bool CanWrite => true;
-
-        public override long Length => _length;
-
-        public override long Position { 
-            get => _length; 
-            set => throw new NotImplementedException(); 
-        }
-
-        public override void Flush() 
-            => _innerStream.Flush();
-
-        public override int Read(byte[] buffer, int offset, int count) 
-            => throw new NotImplementedException();
-
-        public override long Seek(long offset, SeekOrigin origin) 
-            => throw new NotImplementedException();
-
-        public override void SetLength(long value) 
-            => throw new NotImplementedException();
-
-        public override void Write(byte[] buffer, int offset, int count)
-        {
-            _innerStream.Write(buffer, offset, count);
-            _length += count;
-        }
-    }
-}