Aspose.SVG for .NET 24.3.0 – Save an SVG to a Stream

Aspose.SVG for .NET 24.3.0

In version 24.3.0, the IOutputStorage interface and LocalFileSystemStorage class have been deprecated but will continue to work until version 24.6.0 is released. If you use earlier versions of Aspose.SVG for .NET, we recommend that you upgrade and migrate to the new version, as version 24.6.0 will remove these deprecated classes.

DeprecatedNew
IOutputStorage InterfaceResourceHandler Class
LocalFileSystemStorage ClassFileSystemResourceHandler Class

The SVG document can contain different resources like CSS, external images, and files. In the article, we will consider the cases for saving SVG documents with resources to Zip archive, memory stream, and local file system storage. Aspose.SVG for .NET continues to develop and enhance the ways to save SVGs with all linked files. Here we will look at examples of saving files using deprecated classes and offer advanced solutions for implementing new classes.

ResourceHandler Class Vs IOutputStorage Interface

The ResourceHandler class allows developers to implement the HandleResource() method, in which you can create a stream yourself and release it wherever you need it. The new method adds the ability to see a Resource and process more information about it. So, by adopting the ResourceHandler class, developers can benefit from a more streamlined and expressive approach to managing resources, resulting in cleaner, more maintainable, and flexible code when saving SVG documents.

Save SVG to a Zip Archive

Here, we will examine one and the same example of saving the with-resources.svg file in a Zip archive using an outdated IOutputStorage interface and a new ResourceHandler class.

Using IOutputStorage – 24.2.0 and Earlier Versions


The IOutputStorage interface was a base interface that supported the creation and management of output streams. You can implement the IOutputStorage interface by creating ZipStorage class to save SVG with resources to a Zip archive:

 1using System.IO;
 2using Aspose.Svg.IO;
 3using System.IO.Compression;
 4...
 5
 6	// Prepare a path to a source SVG file 
 7    string inputPath = Path.Combine(DataDir, "with-resources.svg");;
 8    
 9    var dir = Directory.GetCurrentDirectory();
10
11    // Prepare a full path to an output Zip storage
12    string customArchivePath = Path.Combine(dir, "./../../../../tests-out/old/archive.zip");
13
14    // Load the SVG document 
15    using (var doc = new SVGDocument(inputPath))
16    {
17        // Initialize an instance of the ZipStorage class
18        using (var zipSrorage = new ZipStorage(customArchivePath))
19        {
20            // Save SVG with resources to a Zip archive
21            doc.Save(zipSrorage);
22        }
23    }

The following code snippet shows the realization of the IOutputStorage in the ZipStorage class to demonstrate saving an SVG document with resources to a Zip archive.

 1    internal class ZipStorage : IOutputStorage, IDisposable
 2    {
 3        private FileStream zipStream;
 4        private ZipArchive archive;
 5        private int streamsCounter;
 6        private bool initialized;
 7
 8        public ZipStorage(string name)
 9        {
10            DisposeArchive();
11            zipStream = new FileStream(name, FileMode.Create);
12            archive = new ZipArchive(zipStream, ZipArchiveMode.Update);
13            initialized = false;
14        }
15
16        public OutputStream CreateStream(OutputStreamContext context)
17        {
18            var zipUri = (streamsCounter++ == 0 ? Path.GetFileName(context.Uri) :
19                Path.Combine(Path.GetFileName(Path.GetDirectoryName(context.Uri)), Path.GetFileName(context.Uri)));
20            var samplePrefix = String.Empty;
21            if (initialized)
22                samplePrefix = "my_";
23            else
24                initialized = true;
25
26            var newStream = archive.CreateEntry(samplePrefix + zipUri).Open();
27            var outputStream = new OutputStream(newStream, "file:///" + samplePrefix + zipUri);
28            return outputStream;
29        }
30
31        public void ReleaseStream(OutputStream stream)
32        {
33            stream.Flush();
34            stream.Close();
35        }
36
37        private void DisposeArchive()
38        {
39            if (archive != null)
40            {
41                archive.Dispose();
42                archive = null;
43            }
44            if (zipStream != null)
45            {
46                zipStream.Dispose();
47                zipStream = null;
48            }
49            streamsCounter = 0;
50        }
51
52        public void Dispose()
53        {
54            DisposeArchive();
55        }
56    }

Using new ResourceHandler class – Since Version 24.3.0


The ResourceHandler class is intended for customers implementation. The following C# example shows how to save an SVG document with resources to a Zip archive using the ZipResourceHandler class of the ResourceHandler:

 1using System.IO;
 2using Aspose.Svg.IO;
 3using System.IO.Compression;
 4...
 5
 6    // Prepare a path to a source SVG file 
 7    string inputPath = Path.Combine(DataDir, "with-resources.svg");
 8
 9    var dir = Directory.GetCurrentDirectory();
