Lazarus

Free Pascal => Windows => Topic started by: ratmalwer on November 07, 2017, 01:13:10 pm

Title: how to get the original filedate not date modifyed
Post by: ratmalwer on November 07, 2017, 01:13:10 pm
Hello

I have this statement witch works

Code: Pascal  [Select][+][-]
  1. FileDateTime := FormatDateTime('YYYY.MM.DD hh:mm:ss', FileDateToDateTime(FileAge(myFilename)));
Result = 2015.08.14 20:15:48

When I check it with the Windows-Explorer I see that this result is the date-modified.
How can I get the original-date of the file (created by my camara) witch is 2006.04.04 12:28 ???
Title: Re: how to get the original filedate not date modifyed
Post by: ASerge on November 07, 2017, 04:48:18 pm
Code: Pascal  [Select][+][-]
  1. uses Windows;
  2.  
  3. function TryGetFileTimeCreated(const FileName: string; out Created: TDateTime): Boolean;
  4. var
  5.   R: TSearchRec;
  6.   UTCTime, LocalTime: TSystemTime;
  7. begin
  8.   Result := FindFirst(FileName, faArchive, R) = 0;
  9.   if Result then
  10.   begin
  11.     SysUtils.FindClose(R);
  12.     Result := FileTimeToSystemTime(@R.FindData.ftCreationTime, @UTCTime) and
  13.       SystemTimeToTzSpecificLocalTime(nil, @UTCTime, @LocalTime);
  14.   end;
  15.   if Result then
  16.     Created := SystemTimeToDateTime(LocalTime)
  17.   else
  18.     Created := 0;
  19. end;
  20.  
  21. procedure TForm1.FormCreate(Sender: TObject);
  22. var
  23.   Created: TDateTime;
  24. begin
  25.   if TryGetFileTimeCreated(Application.ExeName, Created) then
  26.     Caption := DateTimeToStr(Created);
  27. end;
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 07, 2017, 06:08:05 pm
Hi Serge

thanks for this clear funtion.... it works nicely but does not give me the desired result.
As I do not have a Windowsversion in english I enclose the corresponding Printscreen.

My solution gives the result shown in column B. (modificationtime = probabli when I resized the picture last)
Your solution gives the result in column D (creationtime = the time I copied the picture).

