yigolden / TiffLibrary

C# library for decoding and encoding Tag Image File Format (TIFF) files.
MIT License
58 stars 16 forks source link

Multipage Tiff #3

Closed raboud closed 3 years ago

raboud commented 3 years ago

when loading a 25 page tiff file the frame count comes back as 1. And when i sage the file back, I get a single page.

namespace TiffTester
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");

            SixLabors.ImageSharp.Configuration.Default.Configure(new TiffLibrary.ImageSharpAdapter.TiffConfigurationModule());

            using (Image<Rgba32> image = Image.Load<Rgba32>(@"e:/temp/Test1.tiff"))
            {
                int pageCount = image.Frames.Count;

                image.SaveAsTiff(@"e:/temp/test2.tif", new TiffEncoder
                {
                    PhotometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero,
                    EnableTransparencyForRgb = false,
                    Compression = TiffCompression.T4Encoding,
                    Predictor = TiffPredictor.None
                });
            }
        }
    }
}
yigolden commented 3 years ago

Multipage TIFFs are not supported by the ImageSharp adapter. I will investigate how to implement this. In the meantime, you could workaround this issue by using this code to load and save multipage TIFF.

List<Image<L8>> frames = new List<Image<L8>>();
try
{
    // Load multipage TIFF
    using (TiffFileReader reader = await TiffFileReader.OpenAsync(@"E:\temp\Test1.tiff"))
    {
        TiffStreamOffset ifdOffset = reader.FirstImageFileDirectoryOffset;
        while (!ifdOffset.IsZero)
        {
            TiffImageFileDirectory ifd = await reader.ReadImageFileDirectoryAsync(ifdOffset);
            TiffImageDecoder decoder = await reader.CreateImageDecoderAsync(ifd);
            Image<L8> image = new Image<L8>(decoder.Width, decoder.Height);
            await decoder.DecodeAsync(image);
            frames.Add(image);
            ifdOffset = ifd.NextOffset;
        }
    }

    // Save multipage TIFF
    TiffImageEncoderBuilder builder = new TiffImageEncoderBuilder();
    builder.PhotometricInterpretation = TiffPhotometricInterpretation.WhiteIsZero;
    builder.Compression = TiffCompression.T4Encoding;
    TiffImageEncoder<L8> encoder = builder.BuildForImageSharp<L8>();

    using (TiffFileWriter writer = await TiffFileWriter.OpenAsync(@"E:\temp\test2.tif"))
    {
        TiffStreamOffset lastOffset = default;
        foreach (Image<L8> image in frames)
        {
            using (TiffImageFileDirectoryWriter ifdWriter = writer.CreateImageFileDirectory())
            {
                await encoder.EncodeAsync(ifdWriter, image);
                if (lastOffset.IsZero)
                {
                    lastOffset = await ifdWriter.FlushAsync();
                    writer.SetFirstImageFileDirectoryOffset(lastOffset);
                }
                else
                {
                    lastOffset = await ifdWriter.FlushAsync(lastOffset);
                }
            }
        }
        await writer.FlushAsync();
    }
}
finally
{
    foreach (var image in frames)
    {
        image.Dispose();
    }
}
yigolden commented 3 years ago

After some investigation, I don't think this is possible with the Image.Frames API. Because in ImageSharp, frames in an image must have the same size. They are exclusively used in GIF format. While in multipage TIFF, pages can have different sizes. They should be treated like a collection of images instead of frames.

To support multipage TIFF, I think a "image collection"-like API is appropriate which doesn't exists in ImageSharp library today.