Link to home
Start Free TrialLog in
Avatar of smithmrk
smithmrkFlag for United States of America

asked on

Memory Question

OK, I need to understand something because I'm confused!

I have this loop here that adds images to a ArrayList from Memory.
Then I loop through the ArrayList to create a Multipage TIFF File.

What I don't understand is if I close the MemoryStream after I create each image it still adds the images to the ArrayList...but when I go to read them I get an error that the Stream is closed?

This WORKS:
For icount As Int16 = 0 To 2
            Dim Ticket As New Bitmap(1312, 574)
            Dim ticketGraphics As Graphics = Graphics.FromImage(Ticket)
            Dim MyFont As New Font("Arial", 20, FontStyle.Regular)
            Dim memstrm As IO.MemoryStream = New IO.MemoryStream

            ticketGraphics.DrawString("-- Test Ticket --", MyFont, Brushes.Black, 520, 90)
            ticketGraphics.DrawString(icount.ToString, MyFont, Brushes.Black, 520, 120)
            Ticket.Save(memstrm, System.Drawing.Imaging.ImageFormat.Tiff)

            MultipageImages.Add(memstrm)
            memstrm.Flush()
        Next

This DOES NOT WORK after I add them all to the ArrayList:
For icount As Int16 = 0 To 2
            Dim Ticket As New Bitmap(1312, 574)
            Dim ticketGraphics As Graphics = Graphics.FromImage(Ticket)
            Dim MyFont As New Font("Arial", 20, FontStyle.Regular)
            Dim memstrm As IO.MemoryStream = New IO.MemoryStream

            ticketGraphics.DrawString("-- Test Ticket --", MyFont, Brushes.Black, 520, 90)
            ticketGraphics.DrawString(icount.ToString, MyFont, Brushes.Black, 520, 120)
            Ticket.Save(memstrm, System.Drawing.Imaging.ImageFormat.Tiff)

            MultipageImages.Add(memstrm)
            memstrm.Flush()
           memstrm.Close()
       Next

Private Sub CreateMultiPage_ImageFile()
        ImageWriter = New IO.FileStream("C:\MemoryTest.tif", FileMode.Create)

        Dim saveEncoder As Encoder
        Dim compressionEncoder As Encoder
        Dim SaveEncodeParam As EncoderParameter
        Dim EncoderParams As New EncoderParameters(1)
        Dim codecInfo As ImageCodecInfo = getCodecForString("TIFF")

        saveEncoder = Encoder.SaveFlag
        compressionEncoder = Encoder.Compression

        ' Save the first page:.
        SaveEncodeParam = New EncoderParameter(saveEncoder, CLng(EncoderValue.MultiFrame))
        EncoderParams.Param(0) = SaveEncodeParam

        Dim TicketImage As Image = Image.FromStream(DirectCast(MultipageImages(0), Stream))
       TicketImage.Save(ImageWriter, codecInfo, EncoderParams)

        For iCount As Int16 = 1 To MultipageImages.Count - 1

            ' Save the next set of pages:
            SaveEncodeParam = New EncoderParameter(saveEncoder, CLng(EncoderValue.FrameDimensionPage))
            EncoderParams.Param(0) = SaveEncodeParam

            Dim NextImage As Image = Image.FromStream(DirectCast(MultipageImages(iCount), Stream))
            TicketImage.SaveAdd(NextImage, EncoderParams)
        Next

        SaveEncodeParam = New EncoderParameter(saveEncoder, CLng(EncoderValue.Flush))
        EncoderParams.Param(0) = SaveEncodeParam
        TicketImage.SaveAdd(EncoderParams)

        MultipageImages.Clear()
        MultipageImages = Nothing
        ImageWriter.Close()
        ImageWriter.Dispose()
    End Sub

The error occurs when trying to load the Image From the ArrayList into an Image...but it works fine if I don't close the Memory Stream after each image...why?

Just trying to manage the memory to the best to not overload it.

Thanks,
Mark
Avatar of Nasir Razzaq
Nasir Razzaq
Flag of United Kingdom of Great Britain and Northern Ireland image

You are just adding a reference to the original stream to the array so when you access it, it still tries to access the original memstream.
Avatar of smithmrk

ASKER

OK, it this a good practice or should I be doing something different to use the memory resources to the best?

Thanks,
Mark
You can keep the images in memory as ByteArray instead of streams.
OK...how do I convert / change my code to use a Byte Array vs. the Array List?

