How to add pages to an existing Tiff with TiffBitmapEncoder

I've been working with the Bob Powell example for Adding pages to a multipage TIFF and ran into some speed issues performing the add within a loop. Basically, I have a loop that is:

While ChecksArePresent
  Scan Images
    add to tiff
    Store data in DB

I experience increasingly slow processing as I add pages to the tiff, and I understand that that is because I am re-encoding the pages again and again with each pass.  I had "Parameter is Not Valid" when I collected the images into an ArrayList or List(Of Image).

When I work with the TiffBitmapEncoder I am getting "Handle is Invalid" errors with the streams for outputting the file. This attempt basically fills up a temporary directory with the scanned images, then loops through these like so:
    Private Function AddPagesToMaster() As Boolean
        Dim bRetVal As Boolean = False
        If Directory.GetFiles(sTempFilePath).Length > 0 Then
                If File.Exists(TEMP_FILE_NAME) Then File.Delete(TEMP_FILE_NAME)
                File.Move(g_sMasterTif, TEMP_FILE_NAME)
                Dim encoder As New System.Windows.Media.Imaging.TiffBitmapEncoder
                encoder.Compression = Windows.Media.Imaging.TiffCompressOption.Ccitt4
                Dim fsIn As New FileStream(TEMP_FILE_NAME, FileMode.Open, FileAccess.Read, FileShare.Read)
                Dim fsOut As New FileStream(g_sMasterTif, FileMode.Create, FileAccess.ReadWrite, FileShare.None)
                Dim decoder As New System.Windows.Media.Imaging.TiffBitmapDecoder(fsIn, Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat, Windows.Media.Imaging.BitmapCacheOption.Default)

                For Each frm As System.Windows.Media.Imaging.BitmapSource In decoder.Frames
                Dim aImg() As String = Directory.GetFiles(sTempFilePath)
                Array.Sort(aImg) 'I am naming the files so that they come back sequentially and I can figure the Page number in another proc.
                For Each sPath As String In aImg
                    Dim strBmp As Stream = File.OpenRead(sPath)

                encoder.Save(fsOut) 'Gives me a "Handle is invalid error

                bRetVal = True
            Catch ex As Exception
                MessageBox.Show(ex.Message, "Exception in AddPagesToMaster", MessageBoxButtons.OK, MessageBoxIcon.Error)

            End Try
        End If

        Return bRetVal
    End Function

Open in new window

I have tried wrapping up the fsIn and fsOut variables in "Using" statements with the same effect.  I tried deleting the output file and changed the error line to

Open in new window

That yielded an error that I had bad metadata.

I'm using 2010 on Windows 7, 64bit.  I've found a few articles that indicate changes under the hood for CCITT4 on Windows 7, but I have also changed to LZW and None for the compression to no avail.  I've seen Libtiff.Net but want to keep my number of DLLs down if I can simply code this directly.  I checked MSDN, but can't quite work out the errors described above.

Any help would be greatly appreciated.
Who is Participating?
ja928Connect With a Mentor Author Commented:
After a lot of struggles with contention, I was able to get it working this way:
    Public Function AddToMaster(ByVal sFolder As String) As Boolean
        Dim bRetval As Boolean = False

        Dim decoder As BitmapDecoder = Nothing

            Using appendToOutput As Stream = File.Open(g_sMasterTif, FileMode.Open, FileAccess.Read, FileShare.Read)
                decoder = BitmapDecoder.Create(appendToOutput, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
            End Using

            Using output As Stream = File.Open(g_sMasterTif, FileMode.Open, FileAccess.Write)
                Dim tiffEncoder As TiffBitmapEncoder = New TiffBitmapEncoder()
                For Each frm As BitmapFrame In decoder.Frames
                tiffEncoder.Compression = TiffCompressOption.Ccitt4

                Dim aImg() As String = Directory.GetFiles(sFolder)
                Array.Sort(aImg) 'I am naming the files so that they come back sequentially and I can figure the Page number in another proc.
                For Each sFile As String In aImg
                    Dim bmp As BitmapFrame = Nothing

                    Using original As Stream = File.Open(sFile, FileMode.Open, FileAccess.Read)
                        bmp = BitmapFrame.Create(original, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad)
                    End Using


            End Using
            bRetval = True
        Catch ex As Exception
            'Handle problems
            Dim sDebug As String = ex.Message
        End Try

        Return bRetval
    End Function

Open in new window

This uses the Framework 4 features and required no third party dependencies.
You are adding frames in two separate loops. Why is that?
ja928Author Commented:
Thanks for your comment.  The project is a check scanning application which captures the front and back image of a check, adds the images to an existing TIFF, and updates the database so we can retrieve the frames later.  The reason for the master TIFF is that we scan 500,000 checks annually and wanted to decrease the number of files in any given folder for maintenance and backup.  The psuedo-coded loop is an existing state that works in VB6 with Advanced Imagery Library and FreeImage3.dll. We are updating the application to .Net and I wanted to slim down the number of references.  The Framework 4 TiffBitmapEncoder object looked ideal for this, but I can't seem to get it to work.  I'd prefer to go with this if I can reduce my dependencies and get a fast enough processing time.

The Bob Powell example worked for me, but got progressively slower with each scan since the sub routines loop through each frame of the (growing) Master Tiff with each pass.  Correct me if I'm wrong, but I was under the impression that you can't just open a TIFF and append the frames at the end.  The Bob Powell example is viable if I can queue up the images in some kind of array, but when I try that I get "Parameter is not Valid" errors trying to pull the images from my in-memory array.  I've seen other sources that store them as backgrounds for Panels, but again it looks like the TiffBitmapEncoder should do the trick.
ja928Author Commented:
This shows how to perform the task looping through files in a folder.  It can be tailored to your specific application
All Courses

From novice to tech pro — start learning today.