Home > Net >  How to avoid random InvalidDataException using System.IO.Compression
How to avoid random InvalidDataException using System.IO.Compression

Time:01-12

I have a .zip file containing three jpg images. I want to display all three of them in one FlowDocumentReader in WPF.

This is my code:

FlowDocument flowDoc = new FlowDocument();
ZipArchive zipFile = ZipFile.OpenRead("images.zip");

foreach (ZipArchiveEntry zip in zipFile.Entries)
{
    Stream imageStream = zip.Open();
    BitmapImage bitmapImage = new BitmapImage();
    bitmapImage.BeginInit();
    bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
    bitmapImage.StreamSource = imageStream;
    bitmapImage.EndInit();
    bitmapImage.DownloadCompleted  = BitmapImage_DownloadCompleted;

    Image myImage = new Image
    {
        Source = bitmapImage,
        Stretch = Stretch.Uniform
    };

    BlockUIContainer uiContainer = new BlockUIContainer
    {
        Child = myImage
    };

    flowDoc.Blocks.Add(uiContainer);
}

FlowDocReader.Document = flowDoc;

Up to the last line it always works without problems, but when the FlowDocumentReader loads the document there randomly appear problems:

Sometimes the code works well and alle three images are displayed in the FlowDocumentReader.

Sometimes some of the images are displayed with some errors (shifted colors at some bottom lines of pixels). I get no exception in this cases.

Sometimes only one, two or no image is displayed. In this case there is 2x per image not displayed Exception thrown: 'System.IO.InvalidDataException' in System.dll. This exception was originally thrown at this call stack: System.IO.Compression.InflaterZlib.Inflate(System.IO.Compression.ZLibNative.FlushCode)

I get all of this random results using the same .zip file. I can reproduce the problem using different .zip files.

Am I doing something wrong, or is there a known bug?

CodePudding user response:

There are situations where BitmapImage does apparently not read its StreamSource until the end. This may for example occur when you read a bitmap from the response stream of a HTTP request.

I also observed it with the Stream returned from the ZipArchiveEntry.Open() method.

My workaround in these situations is to copy the frame buffer into an intermediate MemoryStream:

using (var archive = ZipFile.OpenRead("images.zip"))
{
    foreach (var entry in archive.Entries)
    {
        using (var imageStream = entry.Open())
        using (var memoryStream = new MemoryStream())
        {
            imageStream.CopyTo(memoryStream);
            memoryStream.Seek(0, SeekOrigin.Begin);

            var bitmapImage = new BitmapImage();
            bitmapImage.BeginInit();
            bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
            bitmapImage.StreamSource = memoryStream;
            bitmapImage.EndInit();

            ...
        }
    }
}
  • Related