Thanks,
Mark
ASKER CERTIFIED SOLUTION
Avatar of Nasir Razzaq
Nasir Razzaq
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
How does this look?

Imports System.IO
Imports System.Xml
Imports System.Drawing.Imaging
Imports System.Runtime.InteropServices

Public Class Form1
    Private ImageWriter As IO.FileStream
    Private MultipageImages As New ArrayList
    Private ImageByteArray As Byte()

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        For icount As Int16 = 0 To 4
            Dim Ticket As New Bitmap(1312, 574)
            Dim ticketGraphics As Graphics = Graphics.FromImage(Ticket)
            Dim MyFont As New Font("Arial", 20, FontStyle.Regular)
            Dim memstrm As IO.MemoryStream = New IO.MemoryStream

            ticketGraphics.DrawString("-- Test Ticket --", MyFont, Brushes.Black, 520, 90)
            ticketGraphics.DrawString(icount.ToString, MyFont, Brushes.Black, 520, 120)
            Ticket.Save(memstrm, System.Drawing.Imaging.ImageFormat.Tiff)

            ImageByteArray = memstrm.ToArray
            MultipageImages.Add(ImageByteArray)
            memstrm.Flush()
            memstrm.Close()
            memstrm.Dispose()
            Ticket.Dispose()
            ticketGraphics.Dispose()
            MyFont.Dispose()
            ImageByteArray = Nothing
        Next

        Call CreateMultiPage_ImageFile()
        MessageBox.Show("Done")
    End Sub

    Private Sub CreateMultiPage_ImageFile()
        ImageWriter = New IO.FileStream("C:\MemoryTest.tif", FileMode.Create)

        Dim saveEncoder As Encoder
        Dim compressionEncoder As Encoder
        Dim SaveEncodeParam As EncoderParameter
        Dim EncoderParams As New EncoderParameters(1)
        Dim codecInfo As ImageCodecInfo = getCodecForString("TIFF")

        saveEncoder = Encoder.SaveFlag
        compressionEncoder = Encoder.Compression

        ' Save the first page:.
        SaveEncodeParam = New EncoderParameter(saveEncoder, CLng(EncoderValue.MultiFrame))
        EncoderParams.Param(0) = SaveEncodeParam

        ImageByteArray = MultipageImages(0)
        Dim memstrm As IO.MemoryStream = New IO.MemoryStream(ImageByteArray)

        Dim TicketImage As Image = Image.FromStream(memstrm)
        TicketImage.Save(ImageWriter, codecInfo, EncoderParams)
        memstrm.Flush()
        memstrm.Close()
        memstrm.Dispose()
        ImageByteArray = Nothing

        For iCount As Int16 = 1 To MultipageImages.Count - 1
            ' Save the next set of pages:
            SaveEncodeParam = New EncoderParameter(saveEncoder, CLng(EncoderValue.FrameDimensionPage))
            EncoderParams.Param(0) = SaveEncodeParam

            ImageByteArray = MultipageImages(iCount)
            memstrm = New IO.MemoryStream(ImageByteArray)

            Dim NextImage As Image = Image.FromStream(memstrm)
            TicketImage.SaveAdd(NextImage, EncoderParams)
            memstrm.Flush()
            memstrm.Close()
            memstrm.Dispose()
            NextImage.Dispose()
            ImageByteArray = Nothing
        Next

        SaveEncodeParam = New EncoderParameter(saveEncoder, CLng(EncoderValue.Flush))
        EncoderParams.Param(0) = SaveEncodeParam
        TicketImage.SaveAdd(EncoderParams)

        MultipageImages.Clear()
        MultipageImages = Nothing
        ImageWriter.Close()
        ImageWriter.Dispose()
    End Sub

    Private Function getCodecForString(ByVal type As String) As ImageCodecInfo
        Dim info As ImageCodecInfo() = ImageCodecInfo.GetImageEncoders()

        For i As Integer = 0 To info.Length - 1
            Dim EnumName As String = type.ToString()
            If info(i).FormatDescription.Equals(EnumName) Then
                Return info(i)
            End If
        Next

        Return Nothing
    End Function
End Class

Open in new window

Looks fine. Does it work?
YES, Thank You!
I'm just trying to make my program as efficent as possible to make the best of memory and resources.

Thanks again,
Mark
Thanks for you help!

Mark
Glad it worked :-)