3
votes

We've come across some TIFF images that are type 6 OJPEG compressed, many have the same BitsPerSample of "8 8 8" and work fine.

However, now and then we see ones that have a BitsPerSample value of say "8 25608 0". I'm wondering if this is even possible and if not whether its a bug in the system that generated the TIFFs. If it is could they potentially be fixed by simply modifying the tag so the BitsPerSample is "8 8 8"?

Currently I've only found one tool (LEAD) that can handle them by converting them to uncompressed TIFFs, obviously I've no idea how it does this and it's a big overhead just to solve an issue with a very small minority of images.

Has anyone come across this or have more knowledge than me regarding whether this is simple or complicated to fix, so far my attempts at poking around in the Libtiff.net code haven't been very fruitful!

Cheers

UPDATE: Using litiff.net with something as simple as this:

    static void Main(string[] args)
    {
        using (Tiff image = Tiff.Open(args[0], "r"))
        {
            FieldValue[] value = image.GetField(TiffTag.IMAGEWIDTH);
            int width = value[0].ToInt();

            Console.WriteLine(string.Format("Width = {0}", width));
        }
    }

Results in (obviously skipped the exception handling!):

ReadDirectory: Warning, 10.TIF: unknown field with tag 33000 (0x80e8) encountered 10.TIF: Cannot handle different per-sample values for field "BitsPerSample"

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object. at tifftest.Program.Main(String[] args) in C:\tiffstuff\tifftest\tifftest\Program.cs:line 15 Segmentation fault

I'm now getting it to bypass the check and assume 8 for "BitsPerSample" however I'm now trying to extract the image to save as a BMP using the example on the bitmiracle site:

            using (Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb))
            {
                Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height);

                BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                byte[] bits = new byte[bmpdata.Stride * bmpdata.Height];

                for (int y = 0; y < bmp.Height; y++)
                {
                    int rasterOffset = y * bmp.Width;
                    int bitsOffset = (bmp.Height - y - 1) * bmpdata.Stride;

                    for (int x = 0; x < bmp.Width; x++)
                    {
                        int rgba = raster[rasterOffset++];
                        bits[bitsOffset++] = (byte)((rgba >> 16) & 0xff);
                        bits[bitsOffset++] = (byte)((rgba >> 8) & 0xff);
                        bits[bitsOffset++] = (byte)(rgba & 0xff);
                    }
                }

                System.Runtime.InteropServices.Marshal.Copy(bits, 0, bmpdata.Scan0, bits.Length);
                bmp.UnlockBits(bmpdata);

                bmp.Save("c:\\tiffstuff\\TiffTo24BitBitmap.bmp");
            }

I obviously get the OJPEG warning and then the following: OJPEGReadHeaderInfoSecTablesQTable: Missing JPEG tables

The resultant image is just 100% green.

Am I just too far out of my depth in terms of fixing this? I know the JPEG is in there somewhere just can't seem to get at it and decompress it successfully :-(

2
Are you working with colour or grayscale images? Just a guess, but if SamplesPerPixel is set to 1, I think you only need to read 1 value, which would be "8". This is the case with grayscale images. Colour images use 3 samples per pixel (RGB) and you need "8" for each channel. What are you doing to the images and can you show code of where it fails? - John Willemse
They are RGB images, I've updated the original question with some basic code, issue is I can't even open the file to change the BitsPerSample tag to test if changing it to "8 8 8" would fix the issue. Once successfully opened I just want to save it as a JPEG. - Simon
@Simon do we have a solution to this now after 8years has passed. my TIF image is JPEG compressed with bit depth of 24. and this is only getting converted to jpg using tool LEAD. any direction would be helpful. - Ankit Dhadse

2 Answers

1
votes

A bit depth of 25608 is definitely wrong. JPEG compression never uses a bit depth other than 8 bits per pixel. There are other image formats that can use 16 or even 32 bits per pixel, but that is as high as it gets for any normal application.

In JPEG there is RGB images, i.e. "8 8 8", CMYK images, i.e "8 8 8 8", and monochrome images, ie. "8".

It's possible that the images are CMYK, and that the software that you use doesn't support that. In that case you need to convert them to RGB to use them with that software.

If the images are RGB then the tag is simply corrupt, and fixing it would make the images work just fine. (Assuming of course that there isn't anything else that is also currupted.)

1
votes

It seems like the file is semi-broken. As @Guffa mentioned, for OJPEG files bits per sample value should be 8 8 8 (RGB) or 8 8 8 8 (CMYK)

Unfortunately, LibTiff.Net does not give a chance to repair such important tags like BITSPERSAMPLE.

The only option I see is to add auto-correction code for such files into the library.

The code that gives the error is in Tiff_DirRead.cs file (in three places shown below).

private bool fetchPerSampleShorts(TiffDirEntry dir, out short pl)
{
    ...
    for (ushort i = 1; i < check_count; i++)
    {
        if (v[i] != v[0])
        {
            ErrorExt(this, m_clientdata, m_name,
                "Cannot handle different per-sample values for field \"{0}\"",
                FieldWithTag(dir.tdir_tag).Name);
            failed = true;
            break;
        }
    }
    ...
}

private bool fetchPerSampleLongs(TiffDirEntry dir, out int pl)
{
    ...
    for (ushort i = 1; i < check_count; i++)
    {
        if (v[i] != v[0])
        {
            ErrorExt(this, m_clientdata, m_name,
                "Cannot handle different per-sample values for field \"{0}\"",
                FieldWithTag(dir.tdir_tag).Name);
            failed = true;
            break;
        }
    }
    ...
}

private bool fetchPerSampleAnys(TiffDirEntry dir, out double pl)
{
    ...
    for (ushort i = 1; i < check_count; i++)
    {
        if (v[i] != v[0])
        {
            ErrorExt(this, m_clientdata, m_name,
                "Cannot handle different per-sample values for field \"{0}\"",
                FieldWithTag(dir.tdir_tag).Name);
            failed = true;
            break;
        }
    }
    ...
}

You might try to remove if (v[i] != v[0]) clause and corresponding error-handling code. I think this will let you open the file (if there is no other problems in it).

You might want to convert or at least patch such files somehow.