juergen d
juergen d

Reputation: 204756

Zip in memory and encode with base64

I want to zip a SVG file in memory and encode it with base64 (I want to save the zipped/base64 SVG in a XML file).

This is what I have (but I am open to everything):

byte[] svg = File.ReadAllBytes("test.SVG");
using (MemoryStream ms = new MemoryStream())
{  
    using (Package pkg = Package.Open(ms, FileMode.Create)) 
    {
        PackagePart part = pkg.CreatePart(new Uri("/test.SVG", UriKind.Relative), "image/svg+xml", CompressionOption.Normal);  
        using (Stream strm = part.GetStream()) 
        {  
            using (StreamWriter sw = new StreamWriter(strm)) 
            {  
                sw.Write(svg);
            }

            byte[] b = ReadToEnd(part.GetStream());
            return Convert.ToBase64String(b);
        }
    }
}

It convert something to base64 but that is not my file since it is only a few characters long.

Upvotes: 0

Views: 4435

Answers (2)

Jim Mischel
Jim Mischel

Reputation: 133995

There are multiple problems with your code.

Most importantly, you're opening a StreamWriter to write binary data. You have:

byte[] svg;

...

using (StreamWriter sw = new StreamWriter(...))
{
    sw.Write(svg);
}

StreamWriter is used to write text. The call you have ends up resolving to TextWriter.Write(object). The result is as if you had called:

sw.Write(svg.ToString());

Which will output the name of the class ("System.Byte[]"). That's why what you're getting is 13 bytes long. It also points to another problem (see below).

So the first thing you need to do is ditch the StreamWriter and have:

    using (Stream strm = part.GetStream()) 
    {  
        strm.Write(svg, 0, svg.Length)
    }

That, at least, will write the data you want to the stream.

Now, as for reading, you have a problem. You probably can then write:

        strm.Flush();
        strm.Position = 0;
        byte[] b = ReadToEnd(part.GetStream());
        return Convert.ToBase64String(b);

I don't know what your ReadToEnd method does. Perhaps it positions the stream and reads everything. But that's not going to give you what you want, which is the other problem I alluded to.

The stream returned by part.GetStream overrides the Read method and decompresses the data. So the byte array you get back will be the same as the original svg array that you wrote.

Looking at the Package API, I don't see a method that will give you the compressed data stream for a particular part.

In short, I think you need to write the entire package, convert that to base-64, and return it, as shown in Alexei's answer.

Upvotes: 3

Alexei Levenkov
Alexei Levenkov

Reputation: 100527

You are not seeking the stream to the beginning. Easiest fix is to use ToArray right before disposing MemoryStream:

using (MemoryStream ms = new MemoryStream())
{
  // Whatever manipulations with stream you need goes here.
  ...
  ms.Close(); // guarantees to commit all changes, 
              // safe to do as `ToArray` work on disposed stream
  return Convert.ToBase64String(ms.ToArrray());
}

Upvotes: 2

Related Questions