It probally could be better or faster I am open for suggestions.
I did +3K photos on my nas all made with my sony camera spoofing the binairy exif header rewriting the windows timestamps.
All credits go to the makers of the functions
Laszlo BinRead
JaseF and Krogdor Hex2ASCII
hberntsen GetDateTaken
hberntsen for his idea todo it like this without a 3rd party app.
My code will read 512 bytes from byte 200 (offset), I opened a few photos and the best change to get a usable date are within these ranges if exif data header is present.
Main code
Code:
Loop, *.jpg,,1
{
file = %A_LoopFileFullPath%
Progress, b w500, At work,%A_LoopFileFullPath%, %A_LoopFileFullPath%, %A_LoopFileFullPath%
Progress, 10
res := BinRead(file,data,512,200)
Progress, 10
hexdate := GetDateTaken(data)
Progress, 20
hex := Hex2ASCII(hexdate)
Progress, 30
RegExMatch(hex,"\d\d\d\d:\d\d:\d\d\s\d\d:\d\d:\d\d", date)
Progress, 40
if date =
{
Progress, 100
continue
}
Progress, 50
StringReplace, hex, hex, :, , All
StringReplace, hex, hex, %A_SPACE%, , All
StringLeft, OutputHex, hex, 14
FileGetTime, OutputVar, %A_LoopFileFullPath%, C
if OutputHex = %OutputVar%
{
Progress, 100
continue
}
Loop,25
{
bar := 50+A_index
Progress, %bar%
sleep 1
}
FileSetTime, %Outputhex%, %A_LoopFileFullPath%, M
FileSetTime, %Outputhex%, %A_LoopFileFullPath%, C
FileSetTime, %Outputhex%, %A_LoopFileFullPath%, A
Loop,25
{
bar := 75+A_index
Progress, %bar%
sleep 1
}
}
exitapp
Used Functions
hberntsen GetDateTakenCode:
GetDateTaken(data)
{
Loop, Parse, data, `n
{
RegExMatch(A_LoopField,"3\d3\d3\d3\d3a3\d3\d3a3\d3\d203\d3\d3a3\d3\d3a3\d3\d", hexdate)
if hexdate !=
break
}
if hexdate !=
return hexdate
}
JaseF and Krogdor Hex2ASCIICode:
Hex2ASCII(fHexString)
{
Loop Parse, fHexString
NewHexString .= A_LoopField (Mod(A_Index,2) ? "" : ",")
StringTrimRight, NewHexString, NewHexString,1
Loop, Parse, NewHexString, `,
ConvString .= Chr("0x" A_LoopField)
Return ConvString
}
Laszlo BinRead Code:
BinRead(file, ByRef data, n=0, offset=0)
{
h := DllCall("CreateFile","Str",file,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
IfEqual h,-1, SetEnv, ErrorLevel, -1
IfNotEqual ErrorLevel,0,Return,0 ; couldn't open the file
m = 0 ; seek to offset
IfLess offset,0, SetEnv,m,2
r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
IfEqual r,0, SetEnv, ErrorLevel, -3
IfNotEqual ErrorLevel,0, {
t = %ErrorLevel% ; save ErrorLevel to be returned
DllCall("CloseHandle", "Uint", h)
ErrorLevel = %t% ; return seek error
Return 0
}
TotalRead = 0
data =
IfEqual n,0, SetEnv n,0xffffffff ; almost infinite
format = %A_FormatInteger% ; save original integer format
SetFormat Integer, Hex ; for converting bytes to hex
Loop %n%
{
result := DllCall("ReadFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Read,"UInt",0)
if (!result or Read < 1 or ErrorLevel)
break
TotalRead += Read ; count read
c += 0 ; convert to hex
StringTrimLeft c, c, 2 ; remove 0x
c = 0%c% ; pad left with 0
StringRight c, c, 2 ; always 2 digits
data = %data%%c% ; append 2 hex digits
}
IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%
h := DllCall("CloseHandle", "Uint", h)
IfEqual h,-1, SetEnv, ErrorLevel, -2
IfNotEqual t,,SetEnv, ErrorLevel, %t%
SetFormat Integer, %format% ; restore original format
Totalread += 0 ; convert to original format
Return TotalRead
}
After having all this done I made a script that sorted all .jpg into a yyyy-mm-dd folder.
Note* this will only look at the timestamp not the exif data
Code:
Loop, *.jpg,,1
{
SplashTextOn, 400, 300, File, Current file:`n%A_LoopFileFullPath%
LoopFileTimeModified:=substr(A_LoopFileTimeModified,1,4) . "-" . substr(A_LoopFileTimeModified,5,2) . "-" . substr(A_LoopFileTimeModified,7,2)
if LoopFileTimeModified = %A_LoopFileDir%
continue
IfNotExist, %A_ScriptDir%\%LoopFileTimeModified%
FileCreateDir, %A_ScriptDir%\%LoopFileTimeModified%
FileMove, %A_LoopFileFullPath%, %A_ScriptDir%\%LoopFileTimeModified%,0 ; Move the file without renaming it.
}
exitapp
Leave me a message when you are using it, Thanks.