WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

UDF - UDS Library
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus
plus

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

TIF Page Counter

 Keywords: TIF TIFF Page Count Conter Freeimage FreeImage.dll DllCall DllCallCdecl FreeImage_OpenMultiBitmap FreeImage_GetPageCount FreeImage_CloseMultiBitmap

;==========================================================================================================================================
; Create a list of all TIF files with their number of included image pages.
;
; Detlev Dalitz.20120412.
;==========================================================================================================================================

;------------------------------------------------------------------------------------------------------------------------------------------
#DefineFunction udfTIFPageCount (strFilename)
IntControl (73, 1, @TRUE, "", 0) ; On error goto the label :WBERRORHANDLER and leave the function.
LastError ()
hdlBB = BinaryAlloc (4)
BinaryReadEx (hdlBB, 0, strFilename, 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
   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.
   intPageCount = 0
   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))
   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
   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))
   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.
   intPageCount = 0
   While intPosIFD ; Break on the null pointer.
      BinaryReadEx (hdlBB, 0, strFilename, intPosIFD, 2)
      BinaryPokeHex (hdlBB, 0, BinaryPeekHex (hdlBB, 1, 1) : BinaryPeekHex (hdlBB, 0, 1))
      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))
      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)
Return intPageCount
;..........................................................................................................................................
; This UDF udfTIFPageCount returns the integer number of all pages included in the given TIF file.
;
; In case of an error the function returns 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.
;
; See TIF specifications ...
; http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf
; http://www.awaresystems.be/imaging/tiff.html
;
; Detlev Dalitz.20120412.
;..........................................................................................................................................
#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


AddExtender ("wwfaf44i.dll") ; File and Folder Finder.
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)

intCountObjects = 0
intCountItems = 0

intF = 0
arrFiles = ArrDimension (0)

For intD = 0 To intDisksLast
   strFolderRoot = arrDisks[intD] : "\"
   For intM = 0 To intMasksLast
      strMask = arrMasks [intM]

      hdlFAF = fafOpen (strFolderRoot, strMask, fafRecurse|fafHidden)
      While @TRUE
         strFileFullName = fafFind (hdlFAF)
         If strFileFullName == "" Then Break

         intCountItems = intCountItems + 1
         strMsgTitle1 = strMsgTitle : "|" : intCountItems : "|" : FileBaseName (strFileFullName)
         BoxTitle (strMsgTitle1)

         ArrayRedim (arrFiles, intF + 1)
         arrFiles[intF] = strFileFullName
         intF = intF + 1

         intCountObjects = intCountObjects + 1
         strMsgText = "Objects found: " : intCountObjects : @LF : @LF : udfPathFold (strFileFullName)
         BoxText (StrSub (strMsgText, 1, 2400)) ; Display only the first 2400 characters.
         BoxDataClear (1, 1)
      EndWhile
      fafClose (hdlFAF)
   Next
Next

If !!ArrInfo (arrFiles, 1) Then ArraySort (arrFiles)
intBytesWritten = ArrayFilePut (strFileListIn, arrFiles)

Drop (arrFiles)

strMsgText = "Objects found: " : intCountObjects : @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 ()


;----------------------------
: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

ArrayInsert (arrFiles, 0, 2) ; Column 0 contains PageCount.
ArrayInsert (arrFiles, 0, 2) ; Column 1 contains ByteOrder.
; Column 2 contains FullFilename.

intTicks1 = 0
intTicks2 = 0

hdlBB = BinaryAlloc (2) ; Buffer for ByteOrder bytes.
For intF = 0 To intFilesLast
   arrFiles[intF, 0] = udfTIFPageCount (arrFiles[intF, 2])

   BinaryReadEx (hdlBB, 0, arrFiles[intF, 2], 0, 2) ; Get ByteOrder bytes.
   arrFiles[intF, 1] = BinaryPeekStr (hdlBB, 0, 2)
   BinaryEodSet (hdlBB, 0)

   strMsgText = intFiles : "/" : 1 + intF : @LF : @LF : "PageCount = " : arrFiles[intF, 0] : @LF : "ByteOrder = " : arrFiles[intF, 1] : @LF : "Filename = " : @LF : udfPathFold (arrFiles[intF, 2])
   BoxText (StrSub (strMsgText, 1, 2400)) ; Display only the first 2400 characters.
   BoxDataClear (1, 1)
Next
hdlBB = BinaryFree (hdlBB)

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
;==========================================================================================================================================
;;;


#DefineFunction GetPageCount(tiffile)
      ; returns number of pages in a multipage tiff file
      ;
      ; for info and downloads see  http://freeimage.sourceforge.net/
      ;
      ; KDMOYERS 2012.04.11

      me = 'GetPageCount'

      If !FileExist(tiffile)
        Return -1
      EndIf
      Terminate(StrUpper(FileExtension(tiffile)) != "TIF", me, 'only works on tiff files')

      FIF_BMP = 0
      FIF_PCX = 10
      FIF_TIFF = 18
      FIF_JPEG = 2

      pdllhandle = PtrPersistent(dllhandle, 0)
      If *pdllhandle == 0 Then *pdllhandle = DllLoad(DirScript() : "FreeImage.dll")

      ;DLL_API FIMULTIBITMAP * DLL_CALLCONV FreeImage_OpenMultiBitmap(FREE_IMAGE_FORMAT fif, const char *filename, BOOL create_new, BOOL read_only, BOOL keep_cache_in_memory FI_DEFAULT(FALSE), int flags FI_DEFAULT(0));
      imag1 = DllCallCDecl(*pdllhandle, long : "_FreeImage_OpenMultiBitmap@24", long : FIF_TIFF, lpstr : tiffile, long : 0, long : 1, long : 0, long : 0)
      Terminate(imag1 == 0, me, 'Failed to load tiff' : @LF : tiffile)

      ;DLL_API int DLL_CALLCONV FreeImage_GetPageCount(FIMULTIBITMAP *bitmap);
      pages = DllCallCDecl(*pdllhandle, long : "_FreeImage_GetPageCount@4", long : imag1)

      ;DLL_API BOOL DLL_CALLCONV FreeImage_CloseMultiBitmap(FIMULTIBITMAP *bitmap, int flags FI_DEFAULT(0));
      x = DllCallCDecl(*pdllhandle, long : "_FreeImage_CloseMultiBitmap@8", long : imag1, long : 0)
      Terminate(x == 0, me, 'Failed to close tiff')
      imag1 = 0

      Return pages
#EndFunction

Article ID:   W18336
Filename:   TIF Page Counter.txt
File Created: 2012:04:12:13:44:46
Last Updated: 2012:04:12:13:44:46