10
11    // Prepare a full path to an output Zip storage
12    string customArchivePath = Path.Combine(dir, "./../../../../tests-out/new/archive.zip");
13
14    // Load an SVG document 
15    using (var doc = new SVGDocument(inputPath))
16    {
17        // Initialize an instance of the ZipResourceHandler class
18        using (var resourceHandler = new ZipResourceHandler(customArchivePath))
19        {
20            // Save SVG with resources to a Zip archive
21            doc.Save(resourceHandler);
22        }
23    }

The following code snippet shows the realization of the ResourceHandler in the ZipResourceHandler class to demonstrate saving an SVG document with resources to a Zip archive. The HandleResource() method of the ZipResourceHandler class is responsible for handling each resource during the saving process when creating a Zip archive:

 1    internal class ZipResourceHandler : ResourceHandler, IDisposable
 2    {
 3        private FileStream zipStream;
 4        private ZipArchive archive;
 5        private int streamsCounter;
 6        private bool initialized;
 7
 8        public ZipResourceHandler(string name)
 9        {
10            DisposeArchive();
11            zipStream = new FileStream(name, FileMode.Create);
12            archive = new ZipArchive(zipStream, ZipArchiveMode.Update);
13            initialized = false;
14        }
15
16        public override void HandleResource(Resource resource, ResourceHandlingContext context)
17        {
18            var zipUri = (streamsCounter++ == 0
19                ? Path.GetFileName(resource.OriginalUrl.Href)
20                : Path.Combine(Path.GetFileName(Path.GetDirectoryName(resource.OriginalUrl.Href)),
21                    Path.GetFileName(resource.OriginalUrl.Href)));
22            var samplePrefix = String.Empty;
23            if (initialized)
24                samplePrefix = "my_";
25            else
26                initialized = true;
27
28            using (var newStream = archive.CreateEntry(samplePrefix + zipUri).Open())
29            {
30                resource.WithOutputUrl(new Url("file:///" + samplePrefix + zipUri)).Save(newStream, context);
31            }
32        }
33
34        private void DisposeArchive()
35        {
36            if (archive != null)
37            {
38                archive.Dispose();
39                archive = null;
40            }
41
42            if (zipStream != null)
43            {
44                zipStream.Dispose();
45                zipStream = null;
46            }
47
48            streamsCounter = 0;
49        }
50
51        public void Dispose()
52        {
53            DisposeArchive();
54        }
55    }

Save SVG to Memory Streams

Let’s consider the C# example of saving an SVG file with linked resources to a memory stream using the deprecated IOutputStorage interface and the new ResourceHandler class. The source with-resources.svg document and the linked image files are in the same directory.

Using IOutputStorage – 24.2.0 and Earlier Versions


The IOutputStorage interface implementation allowed saving SVG to memory streams:

 1using System.IO;
 2using Aspose.Svg.IO;
 3using System.Collections.Generic;
 4...
 5
 6    // Prepare a path to a source SVG file
 7    string inputPath = Path.Combine(DataDir, "with-resources.svg");
 8
 9    // Initialaze an SVG document
10    using (var doc = new SVGDocument(inputPath))
11    {
12        // Create an instance of the MemoryOutputStorage class and save SVG to memory
13        var memoryStorage = new MemoryOutputStorage();
14        doc.Save(memoryStorage);
15	    memoryStorage.PrintInfo();
16    }

After the example run, the message about memory storage will be printed:

uri:memory:///with-resources.svg, length:556
uri:memory:///photo.png, length:57438

The following code snippet shows the realization of the IOutputStorage in the MemoryOutputStorage class to demonstrate saving an SVG document to memory streams.

 1    internal class MemoryOutputStorage : IOutputStorage
 2    {
 3        public List<Tuple<OutputStream, string>> Streams;
 4
 5        public MemoryOutputStorage()
 6        {
 7            Streams = new List<Tuple<OutputStream, string>>();
 8        }
 9
10        public OutputStream CreateStream(OutputStreamContext context)
11        {
12            var normalizedPath = new Url(context.Uri).Pathname;
13            var uri = new Url(Path.GetFileName(normalizedPath), "memory:///").Href;
14            var outputStream = new OutputStream(new MemoryStream(), uri);
15            Streams.Add(Tuple.Create(outputStream, uri));
16            return outputStream;
17        }
18
19        public void ReleaseStream(OutputStream stream)
20        {
21            stream.Flush();
22        }
23
24        public void PrintInfo()
25        {
26            foreach (var stream in Streams)
27                Console.WriteLine($"uri:{stream.Item2}, length:{stream.Item1.Length}");
28        }
29    }

Using new ResourceHandler class – Since Version 24.3.0


The following code snippet shows the realization of the ResourceHandler in the MemoryResourceHandler class to demonstrate saving an SVG document to memory streams:

 1using System.IO;
 2using Aspose.Svg.IO;
 3using System.Collections.Generic;
 4...
 5
 6    // Prepare a path to a source SVG file
 7    string inputPath = Path.Combine(DataDir, "with-resources.svg");
 8
 9    // Initialize an SVG document
