4

I have a TIFF using JPEG format the WPF / C# can not handle via TiffBitmapDecoder. Our clients use the file format and our current C++ and Java code handles it.

I need to convert this to a format I can display using TiffBitmapDecoder or standard BitmapImage. It looks like the C# version of libtiff is the way to go but I am not having any luck converting in code.

Here is my attempt - I always end up with corrupt files.

Boolean doSystemLoad = false;
Tiff tiff = null;

try
{
    tiff = Tiff.Open(file, "r");
}
catch (Exception e) // TIFF could not handle, let OS do it
{
    doSystemLoad = true;
}
if (tiff != null)
{
    width = Double.Parse(tiff.GetField(TiffTag.IMAGEWIDTH)[0].Value.ToString());
    height = Double.Parse(tiff.GetField(TiffTag.IMAGELENGTH)[0].Value.ToString());

    int bits = Int32.Parse(tiff.GetField(TiffTag.BITSPERSAMPLE)[0].Value.ToString());
    int samples = Int32.Parse(tiff.GetField(TiffTag.SAMPLESPERPIXEL)[0].Value.ToString());
    string compression = tiff.GetField(TiffTag.COMPRESSION)[0].Value.ToString();

    Console.WriteLine("Image is " + width + " x " + height + "   bits " + bits + " sample " + samples);
    Console.WriteLine("Compression " + compression);

    // We allow OS to load anything that is not JPEG compression
    doSystemLoad = compression.ToLower().IndexOf("jpeg") == -1;

    string tempFile = Path.GetTempFileName() + ".tiff";

    // Convert here then load converted via OS
    if (!doSystemLoad)
    {
        Console.WriteLine(">> Attempting to convert... " + tempFile);
        Console.WriteLine("  Scan line  " + tiff.ScanlineSize());

        Tiff tiffOut = Tiff.Open(tempFile, "w");
        tiffOut.SetField(TiffTag.IMAGEWIDTH, width);
        tiffOut.SetField(TiffTag.IMAGELENGTH, height);
        tiffOut.SetField(TiffTag.BITSPERSAMPLE, bits);
        tiffOut.SetField(TiffTag.SAMPLESPERPIXEL, samples);
        tiffOut.SetField(TiffTag.ROWSPERSTRIP, 1L);
        tiffOut.SetField(TiffTag.COMPRESSION, Compression.NONE);
        tiffOut.SetField(TiffTag.ORIENTATION, BitMiracle.LibTiff.Classic.Orientation.TOPLEFT);
        tiffOut.SetField(TiffTag.FAXMODE, FaxMode.CLASSF);
        tiffOut.SetField(TiffTag.GROUP3OPTIONS, 5);

        tiffOut.SetField(TiffTag.PHOTOMETRIC, Photometric.RGB);

        tiffOut.SetField(TiffTag.FILLORDER, FillOrder.MSB2LSB);
        tiffOut.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
        tiffOut.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);
        tiffOut.SetField(TiffTag.XRESOLUTION, 100.0);
        tiffOut.SetField(TiffTag.YRESOLUTION, 100.0);
        tiffOut.SetField(TiffTag.SUBFILETYPE, FileType.PAGE);
        tiffOut.SetField(TiffTag.PAGENUMBER, new object[] { 1, 1 });
        tiffOut.SetField(TiffTag.PAGENAME, "Page 1");

        Byte[] scanLine = new Byte[tiff.ScanlineSize() + 5000];
        for (int row = 0; row < height; row++)
        {
            tiff.ReadScanline(scanLine, row);
            tiffOut.WriteScanline(scanLine, row);
        }
        tiffOut.Dispose();
    }

    tiff.Dispose();

    Stream imageStreamSource = new FileStream(tempFile, FileMode.Open, FileAccess.Read, FileShare.Read);
    TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    BitmapSource bitmapSource = decoder.Frames[0];

    width = bitmapSource.Width;
    height = bitmapSource.Height;

    imageMain.Width = width;
    imageMain.Height = height;
    imageMain.Source = bitmapSource;
}

if (doSystemLoad)
{
    Stream imageStreamSource = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
    TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    BitmapSource bitmapSource = decoder.Frames[0];

    width = bitmapSource.Width;
    height = bitmapSource.Height;

    imageMain.Width = width;
    imageMain.Height = height;
    imageMain.Source = bitmapSource;
}
Bobrovsky
  • 13,789
  • 19
  • 80
  • 130
Kevin
  • 51
  • 1
  • 3
  • 1
    I use BitMiracle LibTiff.net too (and am very pleased with it). My code however, always calls Flush on output files. I'm not sure if Dispose will do that for you; I had corrupt files before using flush too. Please check files with TiffDump (standard binaries available with libtiff for win32) – Adriaan Jun 18 '10 at 09:41

2 Answers2

2

Kevin, one of the previous versions of LibTiff.Net had a bug: Flush was not automatically called. It's fixed some time ago.

Also, we have just released LibTiff.Net 2.2 with support for OJPEG (or Old Jpeg, or Original Jpeg) files. You may want to retry your attempts with the new version if it's still relevant.

Bobrovsky
  • 13,789
  • 19
  • 80
  • 130
  • Cant we use built in class `TiffBitmapDecoder` to read Tiled TIFF as bytes and write it as pdf using iTextSharp? I am not allowed to use any library except iTextSharp :( – Billa Feb 27 '14 at 22:26
1

After direct contact with BitMiracle it turns out that neither LibTIff for C or LibTiff for .NET support the underlying file format so I am out of luck in this area. I will need to look into commercial package support which we hoped to avoid for our .NET product. We already use Acordex for Java and ImageGear for C++ so I believe we will use ImageGear for .NET. TIFF is just a bear to support and we have too many clients using this obscure file format to drop support for it.

Kevin
  • 51
  • 1
  • 3
  • Libtiff.NET started supporting TIFF-JPEG in Summer 2010, and decode-support for TIFF-OJPEG in Spring 2011. Announcements [here](http://bitmiracle.com/blog/category/libtiff). – rwong Aug 23 '11 at 16:53
  • Not quite so :-) As a developer behind LibTiff.Net I should say that the library supports JPEG-in-TIFF since the first release (February 13th, 2010) and OJPEG-in-TIFF since January, 2011. – Bobrovsky Aug 23 '11 at 17:32