Solved

How to add pages to an existing Tiff with TiffBitmapEncoder

Posted on 2011-02-14
4
3,300 Views
Last Modified: 2012-05-11
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
Loop

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
            Try
                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
                    encoder.Frames.Add(frm)
                Next
                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.Frames.Add(Windows.Media.Imaging.BitmapFrame.Create(strBmp))
                    strBmp.Close()
                Next

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

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

            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
 encoder.Save(File.Create("myNewTiff.tif"))

Open in new window

That yielded an error that I had bad metadata.

I'm using VB.net 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.
0
Comment
Question by:ja928
  • 3
4 Comments
 
LVL 83

Expert Comment

by:CodeCruiser
Comment Utility
You are adding frames in two separate loops. Why is that?
0
 

Author Comment

by:ja928
Comment Utility
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.
0
 

Accepted Solution

by:
ja928 earned 0 total points
Comment Utility
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

        Try
            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.Frames.Add(frm)
                Next
                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)
                        tiffEncoder.Frames.Add(bmp)
                    End Using
                Next

                tiffEncoder.Save(output)

            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.
0
 

Author Closing Comment

by:ja928
Comment Utility
This shows how to perform the task looping through files in a folder.  It can be tailored to your specific application
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Object to array 7 26
Setting location of a form 4 21
Problem to picture file 3 37
Exception in Log4Net 1 17
PaperPort 14.5 Patch 1 update is often not detected or downloaded automatically. This article provides direct download links to solve the problem for retail (non-bundled) versions of the Standard and Professional editions, as well as the Professiona…
This article shows how to convert a multi-page PDF file into multiple image files, with one image file created for each page of the PDF. It does this by utilizing an excellent, free software package called GraphicsMagick. The solution is amazingly s…
We often encounter PDF files that are pure images, that is, they do not have text characters, but instead contain only raster graphics. The most common causes of this are document scanning software and faxing software/services that create image-only…
In this seventh video of the Xpdf series, we discuss and demonstrate the PDFfonts utility, which lists all the fonts used in a PDF file. It does this via a command line interface, making it suitable for use in programs, scripts, batch files — any pl…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now