2011.05.05 16:44 "[Tiff] Is LibTiff 3.9.5 Thread Safe ?", by Katerina Sedivy

2011.05.05 16:44 "[Tiff] Is LibTiff 3.9.5 Thread Safe ?", by Katerina Sedivy

Hi,

 So I have my LibTiff.dll 3.9.5 compiled and loaded in a multithread
environement.

I have a tiff which I have used with the TiffInfo tool at command line to
see its information (I've attached the file):

TIFF Directory at offset 0x3e30 (15920)
    Subfile Type: (0 = 0x0)
    Image Width: 1224 Image Length: 576
    Resolution: 96, 96 pixels/inch
    Bits/Sample: 1
    Compression Scheme: LZW
    Photometric Interpretation: min-is-black
    Orientation: row 0 top, col 0 lhs
    Samples/Pixel: 1
    Rows/Strip: 80
    Planar Configuration: single image plane
    Predictor: none 1 (0x1)

I successfully retrieve the information with this code:

procedure TMainAppRunnerDlg.Button3Click(Sender: TObject);
var
  l_Tiff: pointer;
  lu_BitsPerSample: Word;
begin

  l_Tiff := DLL_TIFFOpen(PChar('C:\cheque_3533_A.tif'), 'r');
  if l_Tiff <> nil then
  begin
    lu_BitsPerSample := 0;

    if DLL_TIFFGetField(l_Tiff, 258, lu_BitsPerSample) = 0 then   //

TIFFTAG_BITSPERSAMPLE = 258
      if lu_BitsPerSample = 0 then
        OutputDebugString(PChar('WARNING: TIFFGetField returned false and
BitsPerSample = 0'))
      else
        OutputDebugString(PChar('WARNING: TIFFGetField returned false and
BitsPerSample <> 0 '));
    DLL_TIFFClose(l_Tiff);
    outputdebugstring(PChar('Pass!!!'));

  end;
end;

BUT This same file failed in a multithread environement. I run the code
below in a Thread. There are 3 threads created which each execute
TIFFGetField multiple times, once in a while BitsPerSample returned by
TIFFGetField is 0 instead of 1.

I also got this message in my debugger for the Tiff file attached:
ODS: module: TIFF directory is missing required "%s" field | message:
C:\Develop\Tests\Service app\Thread1\cheque_3533_A.tif Process
ServiceTester.exe ($A50)

Which is a warning output by TIFFReadDirectory in tif_dirread.c.

procedure TServiceThread.Execute;
var
  i: Integer;
  l_Config: TConfig;
  l_Filenames: TStringList;
  ls_Filename,ls_otfilename, ls_dir: string;

  lh_ProcRefrence: longint;
  lu_BitsPerSample: Word;
  lh_TiffHandle: Pointer;
  lh_DLLHandle: Cardinal;

begin
  CoInitialize(nil);
  FreeOnTerminate := True;

  l_Filenames := TStringList.Create;
  try
    LoadConfig(l_Config.InPath, l_Config.FileType, l_Config.Output);
    GetFilesToProcess(l_Filenames, l_Config.InPath, l_Config.FileType);

    for i := 0 to l_Filenames.Count - 1 do
    begin
          try
            ls_Filename := l_Config.InPath + l_Filenames.Strings[i];
            lh_ProcRefrence := DLL_TIFFSetErrorHandler(@TiffErrorProc);
            if lh_ProcRefrence = 0 then
            begin
              OutputDebugString(PChar('WARNING: DLL_TIFFSetErrorHandler
failed'));
              exit;
            end;

//            OutputDebugString(PChar(Format('Thread: %d  | File:

%s',[ThreadID, ls_Filename])));

            lh_TiffHandle := nil;
            lh_TiffHandle := DLL_TIFFOpen(ls_Filename, 'r');
            lu_BitsPerSample := 0;

            if DLL_TIFFGetField(lh_TiffHandle, 258, lu_BitsPerSample) = 0
then // TIFFTAG_BITSPERSAMPLE = 258
              if lu_BitsPerSample = 0 then
                OutputDebugString(PChar(Format('WARNING: TIFFGetField
returned false and BitsPerSample = 0 | Filename: %s |ThreadID:
%d',[ls_Filename, ThreadID])))
              else
                OutputDebugString(PChar(Format('WARNING: TIFFGetField
returned false and BitsPerSample <> 0 | ThreadID: %d',[ThreadID])));
            if lh_TiffHandle <> nil then
              DLL_TIFFClose(lh_TiffHandle);
          except
            on E: Exception do
            begin
              OutputDebugString(PChar(Format('ERROR: %s with file: %s |
ThreadID: %d',[E.Message, ls_Filename, ThreadID])));
              exit;
            end;
          end;
      end;
  finally
    l_Filenames.Free;
    CoUninitialize;
    FreeLibrary(lh_DLLHandle);
  end;