JPEG画像ファイルの作成日時を修正して必要に応じてExif内部のGPSデータを削除するFMXなプログラム

ようやく最終型(の一つ前)を提示します。

まずは単一ファイルをOpenDialogで選択して処理するプログラム。フォームから、

このようにTButtonx1,TLabelx1,TCheckboxx3,TOpenDialogを配置。適宜Nameを変更して、Unit1.hは、

//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.Controls.Presentation.hpp>
#include <FMX.Dialogs.hpp>
#include <FMX.Memo.hpp>
#include <FMX.Memo.Types.hpp>
#include <FMX.ScrollBox.hpp>
#include <FMX.StdCtrls.hpp>
#include <FMX.Types.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TOpenDialog *OpenDialog1;
	TButton *Open;
	TMemo *Memo1;
	TLabel *Label1;
	TCheckBox *NoDumpTables;
	TCheckBox *FixDateTime;
	TCheckBox *SnifGPSInfo;
	void __fastcall OpenClick(TObject *Sender);
private:	// ユーザー宣言
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif

続いて、Unit1.cppは、

//---------------------------------------------------------------------------

#include <fmx.h>
#pragma hdrstop

#include "exif.h"
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.fmx"


extern AnsiString getdatetime(void *array);
AnsiString datetime;

void PRINTF(char **ms, const char *fmt, ...) {
	AnsiString output;
    char buf[4096];
    char *p = NULL;
    int len, cnt;
    va_list args;
    va_start(args, fmt);
    cnt = vsnprintf(buf, sizeof(buf)-1, fmt, args);
    if (!ms) {
		output.sprintf("%s\n", buf);
		//Form1->Memo1->Lines->Add(output);
		if( !(Form1->NoDumpTables->IsChecked) ){
			Form1->Memo1->Lines->Text += output;
			Form1->Memo1->Lines->Text += L"\n";
		}
		return;
	}
	else if (*ms) {
		len = (int)(strlen(*ms) + cnt + 1);
		p = (char*)malloc(len);
		strcpy(p, *ms);
		strcat(p, buf);
		free(*ms);
	} else {
		len = cnt + 1;
		p = (char*)malloc(len);
		strcpy(p, buf);
	}
	*ms = p;
	va_end(args);
}

int sample_removeGPSData(const char *srcJpgFileName,const char *outJpgFileName)
{
	int sts, result;
	void **ifdTableArray = createIfdTableArray(srcJpgFileName, &result);

	if (!ifdTableArray) {
		printf("createIfdTableArray: ret=%d\n", result);
		return result;
	}

	// remove GPS IFD and 1st IFD if exist
	removeIfdTableFromIfdTableArray(ifdTableArray, IFD_GPS);
	removeIfdTableFromIfdTableArray(ifdTableArray, IFD_1ST);

	sts = updateExifSegmentInJPEGFile(srcJpgFileName, outJpgFileName, ifdTableArray);
	if (sts < 0) {
		printf("updateExifSegmentInJPEGFile: ret=%d\n", sts);
	}
	freeIfdTableArray(ifdTableArray);
	return sts;
}




TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}

bool SetFileCreationTime(String filePath, TDateTime dt) {
	// Convert SYSTEMTIME to FILETIME

	SYSTEMTIME  newTime;

	DateTimeToSystemTime(dt,newTime);

	FILETIME ft;
	if (!SystemTimeToFileTime(&newTime, &ft)) {
		return false;
	}

	// Open file with write attributes permission
	HANDLE hFile = CreateFileW(
		filePath.w_str(),
		FILE_WRITE_ATTRIBUTES,
		FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);

	if (hFile == INVALID_HANDLE_VALUE) {
		return false;
	}

	// Set creation time (leave last access and write times unchanged)
	BOOL result = SetFileTime(hFile, &ft, NULL, NULL);

	CloseHandle(hFile);
	return (result != 0);
}

//---------------------------------------------------------------------------
void __fastcall TForm1::OpenClick(TObject *Sender)
{
	String prefix = "nogps_";
	String fullpath;
	String filename;
	String filepath;
	String newname;

	if( OpenDialog1->Execute()){
		fullpath = OpenDialog1->FileName;
		//Memo1->Lines->Add("fullpath " + fullpath);

		void **ifdArray;
		TagNodeInfo *tag;
		int i, result;

		ifdArray = createIfdTableArray(AnsiString(fullpath).c_str(),&result);

		for( i = 0 ; ifdArray[i] != NULL ; i++ ){
			dumpIfdTable(ifdArray[i]);
		}

//mpIfdTable(ifdArray[0]);



		if( FixDateTime->IsChecked ){
			//Form1->Memo1->Lines->Add("datetime is " + datetime);
			TDateTime dt;
			TFormatSettings fs;
			fs = TFormatSettings::Create(); // Initialize with defaults
			//fs.DateSeparator = ':';
			fs.ShortDateFormat = "yyyy:mm:dd";

			dt = StrToDateTime(datetime,fs);
			if( !SetFileCreationTime(fullpath, dt) )
				ShowMessage("file creation date set failed");

		}





		if( SnifGPSInfo->IsChecked ){
			filename = ExtractFileName(fullpath);
			//Memo1->Lines->Add("Extracted filename " + filename);

			filepath = ExtractFilePath(fullpath);
			//Memo1->Lines->Add("Extracted filepath " + filepath);

			newname = filepath + prefix + filename;
			//Memo1->Lines->Add("newname is " + newname);
		// AnsiString(fname).c_str()
			sample_removeGPSData(AnsiString(fullpath).c_str(), AnsiString(newname).c_str());

			if( FixDateTime->IsChecked ){// should again set file creation time for output
				//Form1->Memo1->Lines->Add("datetime is " + datetime);
				TDateTime dt;
				TFormatSettings fs;
				fs = TFormatSettings::Create(); // Initialize with defaults
				//fs.DateSeparator = ':';
				fs.ShortDateFormat = "yyyy:mm:dd";

				dt = StrToDateTime(datetime,fs);
				if( !SetFileCreationTime(newname, dt) )
					ShowMessage("file creation date set failed");

		}


			//Memo1->Lines->Add("datetime " + datetime);
		}
	}
}
//---------------------------------------------------------------------------

起動すると、

となるので、作成日時をExif内部の撮影日時にセットするならば、FixDateTimeにチェック(デフォルト)、Exif内部のGPS情報を切るのであれば、SnifGPSInfoにチェック(これまたデフォルト)、Exifテーブルを表示しないのであれば、NoDumpTablesにチェック(デフォルト)で“Open”します。ファイルを選択すると、ファイル処理して、Exif情報をいじる場合は、

IMG_3197.JPEG

がオリジナルのファイル名だとすると、頭にprefix=nogps_を付けた新しいファイルを書き出します。

nogps_IMG_3197.JPEG

つまりこんな感じで、

これを以前に紹介したexif-check.orgへ投げると、

GPS情報が削除されているのがわかります。exiv2を別プロセスで起動して対処する以前のやり方よりexiv2のパスの指定とかのトラブルが少ないだけ具合はよろしいですね。Drag and Drop(ファイルと一階層のフォルダーを含む)対応は別記事で、

コメント