|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Чтение данных Exif файла jpg
Прошу помочь с решением следующей проблемы. Я написал функцию FileSetDateExif, устанавливающую время модификации файла JPG равным времени его создания 'CreateDate', прописанному в Exif. Функция необходима для сведения в один временной ряд уже модифицированных файлов JPG от разных фотоаппаратов.
Выполнение данной функции сопровождается возникновением исключения "Project … raised exception class EExternalException with message ‘External exception c0000002’" при установке времени каждого файла. Проблему частично решил обрамлением вызова функции конструкцией "try ... except" и установкой опции игнорирования данного сообщения. Однако видимо есть еще иные побочные эффекты упомянутого выше исключения, так как после вызова написанной функции при работе встроенного мною в оболочку моего программного комплекса медиаплеера стали возникать невиданные ранее прерывания от access violation до полного вылета программы. Работу функции исследовал под Windows 7 x64, Delphi 2010. Путем последовательного комментирования операторов установил, что возникновение исключения при выполнении оператора SetFileTime(hndl,nil,nil,@aFileTime) происходит если ранее выполнялся оператор WicDecoder.GetFrame(0,FrameDecode). Буду благодарен за любой совет, так как собственная фантазия уже исчерпалась. Также буду благодарен за любое прояснение ситуации по характеристике возникающего исключения. Ответ на вопрос дан lmikle : "вызывать _release напрямую не рекомендуется... достаточно просто ... присвоить Nil". Приведенный ниже код исправлен в соответствии с данной рекомендацией и теперь работает безукоризненно. Код:
unit uHDDCam; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, MMSystem, Math, Mask, ExtCtrls, ComCtrls, Buttons, uChildAis, ToolWin, DateUtils, wincodec, ComObj, ValEdit, ActiveX; ......................................................... var fmHDDCam: TfmHDDCam; function TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation: PTimeZoneInformation; var lpLocalTime, lpUniversalTime: TSystemTime): BOOL; stdcall; function SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation: PTimeZoneInformation; var lpUniversalTime,lpLocalTime: TSystemTime): BOOL; stdcall; implementation uses ....................................................; function TzSpecificLocalTimeToSystemTime; external kernel32 name 'TzSpecificLocalTimeToSystemTime'; function SystemTimeToTzSpecificLocalTime; external kernel32 name 'SystemTimeToTzSpecificLocalTime'; {$R *.dfm} function FileSetDateExif : Integer; var WicFactory : IWICImagingFactory; WicDecoder : IWICBitmapDecoder; FrameDecode : IWICBitmapFrameDecode; mdReader : IWICMetadataQueryReader; Prop : TPropVariant; hndl : THandle; NewTime : TDateTime; tzi : TTimeZoneInformation; LocalTime,UniversalTime : TSystemTime; aFileTime : TFileTime; begin Result:=0; hndl:=CreateFile(PChar(LastSelectImageName),GENERIC_READ or GENERIC_WRITE, 0,nil,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0); if hndl=THandle(-1) then Result:=GetLastError {INVALID_HANDLE_VALUE} else begin try WicFactory:=CreateComObject(CLSID_WICImagingFactory) as IWICImagingFactory; WicFactory.CreateDecoderFromFileHandle(hndl,TGUID(nil^),WICDecodeMetadataCacheOnDemand,WicDecoder); WicFactory:=nil; {выполнение следующего оператора приводит к ошибке при записи времени файла!!!} WicDecoder.GetFrame(0,FrameDecode); WicDecoder:=nil; if FrameDecode.GetMetadataQueryReader(mdReader)<>S_OK then begin ShowMessage('Не могу прочесть Exif '+LastSelectImageName); System.Exit; end; FrameDecode:=nil; zeroMemory(@Prop,SizeOf(Prop)); mdReader.GetMetadataByName('/xmp/CreateDate',prop); mdReader:=nil; s:=String(Prop.pwszVal); s:=BackDateToRight(s); NewTime:=StrToDateTime(s); GetTimeZoneInformation(tzi); DateTimeToSystemTime(NewTime,LocalTime); {локальное время файла пересчитывается с учетом часового пояса} TzSpecificLocalTimeToSystemTime(@tzi,LocalTime,UniversalTime); SystemTimeToFileTime(UniversalTime,aFileTime); if SetFileTime(hndl,nil,nil,@aFileTime) then System.Exit; Result:=GetLastError; finally FileClose(hndl); end; {finally} end; {hndl<>THandle(-1)} end; {FileSetDateExif} Последний раз редактировалось tsa, 13.03.2017 в 02:34. |
#2
|
|||
|
|||
Возможно, библиотека блокирует файл, да так, что даже api функция не может с ним работать. Варианты:
1. Закрывать файл сразу после того, как считал данные, и убивать COM-объект, а только потом уже ставить время. 2. Найти другую библиотеку чтения EXIF. Видел где-то в исходниках такую. Там полностью Delphi-код, никаких сторонних объектов не используется. |
#3
|
|||
|
|||
Цитата:
WicFactory.CreateDecoderFromFileHandle(hndl,TGUID( nil^),WICDecodeMetadataCacheOnDemand,WicDecoder); WicDecoder._Release; WicFactory._Release; с надеждой, что испорченное место "перепашется" заново как надо, но получил access violation на операторе WicDecoder._Release; хотя декодер только создался предыдущим оператором и не мог быть запорчен. Цитата:
Последний раз редактировалось tsa, 12.03.2017 в 23:29. |
#4
|
|||
|
|||
ну, например, вот есть:
https://delphihaven.wordpress.com/ccr-exif/ Да, кстати, вызывать _release напрямую не рекомендуется. Иначе объект может "помереть" внезапно. Если уж так надо заставить COM-объект "испариться", то достаточно просто переменно присвоить Nil. |
Этот пользователь сказал Спасибо lmikle за это полезное сообщение: | ||
tsa (13.03.2017)
|
#5
|
|||
|
|||
Цитата:
Цитата:
Последний раз редактировалось tsa, 13.03.2017 в 02:37. |