;========================================================================================================================================== ; Create a list of all TIF files with their number of included image pages. ; ; Detlev Dalitz.20120412.20120413.20120414. ;========================================================================================================================================== ;------------------------------------------------------------------------------------------------------------------------------------------ #DefineFunction udfTIFPageCount (strFilename, intMode) ; Version 2. IntControl (73, 1, @TRUE, "", 0) ; On error goto the label :WBERRORHANDLER and leave the function. LastError () strByteOrder = "" hdlBB = BinaryAlloc (4) BinaryReadEx (hdlBB, 0, strFilename, 0, 2) strByteOrder = BinaryPeekStr (hdlBB, 0, 2) intByteOrder = BinaryPeek2 (hdlBB, 0) Switch intByteOrder Case 18761 ; "II" the file is little-endian byte order (Intel). BinaryReadEx (hdlBB, 0, strFilename, 2, 2) intFileID = BinaryPeek2 (hdlBB, 0) ; These 2 header bytes are the file identifier. Version number (always 42). If intFileID != 42 ; If this is not 42, it is not a valid tif image. intPageCount = -2 Break EndIf intPageCount = 0 BinaryReadEx (hdlBB, 0, strFilename, 4, 4) intPosIFD = BinaryPeek4 (hdlBB, 0) ; Offset to first IFD Image File Directory. This IFD can be located anywhere in the file. Every 'page' in a multi-page TIFF is represented by one IFD. While intPosIFD ; Break on the null pointer. BinaryReadEx (hdlBB, 0, strFilename, intPosIFD, 2) intTags = BinaryPeek2 (hdlBB, 0) ; Number of tags in IFD. Read the first 2 bytes of the IFD header for the number of directory entries for this page. intPosNext = intPosIFD + 2 + (12 * intTags) ; Next pointer location is the number of entries at 12 bytes each plus 2 for the header. Offset to next IFD, if there is a next IFD, 0 otherwise. BinaryReadEx (hdlBB, 0, strFilename, intPosNext, 4) intPosIFD = BinaryPeek4 (hdlBB, 0) ; Read next pointer. intPageCount = intPageCount + 1 ; Increment page counter. EndWhile Break Case 19789 ; "MM" the file is big-endian byte order (Motorola). BinaryReadEx (hdlBB, 0, strFilename, 2, 2) BinaryPokeHex (hdlBB, 0, BinaryPeekHex (hdlBB, 1, 1) : BinaryPeekHex (hdlBB, 0, 1)) ; Reverse byte order. intFileID = BinaryPeek2 (hdlBB, 0) ; These 2 header bytes are the file identifier. Version number (always 42). If intFileID != 42 ; If this is not 42, it is not a valid tif image. intPageCount = -2 Break EndIf intPageCount = 0 BinaryReadEx (hdlBB, 0, strFilename, 4, 4) BinaryPokeHex (hdlBB, 0, BinaryPeekHex (hdlBB, 3, 1) : BinaryPeekHex (hdlBB, 2, 1) : BinaryPeekHex (hdlBB, 1, 1) : BinaryPeekHex (hdlBB, 0, 1)) ; Reverse byte order. intPosIFD = BinaryPeek4 (hdlBB, 0) ; Offset to first IFD Image File Directory. This IFD can be located anywhere in the file. Every 'page' in a multi-page TIFF is represented by one IFD. While intPosIFD ; Break on the null pointer. BinaryReadEx (hdlBB, 0, strFilename, intPosIFD, 2) BinaryPokeHex (hdlBB, 0, BinaryPeekHex (hdlBB, 1, 1) : BinaryPeekHex (hdlBB, 0, 1)) ; Reverse byte order. intTags = BinaryPeek2 (hdlBB, 0) ; Number of tags in IFD. Read the first 2 bytes of the IFD header for the number of directory entries for this page. intPosNext = intPosIFD + 2 + (12 * intTags) ; Next pointer location is the number of entries at 12 bytes each plus 2 for the header. Offset to next IFD, if there is a next IFD, 0 otherwise. BinaryReadEx (hdlBB, 0, strFilename, intPosNext, 4) BinaryPokeHex (hdlBB, 0, BinaryPeekHex (hdlBB, 3, 1) : BinaryPeekHex (hdlBB, 2, 1) : BinaryPeekHex (hdlBB, 1, 1) : BinaryPeekHex (hdlBB, 0, 1)) ; Reverse byte order. intPosIFD = BinaryPeek4 (hdlBB, 0) ; Read next pointer. intPageCount = intPageCount + 1 ; Increment page counter. EndWhile Break Case intByteOrder intPageCount = -1 ; Not a valid tif image. EndSwitch :WBERRORHANDLER If LastError () Then intPageCount = -3 ; Not a valid tif image. hdlBB = BinaryFree (hdlBB) If !intMode Then Return intPageCount Return Arrayize (intPageCount : "|" : strByteOrder, "|") ;.......................................................................................................................................... ; This UDF "udfTIFPageCount" returns the integer number of all pages included in the given TIF file. ; ; intMode=0 ... Return the number of pages as integer value. ; intMode=1 ... Return an array of two values. ; arrResult[0] ... the number of pages as integer value. ; arrResult[1] ... the byte order mark as a two character string value. ; ; In case of an error ... ; ... with intMode=0 the integer return value resp. with intMode=1 the arrResult[0] contains a negative integer value: ; -1 ... The TIF byte order mark "II" resp. "MM" cannot be found; ; -2 ... The TIF version number (always 42) cannot be found; ; -3 ... Any other error, possibly damage of the TIF file structure. ; ... with intMode=1 the arrResult[1] contains the first two characters from the current file, if any. ; ; See TIF specifications ... ; http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf ; http://www.awaresystems.be/imaging/tiff.html ; ; Detlev Dalitz.20120412.20120413.20120414. ;.......................................................................................................................................... #EndFunction ;------------------------------------------------------------------------------------------------------------------------------------------ ;------------------------------------------------------------------------------------------------------------------------------------------ #DefineSubRoutine udfPathFold (strPath) If !StrIndex (strPath, "\\", 0, @FWDSCAN) Then Return StrReplace (strPath, "\", "\" : @LF) Return "\\" : StrReplace (StrSub (strPath, 3, -1), "\", "\" : @LF) #EndSubRoutine ;------------------------------------------------------------------------------------------------------------------------------------------ ; Test. DirChange (DirScript ()) strFileThis = IntControl (1004, 0, 0, 0, 0) strFileListIn = ItemReplace ("TIF.List.In.txt", -1, strFileThis, ".") strFileListOut = ItemReplace ("TIF.List.Out.txt", -1, strFileThis, ".") ;---------------------------- :Step1 ; Collect TIF files. ;---------------------------- arrMasks = Arrayize ("*.tif|*.tiff", "|") intMasksLast = ArrInfo (arrMasks, 1) - 1 arrDisks = Arrayize (DiskScan (2), @TAB) intDisksLast = ArrInfo (arrDisks, 1) - 1 ; File and Folder Finder. ; Load Appropriate Extender module. If WinMetrics (-2) == 3 Then AddExtender ("WWFAF64I.DLL") ; 64-bit Else AddExtender ("WWFAF44I.DLL") ; 32-bit ;fafDefault = 0 ; Use extender defaults, same as not specifying a value for the parameter. fafHidden = 1 ; Include hidden files. ;fafSystem = 2 ; Include system files. ;fafFolders = 4 ; Inspect subfolder names also. ;fafFindFolders = 8 ; Only inspect subfolder names not file names. fafRecurse = 16 ; Recurse through subfolders. ;fafNoPathInfo = 32 ; Do not return path information to files or folders found. ;fafNoRedirect = 64 ; Do not turn off file redirection for x64 windows. strMsgTitle = 'Step 1 | TIF | Search for TIF files' strMsgText = "" BoxOpen (strMsgTitle, strMsgText) WinPlace (200, 200, 600, 700, "") BoxDataTag (1, 1) intF = 0 arrFiles = ArrDimension (0) For intD = 0 To intDisksLast strFolderRoot = arrDisks[intD] : "\" For intM = 0 To intMasksLast hdlFAF = fafOpen (strFolderRoot, arrMasks[intM], fafRecurse | fafHidden) While @TRUE strFileFullName = fafFind (hdlFAF) If strFileFullName == "" Then Break ArrayRedim (arrFiles, intF + 1) arrFiles[intF] = strFileFullName intF = intF + 1 strMsgTitle1 = strMsgTitle : "|" : intF : "|" : FileBaseName (strFileFullName) strMsgText = "Files found: " : intF : @LF : @LF : udfPathFold (strFileFullName) BoxTitle (strMsgTitle1) BoxText (strMsgText) BoxDataClear (1, 1) EndWhile fafClose (hdlFAF) Next Next If !!ArrInfo (arrFiles, 1) Then ArraySort (arrFiles) intBytesWritten = ArrayFilePut (strFileListIn, arrFiles) Drop (arrFiles) strMsgText = "Files found: " : intF : @LF : @LF : "Ready." BoxButtonDraw (1, 1, "&OK", "50,780,950,950") BoxText (strMsgText) While !BoxButtonStat (1, 1) TimeDelay (0.2) EndWhile BoxButtonKill (1, 1) BoxShut () Drop (strMsgTitle1, strMsgTitle, strMsgText, strFolderRoot, strFileFullName, intM, intF, intD) Drop (intDisksLast, intMasksLast, intBytesWritten, hdlFAF, fafRecurse, fafHidden) Drop (arrMasks, arrFiles, arrDisks, strPath) ;---------------------------- :Step2 ; Examine TIF files. ;---------------------------- IntControl (73, 2, @TRUE, "", 0) ; On error gosub the label :WBERRORHANDLER. strMsgTitle = "Step 2 | TIF | PageCount | ByteOrder" strMsgText = "" BoxOpen (strMsgTitle, strMsgText) WinPlace (200, 200, 600, 700, "") BoxDataTag (1, 1) arrFiles = ArrayFileGetCSV (strFileListIn, 0, "|") intFiles = ArrInfo (arrFiles, 1) intFilesLast = intFiles - 1 ; Column 2 contains FullFilename. ArrayInsert (arrFiles, 0, 2) ; Column 1 contains ByteOrder. ArrayInsert (arrFiles, 0, 2) ; Column 0 contains PageCount. For intF = 0 To intFilesLast arrResult = udfTIFPageCount (arrFiles[intF, 2], 1) arrFiles[intF, 0] = arrResult[0] arrFiles[intF, 1] = arrResult[1] strMsgText = intFiles : "/" : 1 + intF : @LF : @LF : "PageCount = " : arrFiles[intF, 0] : @LF : "ByteOrder = " : arrFiles[intF, 1] : @LF : "Filename = ..." : @LF : udfPathFold (arrFiles[intF, 2]) BoxText (strMsgText) BoxDataClear (1, 1) Next intBytes = ArrayFilePutCSV (strFileListOut, arrFiles, "|") BoxButtonDraw (1, 1, "&OK", "50,780,950,950") BoxText (strMsgText) While !BoxButtonStat (1, 1) TimeDelay (0.2) EndWhile BoxButtonKill (1, 1) BoxShut () If intBytes Then Run (strFileListOut, "") :CANCEL Exit :WBERRORHANDLER IntControl (73, 2, @TRUE, "", 0) ; On error gosub the label :WBERRORHANDLER. Return ;==========================================================================================================================================