10    using (var doc = new SVGDocument(inputPath))
11    {
12        // Create an instance of the MemoryResourceHandler class and save SVG to memory
13        var resourceHandler = new MemoryResourceHandler();
14        doc.Save(resourceHandler);
15        resourceHandler.PrintInfo();
16    }

Instead of the CreateStream() and ReleaseStream() methods implemented in the MemoryOutputStorage class of the IOutputStorage interface, there is now one HandleResource() method implemented in the MemoryResourceHandler class of the ResourceHandler class, in which you can create a stream yourself and release it wherever you need it. The new method adds the ability to see a Resource and process more information about it:

 1    internal class MemoryResourceHandler : ResourceHandler
 2    {
 3        public List<Tuple<Stream, Resource>> Streams;
 4
 5        public MemoryResourceHandler()
 6        {
 7            Streams = new List<Tuple<Stream, Resource>>();
 8        }
 9
10        public override void HandleResource(Resource resource, ResourceHandlingContext context)
11        {
12            var outputStream = new MemoryStream();
13            Streams.Add(Tuple.Create<Stream, Resource>(outputStream, resource));
14            resource
15                .WithOutputUrl(new Url(Path.GetFileName(resource.OriginalUrl.Pathname), "memory:///"))
16                .Save(outputStream, context);
17        }
18
19        public void PrintInfo()
20        {
21            foreach (var stream in Streams)
22                Console.WriteLine($"uri:{stream.Item2.OutputUrl}, length:{stream.Item1.Length}");
23        }
24    }

As you can see, the new approach directly operates with Resource objects, eliminating the need for additional classes such as OutputStream. This simplifies the code and makes interaction with resources more explicit and understandable. Thus, the ResourceHandler base class offers a more simplified and expressive way to handle resources when saving SVG documents to memory streams.

After the example run, the message about memory storage will be printed:

uri:memory:///with-resources.svg, length:556
uri:memory:///photo.png, length:57438

FileSystemResourceHandler Class Vs LocalFileSystemStorage Class

Unlike the LocalFileSystemStorage class, the new FileSystemResourceHandler class allows you not only to save SVG documents and resources to the selected folder but also, through the methods of the ResourceHandler base class, to control the writing of links in parent files to the files you are saving.

Save SVG to a Local File System Storage

Here, we will examine the same example of saving the SVG file with-resources.svg to local file system storage using the deprecated LocalFileSystemStorage class and the new FileSystemResourceHandler class.

Using LocalFileSystemStorage Class – 24.2.0 and Earlier Versions


The source SVG document with the linked image files are in the same directory. The LocalFileSystemStorage(customOutDir) constructor creates an object that is a file system storage. The Save(IOutputStorage) method takes this object and saves SVG to the output storage.

 1using System.IO;
 2using Aspose.Svg.IO;
 3...
 4
 5	// Prepare a path to a source SVG file
 6    string inputPath = Path.Combine(DataDir, "with-resources.svg");
 7
 8    // Prepare a full path to an output directory 
 9    string customOutDir = Path.Combine(Directory.GetCurrentDirectory(), "./../../../../tests-out/old/");
10
11    // Load the SVG document from a file
12    using (var doc = new SVGDocument(inputPath))
13    {
14        // Save SVG with resources
15        doc.Save(new LocalFileSystemStorage(customOutDir));
16    }

Using FileSystemResourceHandler Class – Since Version 24.3.0


The FileSystemResourceHandler class is an implementation of the ResourceHandler class in Aspose.SVG for .NET. Explicitly designed for saving resources to the local file system, this class provides a convenient and extensible solution for managing resources when saving SVG documents. The following code snippet demonstrates the use of the FileSystemResourceHandler class:

 1using System.IO;
 2using Aspose.Svg.IO;
 3...
 4
 5    // Prepare a path to a source SVG file
 6    string inputPath = Path.Combine(DataDir, "with-resources.svg");
 7
 8    // Prepare a full path to an output directory 
 9    string customOutDir = Path.Combine(Directory.GetCurrentDirectory(), "./../../../../tests-out/new/");
10
11    // Load the SVG document from a file
12    using (var doc = new SVGDocument(inputPath))
13    {
14        // Save SVG with resources
15        doc.Save(new FileSystemResourceHandler(customOutDir));
16    }

The FileSystemResourceHandler(customOutDir) constructor takes a path indicating where the resources will be saved and creates a FileSystemResourceHandler object. The Save(resourceHandler) method takes this object and saves SVG to the output storage.

You can download the complete examples and data files from GitHub. About downloading from GitHub and running examples, you find out from the How to Run the Examples section.

You can try to convert SVG documents to various other formats with our Free Online SVG Converter.

Subscribe to Aspose Product Updates

Get monthly newsletters & offers directly delivered to your mailbox.