目次
サンプル・プログラム
photomapwin.msi | インストーラ |
bin/photomapwin.exe | 実行プログラム本体 |
bin/cwebpage.dll bin/libcurl.dll | 実行時に必要になるDLL |
bin/etc/help.chm | ヘルプ・ファイル |
sour/photomapwin.cpp | ソース・プログラム |
sour/resource.h | リソース・ヘッダ |
sour/resource.rc | リソース・ファイル |
sour/application.ico | アプリケーション・アイコン |
sour/mystrings.cpp | 汎用文字列処理関数など(ソース) |
sour/mystrings.h | 汎用文字列処理関数など(ヘッダ) |
sour/pahooGeocode.cpp | 住所・緯度・経度に関わるクラス(ソース) |
sour/pahooGeocode.hpp | 住所・緯度・経度に関わるクラス(ヘッダ) |
sour/apikey.cpp | APIキーの管理(ソース) |
sour/apikey.hpp | APIキーの管理(ヘッダ) |
sour/TinyEXIF.h | TinyEXIFソース・プログラム |
sour/TinyEXIF.cpp | TinyEXIFソース・プログラム |
sour/tinyxml2.h | tinyxml2ソース・プログラム |
sour/tinyxml2.cpp | tinyxml2ソース・プログラム |
バージョン | 更新日 | 内容 |
---|---|---|
1.5.5 | 2024/03/23 | 使用ライブラリ更新 |
1.5.4 | 2023/09/20 | 使用ライブラリ更新 |
1.5.3 | 2023/07/02 | 使用ライブラリ更新 |
1.5.2 | 2023/03/18 | 使用ライブラリ更新 |
1.5.1 | 2022/11/20 | 使用ライブラリ更新 |
バージョン | 更新日 | 内容 |
---|---|---|
1.6.0 | 2023/07/02 | getPointsGSI()メソッド追加 |
1.5 | 2022/09/03 | デバッグコード埋め込み |
1.4 | 2021/05/01 | makeMapLeaflet() 引数追加 |
1.3 | 2021/03/07 | tokyo_wgs84(), wgs84_tokyo()メソッド追加 |
1.2 | 2020/12/20 | leafletスクリプトの参照URL変更 |
バージョン | 更新日 | 内容 |
---|---|---|
1.12 | 2021/01/31 | readWebContents() 引数post追加 |
1.11 | 2020/10/17 | htmlspecialchars() 追加 |
1.1 | 2020/10/17 | GetVersion2()追加,readWebContents() 引数ua追加 |
1.01 | 2020/10/03 | setClipboardData() bug-fix |
1.0 | 2020/09/22 |
使用ライブラリ
また、地図表示にWebブラウザ・コントロールを利用するため、オープンソースの cwebpage.dll および webbrowser.h が必要になる。cwebpage.dll は [https://www.codeproject.com/Articles/3365/Embed-an-HTML-control-in-your-own-window-using-pla] から、webbrowser.h は Digital Point から、それぞれダウンロードできる。
Exif情報を解釈するのに、Seacave氏による TinyEXIF と、このモジュールが呼び出す inyxml2 を、https://github.com/cdcseacave/TinyEXIF と https://github.com/leethomason/tinyxml2 から、それぞれダウンロードする。
リソースの準備
Eclipse を起動し、新規プロジェクト photomapwin を用意する。
ResEdit を起動し、resource.rc を用意する。
Eclipse に戻り、ソース・プログラム "photomapwin.cpp" を追加する。
リンカー・フラグを -Wl,--enable-stdcall-fixup -mwindows -lgdiplus -lole32 -static -lstdc++ -lgcc -lwinpthread -lcurl -lssl "(任意のパス)\libcurl.dll" "C:\Windows\system32\GdiPlus.dll" "(任意のパス)\cwebpage.dll" に設定する。
解説:定数など
41: // 定数など ==================================================================
42: #define APPNAME "photomapwin" //アプリケーション名
43: #define APPNAMEJP "撮影場所をマッピング" //アプリケーション名(日本語)
44: #define APPVERSION "1.5.5" //バージョン
45: #define APPYEAR "2020-2024" //作成年
46: #define REFERENCE "https://www.pahoo.org/e-soul/webtech/cpp01/cpp01-13-01.shtm" // 参考サイト
47:
48: //char*バッファサイズ
49: #define SIZE_BUFF 512
50:
51: //ListViewItemの最大文字長:変更不可
52: #define MAX_LISTVIEWITEM 258
53:
54: //AppDataのフルパス
55: TCHAR MyPath[MAX_PATH];
56: #define MYAPPDATA "photomapwin"
57:
58: //ヘルプ・ファイル
59: #define HELPFILE ".\\etc\\help.chm"
60:
61: //デフォルト保存ファイル名
62: #define SAVEFILE "photomapwin.csv"
63:
64: //エラー・メッセージ格納用
65: string ErrorMessage;
66:
67: //現在のインターフェイス
68: HINSTANCE hInst;
69:
70: //アプリケーション・ウィンドウ
71: HWND hParent;
72:
73: //アプリケーション・ウィンドウ位置
74: unsigned hParent_X, hParent_Y;
75:
76: //ブラウザ・コントロール
77: WebBrowser wBrowser;
78:
79: //pahooGeocodeオブジェクト
80: pahooGeocode* pGC;
81:
82: //マップID
83: #define MAP_ID "map_id"
84: //地図の大きさ
85: #define MAP_WIDTH 630 //地図の幅(ピクセル)
86: #define MAP_HEIGHT 325 //地図の高さ(ピクセル)
87: //経度・緯度(初期値)
88: #define DEF_LONGITUDE 139.766667
89: double Longitude = DEF_LONGITUDE;
90: #define DEF_LATITUDE 35.681111
91: double Latitude = DEF_LATITUDE;
92: //地図拡大率(初期値)
93: #define DEF_ZOOM 13
94: int Zoom = DEF_ZOOM;
95: //地図の種類(初期値)
96: #define DEF_MAPTYPE "GSISTD"
97: string Maptype = DEF_MAPTYPE;
解説:データ構造
121: //Exif格納クラス
122: #define SIZE_EXIFS 100 //最大格納数
123: class _Exif {
124: public:
125: wstring label = L""; //データ項目
126: wstring data = L""; //データ本体
127: } Exif[SIZE_EXIFS];
解説:フルパスからファイル名を取り出す
343: /**
344: * ファイル名(フルパス)からファイル名(拡張子を除く)を取り出す
345: * @param wstring path ファイル名(フルパス)
346: * @return wstring ファイル名(拡張子を除く)
347: */
348: wstring wgetBasename(wstring path) {
349: wstring basename = L"";
350:
351: //最後のディレクトリ識別子を探す
352: size_t pos = path.rfind(_SW("\\"));
353: if (pos == string::npos) {
354: return basename;
355: }
356: //ファイル名+拡張子
357: wstring fname = path.substr(pos + 1);
358:
359: //拡張子を除く
360: pos = fname.rfind(_SW("."));
361: if (pos == string::npos) {
362: basename = fname;
363: } else {
364: basename = fname.substr(0, pos);
365: }
366: return basename;
367: }
Boost C++ライブラリにも同様関数があるが、うまくコンパイルできなかったので、自力でコーディングした。シフトJIS文字列では、ディレクトリ識別子 ¥(\0x5C)を含む全角文字があるため、ファイル名はワイド文字列に変換して処理する。
解説:画像ファイルを読み込む
503: /**
504: * 画像ファイルの表示
505: * @param HWND hWnd 表示するウィンドウ・ハンドル
506: * @param const char *fname 画像ファイル名
507: * @return bool TRUE:表示成功/FALSE:失敗
508: */
509: bool onPaint(HWND hWnd, const char *fname) {
510: HDC hdc;
511: PAINTSTRUCT ps;
512: static HDC hdcBMP;
513: static int ix,iy;
514: int sx, sy;
515: RECT rect;
516: bool ret = TRUE;
517:
518: //画像ファイル読み込み
519: hdc = GetDC(hWnd);
520: if(loadImageOnMemory((TCHAR*)fname, &hdcBMP, hdc, &ix, &iy) == FALSE) {
521: ErrorMessage = "画像ファイル " + (string)fname + " の読み込みに失敗";
522: return FALSE;
523: }
524: InvalidateRect(hWnd, 0, TRUE);
525: hdc = BeginPaint(hWnd, &ps);
526: GetClientRect(hWnd, &rect);
527:
528: //領域クリア
529: HPEN hNewPen = (HPEN)CreatePen(PS_INSIDEFRAME, 4, RGB(255, 255, 255));
530: HPEN hOldPen = (HPEN)SelectObject(hdc,hNewPen);
531: HBRUSH hNewBrush = (HBRUSH)CreateSolidBrush(RGB(255, 255, 255));
532: HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hNewBrush);
533: Rectangle(hdc, 0, 0, rect.right, rect.bottom);
534: DeleteObject(SelectObject(hdc, hOldBrush));
535: DeleteObject(SelectObject(hdc, hOldPen));
536:
537: //縮小表示
538: reSizeImage(&sx, &sy, ix, iy, (rect.right - rect.left), (rect.bottom - rect.top));
539: SetStretchBltMode(hdc, HALFTONE);
540: StretchBlt(hdc, 0, 0, sx, sy, hdcBMP, 0, 0, ix, iy, SRCCOPY);
541: EndPaint(hWnd, &ps);
542: ReleaseDC(hWnd, hdc);
543:
544: return ret;
545: }
424: /**
425: * 画像ファイルをGDI+を使って読み込む
426: * @param TCHAR* szFile 画像ファイル名
427: * @param HDC* hdcBMP オフスクリーン用デバイスコンテキストを格納
428: * @param HDC hdc デバイスコンテキスト
429: * @param int* ix, iy 読み込んだ画像の横・縦ピクセル数
430: * @return なし
431: */
432: bool loadImageOnMemory(TCHAR* szFile, HDC* hdcBMP, HDC hdc, int* ix, int* iy) {
433: Image* imageP;
434: WCHAR wTitle[MAX_PATH];
435: BITMAPINFOHEADER bmih;
436: HBITMAP hBitmap;
437: BYTE *pBits;
438:
439: //読み込むファイル名
440: MultiByteToWideChar(932, 0, szFile, -1, wTitle, sizeof(wTitle) / sizeof(TCHAR));
441: imageP = Bitmap::FromFile(wTitle);
442: if (imageP == 0) {
443: *ix = 0;
444: *iy = 0;
445: *hdcBMP = 0;
446: return FALSE;
447: }
448:
449: bmih.biSize = sizeof(bmih);
450: bmih.biWidth = *ix = imageP->GetWidth();
451: bmih.biHeight = *iy = imageP->GetHeight();
452: bmih.biPlanes = 1;
453: bmih.biBitCount = 32;
454: bmih.biCompression = BI_RGB;
455: bmih.biSizeImage = 0;
456: bmih.biXPelsPerMeter = 0;
457: bmih.biYPelsPerMeter = 0;
458: bmih.biClrUsed = 0;
459: bmih.biClrImportant = 0;
460: hBitmap = CreateDIBSection(NULL, (BITMAPINFO*)&bmih, 0, (void**)&pBits, NULL, 0);
461: if (pBits == NULL) {
462: ErrorMessage = "メモリ不足";
463: DeleteObject(hBitmap);
464: delete imageP;
465: *ix = 0;
466: *iy = 0;
467: return FALSE;
468: }
469: *hdcBMP = CreateCompatibleDC(hdc);
470: // HOldBitmap = (HBITMAP)SelectObject(*hdcBMP, hBitmap);
471: SelectObject(*hdcBMP, hBitmap);
472: Graphics MyGraphics(*hdcBMP);
473: MyGraphics.DrawImage(imageP, 0, 0, imageP->GetWidth(), imageP->GetHeight());
474: delete imageP;
475:
476: return TRUE;
477: }
479: /**
480: * 縦横比を保った画像サイズ計算
481: * @param int* sx, sy 変換後画像サイズを格納
482: * @param int px, py 元画像の縦横サイズ
483: * @param int dx, dy 変換後領域の縦横サイズ
484: * @return なし
485: */
486: void reSizeImage(int* sx, int* sy, int px, int py, int dx, int dy) {
487: double pxy = double(px) / double(py); //元画像の横縦比
488: double dxy = double(dx) / double(dy); //変換後の横縦比
489: int dx2, dy2;
490:
491: //横を基準に縦を縮小
492: if(pxy > dxy) {
493: dx2 = dx;
494: dy2 = (int)double(dx / pxy);
495: } else {
496: dy2 = dy;
497: dx2 = (int)double(dy * pxy);
498: }
499: *sx = dx2;
500: *sy = dy2;
501: }
まず、GDI+ を使って画像データをメモリに読み込むのがユーザー関数 loadImageOnMemory である。
読み込んだ画像の縦横のピクセル数を取り出し、ユーザー関数 reSizeImage を使って、サムネイル領域のサイズに縦横比が合うように縮小する。メモリ上の画像データを縮小してサムネイル領域に表示するのは StretchBlt 関数である。
縮小したら、
解説:Exif情報を取得する
548: /**
549: * 画像ファイルを開いてExif情報を取得する(実作業)
550: * @param const char *fname 保存ファイル名
551: * @return bool TRUE:取得成功/FALSE:失敗
552: */
553: bool loadExif(const char *fname) {
554: double f;
555: string ss;
556: char buff[SIZE_BUFF + 1];
557: bool ret = TRUE;
558:
559: //画像ファイルのオープン
560: EXIFStreamFile stream(fname);
561: if (! stream.IsValid()) {
562: ErrorMessage = "画像ファイル " + (string)fname + " の読み込みに失敗";
563: return FALSE;
564: }
565: //Exif情報の取得
566: TinyEXIF::EXIFInfo imageEXIF(stream);
567:
568: //Exif情報を配列Exifへ代入
569: //初期化
570: for (int i = 0; i < SIZE_EXIFS; i++) {
571: Exif[i].label = L"";
572: Exif[i].data = L"";
573: }
574: //代入
575: int i = 0;
576: //位置情報
577: if (imageEXIF.GeoLocation.hasLatLon()) {
578: Exif[i].label = _SW("緯度(度)");
579: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.Latitude));
580: Latitude = imageEXIF.GeoLocation.Latitude;
581: i++;
582: Exif[i].label = _SW("経度(度)");
583: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.Longitude));
584: Longitude = imageEXIF.GeoLocation.Longitude;
585: i++;
586: } else {
587: ErrorMessage = "画像ファイル " + (string)fname + " に位置情報が存在しない";
588: ret = FALSE;
589: }
590: if (imageEXIF.GeoLocation.hasAltitude()) {
591: Exif[i].label = _SW("基準高度");
592: switch (imageEXIF.GeoLocation.AltitudeRef) {
593: case 0:
594: Exif[i].data = _SW("海抜");
595: break;
596: case 1:
597: Exif[i].data = _SW("海面下");
598: break;
599: default:
600: Exif[i].data = _SW("不明");
601: break;
602: }
603: i++;
604: Exif[i].label = _SW("高度(メートル)");
605: snprintf(buff, SIZE_BUFF, "%.1f", imageEXIF.GeoLocation.Altitude);
606: Exif[i].data = _SW((string)buff);
607: i++;
608: }
609: if (! imageEXIF.GeoLocation.GPSMapDatum.empty()) {
610: Exif[i].label = _SW("測地系");
611: Exif[i].data = _SW(imageEXIF.GeoLocation.GPSMapDatum);
612: i++;
613: }
614: //画像情報
615: if (imageEXIF.ImageWidth || imageEXIF.ImageHeight) {
616: Exif[i].label = _SW("画像の幅(ピクセル)");
617: Exif[i].data = _SW(to_string(imageEXIF.ImageWidth));
618: i++;
619: Exif[i].label = _SW("画像の高さ(ピクセル)");
620: Exif[i].data = _SW(to_string(imageEXIF.ImageHeight));
621: i++;
622: }
623: if (imageEXIF.RelatedImageWidth || imageEXIF.RelatedImageHeight) {
624: Exif[i].label = _SW("画像の幅(ピクセル)");
625: Exif[i].data = _SW(to_string(imageEXIF.RelatedImageWidth));
626: i++;
627: Exif[i].label = _SW("画像の高さ(ピクセル)");
628: Exif[i].data = _SW(to_string(imageEXIF.RelatedImageHeight));
629: i++;
630: }
631: if (! imageEXIF.ImageDescription.empty()) {
632: Exif[i].label = _SW("画像タイトル");
633: Exif[i].data = _SW(imageEXIF.ImageDescription);
634: i++;
635: }
636: if (! imageEXIF.Make.empty() || ! imageEXIF.Model.empty()) {
637: Exif[i].label = _SW("カメラのメーカー名");
638: Exif[i].data = _SW(imageEXIF.Make);
639: i++;
640: Exif[i].label = _SW("カメラのモデル名");
641: Exif[i].data = _SW(imageEXIF.Model);
642: i++;
643: }
644: if (! imageEXIF.SerialNumber.empty()) {
645: Exif[i].label = _SW("シリアル番号");
646: Exif[i].data = _SW(imageEXIF.SerialNumber);
647: i++;
648: }
649: if (imageEXIF.Orientation) {
650: Exif[i].label = _SW("画像方向");
651: switch (imageEXIF.Orientation) {
652: case 1:
653: Exif[i].data = _SW("左上");
654: break;
655: case 3:
656: Exif[i].data = _SW("右下");
657: break;
658: case 6:
659: Exif[i].data = _SW("右上");
660: break;
661: case 8:
662: Exif[i].data = _SW("左下");
663: break;
664: default:
665: Exif[i].data = _SW("不明");
666: break;
667: }
668: i++;
669: }
670: if (imageEXIF.XResolution || imageEXIF.YResolution || imageEXIF.ResolutionUnit) {
671: ss = "";
672: switch (imageEXIF.ResolutionUnit) {
673: case 2:
674: ss = "(インチ)";
675: break;
676: case 3:
677: ss = "(センチ)";
678: break;
679: default:
680: ss = "";
681: break;
682: }
683: Exif[i].label = _SW("幅の解像度" + ss);
684: Exif[i].data = _SW(to_string((int)imageEXIF.XResolution));
685: i++;
686: Exif[i].label = _SW("高さの解像度" + ss);
687: Exif[i].data = _SW(to_string((int)imageEXIF.YResolution));
688: i++;
689: }
690: if (imageEXIF.BitsPerSample) {
691: Exif[i].label = _SW("画像のビットの深さ");
692: Exif[i].data = _SW(to_string(imageEXIF.BitsPerSample));
693: i++;
694: }
695: if (! imageEXIF.Software.empty()) {
696: Exif[i].label = _SW("ソ\フトウェア");
697: Exif[i].data = _SW(imageEXIF.Software);
698: i++;
699: }
700: if (! imageEXIF.DateTime.empty()) {
701: Exif[i].label = _SW("撮影日時");
702: Exif[i].data = _SW(imageEXIF.DateTime);
703: i++;
704: }
705: if (! imageEXIF.DateTimeOriginal.empty()) {
706: Exif[i].label = _SW("撮影日時(オリジナル)");
707: Exif[i].data = _SW(imageEXIF.DateTimeOriginal);
708: i++;
709: }
710: if (! imageEXIF.DateTimeDigitized.empty()) {
711: Exif[i].label = _SW("撮影日時(デジタイズ)");
712: Exif[i].data = _SW(imageEXIF.DateTimeDigitized);
713: i++;
714: }
715: if (! imageEXIF.SubSecTimeOriginal.empty()) {
716: Exif[i].label = _SW("撮影日時(サブセック)");
717: Exif[i].data = _SW(imageEXIF.SubSecTimeOriginal);
718: i++;
719: }
720: if (! imageEXIF.Copyright.empty()) {
721: Exif[i].label = _SW("著作権者");
722: Exif[i].data = _SW(imageEXIF.Copyright);
723: i++;
724: }
725: Exif[i].label = _SW("露光制御");
726: switch (imageEXIF.ExposureProgram) {
727: case 1:
728: Exif[i].data = _SW("マニュアル設定");
729: break;
730: case 2:
731: Exif[i].data = _SW("通常のプログラムAE");
732: break;
733: case 3:
734: Exif[i].data = _SW("絞り優先");
735: break;
736: case 4:
737: Exif[i].data = _SW("シャッター速度優先");
738: break;
739: case 5:
740: Exif[i].data = _SW("低速プログラム");
741: break;
742: case 6:
743: Exif[i].data = _SW("高速プログラム");
744: break;
745: case 7:
746: Exif[i].data = _SW("ポートレートモード");
747: break;
748: case 8:
749: Exif[i].data = _SW("風景モード");
750: break;
751: default:
752: Exif[i].data = _SW("不明");
753: break;
754: }
755: i++;
756: Exif[i].label = _SW("ISOスピードレート");
757: Exif[i].data = _SW(to_string(imageEXIF.ISOSpeedRatings));
758: i++;
759: Exif[i].label = _SW("シャッター速度(秒)");
760: f = 1.0 / imageEXIF.ShutterSpeedValue;
761: Exif[i].data = _SW("1/" + to_string((int)f));
762: i++;
763: Exif[i].label = _SW("露出時間");
764: f = 1.0 / imageEXIF.ExposureTime;
765: Exif[i].data = _SW("1/" + to_string((int)f));
766: i++;
767: Exif[i].label = _SW("絞り値");
768: Exif[i].data = _SW(to_string(imageEXIF.ApertureValue));
769: i++;
770: Exif[i].label = _SW("F値");
771: Exif[i].data = _SW(to_string(imageEXIF.FNumber));
772: i++;
773: Exif[i].label = _SW("レンズ焦点距離");
774: Exif[i].data = _SW(to_string((int)imageEXIF.FocalLength));
775: i++;
776: Exif[i].label = _SW("輝度値");
777: Exif[i].data = _SW(to_string(imageEXIF.BrightnessValue));
778: i++;
779: Exif[i].label = _SW("露出補正値");
780: Exif[i].data = _SW(to_string(imageEXIF.ExposureBiasValue));
781: i++;
782: Exif[i].label = _SW("被写体距離");
783: Exif[i].data = _SW(to_string(imageEXIF.SubjectDistance));
784: i++;
785: Exif[i].label = _SW("フラッシュ");
786: switch (imageEXIF.Flash) {
787: case 0:
788: Exif[i].data = _SW("非発光");
789: break;
790: case 1:
791: Exif[i].data = _SW("発光");
792: break;
793: case 5:
794: Exif[i].data = _SW("発光したが反射光検出できず");
795: break;
796: case 6:
797: Exif[i].data = _SW("発光して反射光検出");
798: break;
799: default:
800: Exif[i].data = _SW("不明");
801: break;
802: }
803: i++;
804: Exif[i].label = _SW("測光モード");
805: switch (imageEXIF.MeteringMode) {
806: case 0:
807: Exif[i].data = _SW("平均測光");
808: break;
809: case 1:
810: Exif[i].data = _SW("中央重点");
811: break;
812: case 2:
813: Exif[i].data = _SW("スポット");
814: break;
815: case 4:
816: Exif[i].data = _SW("多点スポット");
817: break;
818: case 5:
819: Exif[i].data = _SW("マルチセグメント");
820: break;
821: case 6:
822: Exif[i].data = _SW("部分測光");
823: break;
824: default:
825: Exif[i].data = _SW("不明");
826: break;
827: }
828: i++;
829: Exif[i].label = _SW("光源");
830: switch (imageEXIF.LightSource) {
831: case 1:
832: Exif[i].data = _SW("昼光");
833: break;
834: case 2:
835: Exif[i].data = _SW("蛍光燈");
836: break;
837: case 3:
838: Exif[i].data = _SW("白熱電球");
839: break;
840: case 4:
841: Exif[i].data = _SW("フラッシュ");
842: break;
843: case 9:
844: Exif[i].data = _SW("快晴");
845: break;
846: case 10:
847: Exif[i].data = _SW("曇天");
848: break;
849: case 11:
850: Exif[i].data = _SW("日陰");
851: break;
852: case 12:
853: Exif[i].data = _SW("昼光色");
854: break;
855: case 13:
856: Exif[i].data = _SW("昼白色");
857: break;
858: case 14:
859: Exif[i].data = _SW("蛍光色");
860: break;
861: case 15:
862: Exif[i].data = _SW("白色");
863: break;
864: case 17:
865: Exif[i].data = _SW("標準ライトA");
866: break;
867: case 18:
868: Exif[i].data = _SW("標準ライトB");
869: break;
870: case 19:
871: Exif[i].data = _SW("標準ライトC");
872: break;
873: case 20:
874: Exif[i].data = _SW("D55");
875: break;
876: case 21:
877: Exif[i].data = _SW("D65");
878: break;
879: case 22:
880: Exif[i].data = _SW("D75");
881: break;
882: case 23:
883: Exif[i].data = _SW("D50");
884: break;
885: case 24:
886: Exif[i].data = _SW("ISO白熱電球");
887: break;
888: default:
889: Exif[i].data = _SW("不明");
890: break;
891: }
892: i++;
893: if (imageEXIF.Calibration.FocalLength != 0) {
894: Exif[i].label = _SW("(ピクセル)");
895: Exif[i].data = _SW(to_string(imageEXIF.Calibration.FocalLength));
896: i++;
897: }
898: if (imageEXIF.Calibration.OpticalCenterX != 0) {
899: Exif[i].label = _SW("(ピクセル)");
900: Exif[i].data = _SW(to_string(imageEXIF.Calibration.OpticalCenterX));
901: i++;
902: }
903: if (imageEXIF.Calibration.OpticalCenterY != 0) {
904: Exif[i].label = _SW("(ピクセル)");
905: Exif[i].data = _SW(to_string(imageEXIF.Calibration.OpticalCenterY));
906: i++;
907: }
908: //レンズ情報
909: Exif[i].label = _SW("最小絞り値");
910: Exif[i].data = _SW(to_string((int)imageEXIF.LensInfo.FStopMin));
911: i++;
912: Exif[i].label = _SW("最大絞り値");
913: Exif[i].data = _SW(to_string((int)imageEXIF.LensInfo.FStopMax));
914: i++;
915: Exif[i].label = _SW("広角側(ミリ)");
916: Exif[i].data = _SW(to_string((int)imageEXIF.LensInfo.FocalLengthMin));
917: i++;
918: Exif[i].label = _SW("望遠側(ミリ)");
919: Exif[i].data = _SW(to_string((int)imageEXIF.LensInfo.FocalLengthMax));
920: i++;
921: Exif[i].label = _SW("デジタルズーム倍率");
922: Exif[i].data = _SW(to_string((int)imageEXIF.LensInfo.DigitalZoomRatio));
923: i++;
924: Exif[i].label = _SW("焦点距離(35ミリ判相当");
925: Exif[i].data = _SW(to_string((int)imageEXIF.LensInfo.FocalLengthIn35mm));
926: i++;
927: ss = "";
928: switch (imageEXIF.LensInfo.FocalPlaneResolutionUnit) {
929: case 2:
930: ss = "(インチ)";
931: break;
932: case 3:
933: ss = "(センチ)";
934: break;
935: default:
936: ss = "";
937: break;
938: }
939: Exif[i].label = _SW("焦点面の幅の解像度" + ss);
940: Exif[i].data = _SW(to_string(imageEXIF.LensInfo.FocalPlaneXResolution));
941: i++;
942: Exif[i].label = _SW("焦点面の高さの解像度" + ss);
943: Exif[i].data = _SW(to_string(imageEXIF.LensInfo.FocalPlaneYResolution));
944: i++;
945: if (! imageEXIF.LensInfo.Make.empty() || ! imageEXIF.LensInfo.Model.empty()) {
946: Exif[i].label = _SW("レンズのメーカー名");
947: Exif[i].data = _SW(imageEXIF.LensInfo.Make);
948: i++;
949: Exif[i].label = _SW("レンズのモデル名");
950: Exif[i].data = _SW(imageEXIF.LensInfo.Model);
951: i++;
952: }
953: //位置情報
954: if (imageEXIF.GeoLocation.hasRelativeAltitude()) {
955: Exif[i].label = _SW("相対高度(メートル)");
956: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.RelativeAltitude));
957: i++;
958: }
959: if (imageEXIF.GeoLocation.hasOrientation()) {
960: Exif[i].label = _SW("ロール角");
961: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.RollDegree));
962: i++;
963: Exif[i].label = _SW("ピッチ角");
964: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.PitchDegree));
965: i++;
966: Exif[i].label = _SW("ヨー角");
967: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.YawDegree));
968: i++;
969: }
970: if (imageEXIF.GeoLocation.hasSpeed()) {
971: Exif[i].label = _SW("飛行速度(X方向;メートル/秒)");
972: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.SpeedX));
973: i++;
974: Exif[i].label = _SW("飛行速度(Y方向;メートル/秒)");
975: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.SpeedY));
976: i++;
977: Exif[i].label = _SW("飛行速度(Z方向;メートル/秒)");
978: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.SpeedZ));
979: i++;
980: }
981: if (imageEXIF.GeoLocation.AccuracyXY > 0 || imageEXIF.GeoLocation.AccuracyZ > 0) {
982: Exif[i].label = _SW("GPS精度(XY方向;メートル)");
983: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.AccuracyXY));
984: i++;
985: Exif[i].label = _SW("GPS精度(Z方向;メートル)");
986: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.AccuracyZ));
987: i++;
988: }
989: Exif[i].label = _SW("GPS精度低下率");
990: Exif[i].data = _SW(to_string(imageEXIF.GeoLocation.GPSDOP));
991: i++;
992: Exif[i].label = _SW("GPS差分補正");
993: switch (imageEXIF.GeoLocation.GPSDifferential) {
994: case 0:
995: ss = "差分補正なし";
996: break;
997: case 1:
998: ss = "差分補正適用";
999: break;
1000: default:
1001: ss = "不明";
1002: break;
1003: }
1004: i++;
1005: if (! imageEXIF.GeoLocation.GPSTimeStamp.empty()) {
1006: Exif[i].label = _SW("GPS時刻(UTC)");
1007: Exif[i].data = _SW(imageEXIF.GeoLocation.GPSTimeStamp);
1008: i++;
1009: }
1010: if (! imageEXIF.GeoLocation.GPSDateStamp.empty()) {
1011: Exif[i].label = _SW("GPS日付");
1012: Exif[i].data = _SW(imageEXIF.GeoLocation.GPSDateStamp);
1013: i++;
1014: }
1015:
1016: return ret;
1017: }
tinyEXIF のクラス EXIFStreamFile を使って画像ファイルを読み込むことで、Exif情報を取得できる。これを、冒頭で定義したクラス配列 Exif へ逐次代入するのがユーザー関数 loadExif である。
逐次代入するのに合わせ、タグ名(データ項目名)を日本語にしている。exif-subifdで使われるtag、デジタルスチルカメラ用画像ファイルフォーマット規格 Exif 2.3などを参考にした。
参考サイト
- PHPで撮影場所をマッピング:ぱふぅ家のホームページ
- C++ で直近の地震情報を取得する:ぱふぅ家のホームページ
- C++でTeX画像を作成:ぱふぅ家のホームページ
- WiX によるWindowsインストーラー作成:ぱふぅ家のホームページ
- C++ 開発環境の準備:ぱふぅ家のホームページ
- デジタルスチルカメラ用画像ファイルフォーマット規格 Exif 2.3:カメラ映像機器工業会規格
注意:2021年(令和3年)11月現在、GoogleマップAPIがInternetExplorer11のサポートを終了したため、Googleマップは利用できなくなった。
(2024年3月23日)使用ライブラリ更新
(2023年9月20日)使用ライブラリ更新
(2023年7月2日)使用ライブラリ更新