Steve
Steve

Reputation: 279

libtiff.net split multipage tiff into single page tiff images

I'm trying to use LibTiff.Net to split a multipage TIFF image into single page TIFF images.

I am building a TIFF splitting intermediary between two systems. I will receive the multipage TIFF image as a stream and then split it up into individual page TIFF image files and return them as a list of byte arrays.

I make a call to a web service that returns the multipage TIFF image as a stream. I need to extract each page as a separate TIFF image to return them as a list of byte arrays. I've seen the TiffCP utility that can split a multipage image on disk into separate TIFF image files on disk. I don't want to write anything to disk during this operation if I can avoid it.

I also don't want to decode any of the image content of the input image because that would waste processing time.

Is this possible with LibTiff.Net?

UPDATED @bobrovsky - thank you for your suggestion.

Here is what I've tried. I took the Copier class out of the source code for TiffCP to use it in my project with zero edits. The code below is how I'm using it. When this code completes execution the MemoryStream objects that should have the entire single page TIFF image inside them are all exactly 1,282 bytes in size. It seems like I'm missing a function call that forces the TIFF image data to be written to the underlying store (in this case the MemoryStream). I've included a call to Flush() to try fixing this issue but it had no affect. Does anyone know what I'm missing?

using (memoryStream)
{
    memoryStream.Position = 0;
    using (Tiff image = Tiff.ClientOpen("iqdoc", "r", memoryStream, new TiffStream()))
    {
        int totalPages = image.NumberOfDirectories();
        for (int i = 0; i < totalPages; i++)
        {
            image.SetDirectory((short)i);
            using (var ms = new MemoryStream())
            using (Tiff page = Tiff.ClientOpen("page", "w", ms, new TiffStream()))
            {
                var c = new Copier();
                c.m_compression = c.m_defcompression; // THIS WAS MISSING
                if (!c.Copy(image, page) || !page.WriteDirectory())
                    throw new ApplicationException("Failed to extract page from document for presentation.");

                FieldValue[] field = image.GetField(TiffTag.IMAGEWIDTH);
                int width = field[0].ToInt();

                field = image.GetField(TiffTag.IMAGELENGTH);
                int height = field[0].ToInt();

                page.Flush();

                pages.Add(new
                {
                    Height = height,
                    Width = width,
                    PageBytes = Convert.ToBase64String(ms.ToArray()),
                });

                c = null;
            }
        }
    }
}

Thanks!

Upvotes: 2

Views: 2341

Answers (1)

Bobrovsky
Bobrovsky

Reputation: 14236

Yes, it's possible. TiffCP does this.

You can take TiffCP code and adapt it to your needs (change the way it stores output).

You can also come up with other ideas and implement one of those.

You might not get a complete working solution in an answer on this site.

EDIT:

Your code is mostly ok, but you should only access bytes of the memory stream after Tiff has finished writing to it.

Unfortunately, Tiff closes memory stream in it's Dispose and Close methods. You might try two approaches to overcome the issue:

  • Call Tiff.WriteDirectory before accessing bytes in the memory stream. This should be ok, but you might get an incomplete TIFF in the stream.
  • Create your own stream (based on the System.IO.MemoryStream) which overloads Close method with an empty implementation and use this stream instead of MemoryStream. Access bytes in this stream after Tiff is disposed.

Upvotes: 1

Related Questions