What I want is the time shown in Column A or C (the time th picture was taken)....
... somehow I suspect Windows looks at the EXIF of the picture when creating this Datetime. But I do not know where it is stored.
Title: Re: how to get the original filedate not date modifyed
Post by: molly on November 07, 2017, 06:21:52 pm
I haven't checked ASerge's code, but took my inspiration (read: shameless copy) from StackOverFlow (https://stackoverflow.com/questions/9209394/how-to-get-file-created-accessed-and-modified-dates-the-same-as-windows-propert).

Code: Pascal  [Select][+][-]
  1. program test;
  2.  
  3. {$MODE OBJFPC}{$H+}
  4.  
  5. uses
  6.   WIndows, SysUtils;
  7.  
  8.  
  9. procedure ReportTime(const Name: string; const FileTime: TFileTime);
  10. var
  11.   SystemTime, LocalTime: TSystemTime;
  12. begin
  13.   if not FileTimeToSystemTime(FileTime, SystemTime)
  14.   then RaiseLastOSError;
  15.  
  16.   if not SystemTimeToTzSpecificLocalTime(nil, SystemTime, LocalTime)
  17.   then RaiseLastOSError;
  18.   WriteLn(Name, ': ', DateTimeToStr(SystemTimeToDateTime(LocalTime)));
  19. end;
  20.  
  21. procedure ReportFileTimes(const FileName: string);
  22. var
  23.   fad: TWin32FileAttributeData;
  24. begin
  25.   if not GetFileAttributesEx(PChar(FileName), GetFileExInfoStandard, @fad)
  26.   then RaiseLastOSError;
  27.   WriteLn(FileName);
  28.   ReportTime('Created' , fad.ftCreationTime);
  29.   ReportTime('Modified', fad.ftLastWriteTime);
  30.   ReportTime('Accessed', fad.ftLastAccessTime);
  31. end;
  32.  
  33. begin
  34.   ReportFileTimes('test.exe');
  35. end.
  36.  

Perhaps that is able to help you out ?
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 07, 2017, 06:37:39 pm
Thanks.. it looks similar to Serges code...

Code: Pascal  [Select][+][-]
  1.   ReportTime('Created' , fad.ftCreationTime);
  2.   ReportTime('Modified', fad.ftLastWriteTime);
  3.   ReportTime('Accessed', fad.ftLastAccessTime);
  4.  
  5. here I need someting like (wherever Windows stores this)
  6.  
  7.   ReportTime('original' , fad.ftOriginalTime); ???
  8.   ReportTime('EXIF', fad.ftEXIFTime);  ???
  9.   ReportTime('camera', fad.ftCameraTime); ???
Title: Re: how to get the original filedate not date modifyed
Post by: molly on November 07, 2017, 06:47:16 pm
Ah ok.

Just to make sure: are you are talking about metadata stored inside the file itself ?

In case it is then this can't be retrieved with the functions showed so far. It depends on the fileformat and how the metadata is stored inside the file.

Seeing that you mentioned exif, afaik means that you would either require to use a exif library that examines the file or use special windows shell api functionality (the latter i do not have a ready to go example for as ti depends on the installed explorer extension(s)).
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 07, 2017, 07:01:28 pm
You see my problem alright!

But Windows stores this date in the field: date taken (rightclick on a JPG in explorer --- Properties -- Details  -- Title: Origin) and makes it to its (main)date.  -- or look at my printscreen above.
Now is just the question how to get hold of that.
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 07, 2017, 07:08:35 pm
Hi molly

again you are right... sorry I did not finish reading correctly.
So if somebody has a API-solution I gladly apprechiate that.
On the other hand I can redesign my workflow, as I'm not verry good in API-Calls and verry new to lazarus..
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 07, 2017, 11:42:46 pm
Finally I fount the right property - it is System.Photo.DateTaken

https://msdn.microsoft.com/en-us/library/windows/desktop/bb760410(v=vs.85).aspx (https://msdn.microsoft.com/en-us/library/windows/desktop/bb760410(v=vs.85).aspx)

but how do I implement an API-Call??? I did not find an example...
Title: Re: how to get the original filedate not date modifyed
Post by: molly on November 08, 2017, 01:56:19 am
@ratmalwer:
You can try the port of DExif (https://github.com/cutec-chris/dexif) library, which afaik has the additional feature of being platform agnostic. If you download the sources then there is a pdf that has all relevant information listed to tell you how to use the library.
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 08, 2017, 01:22:34 pm
Thanks for this hint. This could be a possibility, but I suppose it is rather slow on a big amount of pictures.

Now I installed the package: DExif and got the basic-example running - I get a heap-error closing the app. So I have no plan what to do?!

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   MyFileName : String;
  4.   ImgData: TImgData;
  5. begin
  6.      if OpenDialog1.Execute then
  7.    begin
  8.      MyFileName := OpenDialog1.Filename;
  9.    end;
  10.   if FileExists(MyFileName) then begin
  11.     ValueListEditor1.Clear;
  12.     Image1.Proportional:= True;
  13.     Image1.Stretch:= True;
  14.     Image1.Picture.LoadFromFile(MyFileName);
  15.     ImgData:= TImgData.Create();
  16.     try
  17.       if ImgData.ProcessFile(MyFileName) then begin
  18.         if ImgData.HasEXIF then begin
  19.           ValueListEditor1.InsertRow('Camera Make',
  20.             ImgData.ExifObj.CameraMake,True);
  21.           ValueListEditor1.InsertRow('Camera Modell',
  22.             ImgData.ExifObj.CameraModel,True);
  23.           ValueListEditor1.InsertRow('Picture DateTime',
  24.             FormatDateTime(ISO_DATETIME_FORMAT, ImgData.ExifObj.GetImgDateTime),True);
  25.         end
  26.         else
  27.           ValueListEditor1.InsertRow('No EXIF','No Data',True);
  28.       end
  29.       else
  30.         ValueListEditor1.InsertRow('No EXIF','Processdata',True);
  31.     finally
  32.       ImgData.Free;
  33.     end;
  34.   end;
  35. end;
Title: Re: how to get the original filedate not date modifyed
Post by: molly on November 09, 2017, 02:11:16 am
Thanks for this hint. This could be a possibility, but I suppose it is rather slow on a big amount of pictures.
How do you think that Explorer retrieves this information ? Exactly in a similar manner  :)

The only thing that explorer could perhaps do better (due to its integration) is caching the results in the background. That advantage is gone the moment you start to handle a big amount of files, as cache runs dry.

Quote
Now I installed the package: DExif and got the basic-example running - I get a heap-error closing the app. So I have no plan what to do?!
Post your project or create a simple example project showing that heaptrace error. You can publish your project inside lazarus and zip up the directory/files where you published the files into. You can attach that zip-file to a post on the forum

I made a simple example using FPC, based on the code you showed and i did not experience any leakage. That suggests that you have some leakage somewhere else inside your code and is probably not related to your use of DExif library.

fwiw: this is the output from my fpc test example (using the nokia test jpg that came with DExif):
Code: [Select]
> test
Camera Make      : Nokia
Camera Model     : 6300
Picture DateTime : 2017-09-11 09:57:02
Heap dump by heaptrc unit
1559 memory blocks allocated : 141850/158056
1559 memory blocks freed     : 141850/158056
0 unfreed memory blocks : 0
True heap size : 163840 (96 used in System startup)
True free heap : 163744
Note that heaptrace does produce a message (i did not turned that off), but is telling that there are zero unfreed memory blocks (meaning everything went ok).
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 09, 2017, 02:51:10 pm
Hi molly
thanks that you care.

I agree, that windows gets the information from the Exif. But I think it stores it in System.Photo.DateTaken for fast access in Windows-explorer. Else it would take ages opening a folder contining hundreds of pictures. Thats the reason I fancy this option.

On the other hand I could use the DExif to display more information in my app.
So I enclose my project (Basic-sample sligtly modifyed) and the errormessage. Please tell me if thats suffitient.

Title: Re: how to get the original filedate not date modifyed
Post by: molly on November 09, 2017, 05:02:29 pm
thanks that you care.
Please tell me if thats suffitient.

You're welcome, and at the same time you make my 'job' easy. The picture alone was sufficient  :)

Take a very good look at your screen-shot. It says: "0 unfreed memory blocks : 0"

As i wrote in my previous post, that means that everything went ok. There are no memory leaks in your project.

You might ask yourself then why on earth does heaptrace display a message when there are no leaks. The answer to that is simple: You either make use of heaptrace or you don't.

By default heaptrace outputs its collected information. You can change that behaviour by setting the variable GlobalSkipIfNoLeaks (https://www.freepascal.org/docs-html/rtl/heaptrc/globalskipifnoleaks.html) to true on your program startup (form.create should be ok).

afair it might be that you have a Lazarus with an older FPC compiler, in which case this variable is not available (so that you are unable to influence this behaviour of heaptrace). What you could  do then is opt for upgrading your Lazarus installation.
Title: Re: how to get the original filedate not date modifyed
Post by: mai on November 09, 2017, 07:51:57 pm
maybe use statx xstat (search my other post)

make syscall to use it
Title: Re: how to get the original filedate not date modifyed
Post by: ASerge on November 09, 2017, 10:58:51 pm
But Windows stores this date in the field: date taken (rightclick on a JPG in explorer --- Properties -- Details  -- Title: Origin) and makes it to its (main)date.  -- or look at my printscreen above.
Get any property from the shell!
Code: Pascal  [Select][+][-]
  1. {$APPTYPE CONSOLE}
  2. program Project1;
  3.  
  4. uses Windows, SysUtils, ActiveX, ShlObj;
  5.  
  6. function GetShellFolder2(const Dir: UnicodeString; out Intf: IShellFolder2): Boolean;
  7. var
  8.   DesktopFolder: IShellFolder;
  9.   DirPIDL: PItemIDList = nil;
  10. begin
  11.   Result := Succeeded(SHGetDesktopFolder(DesktopFolder)) and
  12.     Succeeded(DesktopFolder.ParseDisplayName(0, nil, PWideChar(Dir),
  13.       ULONG(nil^), DirPIDL, ULONG(nil^))) and
  14.     Succeeded(DesktopFolder.BindToObject(DirPIDL, nil, IID_IShellFolder2, Intf));
  15.   CoTaskMemFree(DirPIDL);
  16. end;
  17.  
  18. function GetFileProperty(const FileName: string; const Column: SHColumnID;
  19.   out Value: OleVariant): Boolean;
  20. var
  21.   DirFolder: IShellFolder2;
  22.   FilePIDL: PItemIDList = nil;
  23.   WFileName: UnicodeString;
  24. begin
  25.   WFileName := Utf8Decode(FileName);
  26.   Result := False;
  27.   if GetShellFolder2(ExtractFileDir(WFileName), DirFolder) then
  28.   begin
  29.     Result := Succeeded(DirFolder.ParseDisplayName(0, nil,
  30.       PWideChar(ExtractFileName(WFileName)),
  31.         ULONG(nil^), FilePIDL, ULONG(nil^))) and
  32.       Succeeded(DirFolder.GetDetailsEx(FilePIDL, Column, @Value));
  33.     CoTaskMemFree(FilePIDL);
  34.   end;
  35. end;
  36.  
  37. const
  38.   CFileName = 'c:\Path\Your favorite file.JPG';
  39.   // All available values see in propkey.h in SDK
  40.   CColumnPhotoDateTaken: SHColumnID = ( // PKEY_Photo_DateTaken
  41.     fmtid: '{14B81DA1-0135-4D31-96D9-6CBFC9671A99}'; // FMTID_ImageProperties
  42.     pid: 36867);
  43. var
  44.   Value: OleVariant;
  45. begin
  46.   CoInitialize(nil);
  47.   if GetFileProperty(CFileName, CColumnPhotoDateTaken, Value) then
  48.   begin
  49.     Writeln('Photo Date Taken at UTC: ', Value);
  50.   end;
  51.   Readln;
  52. end.
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 10, 2017, 12:01:06 am
hello molly

you where right GlobalSkipIfNoLeaks is not known by lazarus-1.6.4-fpc-3.0.2-win64.exe.

Even it is the latest Version on official Lazarus-Site. So I searched the net and found:

Lazarus-1.8  RC5  (i did not try)
Lazarus-1.9-56259_fpc-3.1.1-37548M_20171103-1327.7z (google)  -> this i unzipped and messed up my installation. (compiler missing and so on...)

Now I just removed my installation.

So how do I get a installation that is up to date? Or is there one coming on official site soon?
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 10, 2017, 12:04:22 am
hi mai

i just found this one: Linux / Re: new kernel function fstatx() in Kern 4.11

Can you be a little more specific - Im rather new at Lazarus and pascal and working with Windows 7.
Title: Re: how to get the original filedate not date modifyed
Post by: molly on November 10, 2017, 12:35:32 am
hello molly

you where right GlobalSkipIfNoLeaks is not known by lazarus-1.6.4-fpc-3.0.2-win64.exe.
Eh... that's weird  %)

FPC 3.0.2 should be enough (i use that version as well).


Quote
So how do I get a installation that is up to date? Or is there one coming on official site soon?
The 1.8 release should become a final release pretty soon. But somehow everything related to this release seems to be a bit ... well ... out of the ordinary. So, please don't hold that against me in case it will take another year before reaching final release :D

You should be good to go with your initial installation of lazarus-1.6.4-fpc-3.0.2-win64.exe. I would recommend to verify this with someone else first as i'm unable to verify myself at the moment.

I apologize for recommending to upgrade. I more or less expected that you would mention your current version first, before actually performing an upgrade. In hindsight that seem to have caused more trouble than you bargained for  :-[

Are you able to remove your current installation and re-install lazarus-1.6.4-fpc-3.0.2-win64.exe ? If not then please feel free to mention the errors you are encountering, so that we're able to solve them for you.
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 10, 2017, 03:18:08 am
HEUREKA

... I found it.... I placed the directive in the project as shown....

Code: Pascal  [Select][+][-]
  1. program BaseSample;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   {$IFDEF UNIX}{$IFDEF UseCThreads}
  7.   cthreads,
  8.   {$ENDIF}{$ENDIF}
  9.   Interfaces, // this includes the LCL widgetset
  10.   Forms, ureadexif
  11.   { you can add units after this };
  12.  
  13. {$R *.res}
  14.  
  15. begin
  16.   RequireDerivedFormResource:=True;
  17.   Application.Initialize;
  18.   Application.CreateForm(TForm1, Form1);
  19.   Application.Run;
  20.   GlobalSkipIfNoLeaks := true;
  21.   UseHeapTrace := false;
  22. end.
  23.  


still hoping to get an examle of some (any) API-Call to windows and where to place it, so I could try to get the datetaken property of windows

(I am still a newbee but try to improove)
Title: Re: how to get the original filedate not date modifyed
Post by: molly on November 10, 2017, 03:57:34 am
HEUREKA
Glad that you was able to find it.

Quote
still hoping to get an examle of some (any) API-Call to windows and where to place it, so I could try to get the datetaken property of windows
Look at reply #15 from ASerge. That is using activeX shell object api to retrieve the (column) information.
Title: Re: how to get the original filedate not date modifyed
Post by: ratmalwer on November 10, 2017, 05:15:12 am
Thanks all for your help.... Reading though the web and asking on other platforms it seems I am wrong with my oppinion that the datetaken is a property witch can be accessed directly by API / NTFS... In other words, it ist actually needed to open each file to get its Exif... as I was told earlyer...
so i declare this thead as closed....
Title: Re: how to get the original filedate not date modifyed
Post by: Mike.Cornflake on November 11, 2017, 08:33:24 pm
Last time I read EXIF I was a Delphi programmer.  Back then I used the dEXIF library which I was quite happy with.  Looking around I see this has been translated to Lazarus...

https://github.com/cutec-chris/dexif
Title: Re: how to get the original filedate not date modifyed
Post by: JuhaManninen on November 11, 2017, 10:22:29 pm
https://github.com/cutec-chris/dexif
The ReadMe says the license was switched to LGPL with author's permission.
The Copyright.txt however explains a very different license. Somebody should tell them to update it.
Title: Re: how to get the original filedate not date modifyed
Post by: Mike.Cornflake on November 11, 2017, 10:28:21 pm
At the top of Copyright.txt
Quote
----------------------------------
This port of dEXIF to Lazarus/Freepascal is accepted in July 2017 by the Copyright-Owner
----------------------------------
Hello Andreas ,
  It is possible, all I ask is attribution somewhere in your documentation or source. 
  I will indeed look at updating the license terms but wanted to let you know it's OK to proceed so you don't have to wait.
Thanks,   

Gerry McGuire dEXIF author.

---------------------------------

So, it looks like Gerry is aware of this and updating the license is already on his TODO.
TinyPortal © 2005-2018