C/C++ でやっています。
基本的には MinGW でやっているのですが、
Jpegタグ で Windows用(?) の "キーワードタグ" ってありますよね。
( 呼び名がライブラリ等によって変わりますが。 )
画像や実行ファイル等 のファイルを閲覧するときに使う Explorer で
jpegファイル を右クリック -> "プロパティ(R)" を選択 -> "詳細" タブ を選択 -> "タグ"
で編集できるやつです。
これを編集できるソフトを作ろうと思い、調べてみたところ、
GDI+ というライブラリでできるようです。
ですが libファイルで VC++向けらしいので
VC++ で DLL化 し、MinGWで作成した実行ファイルからアクセスし使用する
という方法を取ろうと思っています。
一応最低限 ( タグ追加 ) はできたのですが、
タグ削除ができません。
"コメント"タグ は NULL を追加したら "削除"扱いにできるようなのでいいですが、
"キーワード"タグ が...
[ DLL側 ( 一部 ) ]
C++
1/* GDI+ で必要最低限のもの */ 2#include <windows.h> 3#include <gdiplus.h> 4#include <stdio.h> 5#include<string> 6using namespace Gdiplus; 7using namespace std; 8 9/* ライブラリ内の関数をオープンにするためのもの */ 10#define FUNCTION_DEFINITION extern "C" __declspec(dllexport) 11 12/* GDI+ をリンクする */ 13#pragma comment (lib, "gdiplus.lib") 14 15 16#define MAX_TAG 2000 17 18 19/* コール時に受け取る可能性のある種類 */ 20#define ID_KEYWORD_TAG (0) 21#define ID_COMMENT_TAG (1) 22#define ID_USER_COMMNET_TAG (1) 23 24 25/* 26 マクロ GDIPLUS_INITIALIZE は GDI+を使うときに書く GdiplusStartupInput gdiplusStartupInput; ... で、 27 マクロ GDIPLUS_UNINITIALIZE は GdiplusShutdown(gdiplusToken) とする。 28*/ 29 30 31// 時数制限のため、プロトタイプのみの記載。 32// char型配列からWCHAR型配列に変換 33void CStringToWCHAR( const char *cStr, WCHAR *wStr ); 34 35 36// 時数制限のため、プロトタイプのみの記載。 37// WCHAR型配列からchar型配列に変換 38void WcharToCString( const WCHAR *wStr, char *cStr ); 39 40 41// 時数制限のため、プロトタイプのみの記載。 42// GDI+ のヘルプファイルから流用。 43// Helper function 44void PropertyTypeFromWORD(WORD index, WCHAR* string); 45 46 47// 時数制限のため、プロトタイプのみの記載。 48// GDI+ のヘルプファイルから流用。 49int GetEncoderClsid(const WCHAR* format, CLSID* pClsid); 50 51 52 53bool WriteTag( WCHAR *JpgFilePath, int TagID, const char *str, WCHAR *NewjpgPathName ) 54{ 55 // Initialize GDI+. 56 GDIPLUS_INITIALIZE; 57 58 bool bStatus = false; 59 60 Status stat; 61 CLSID clsid; 62 WCHAR wPropertyValue[6000]; 63 64 Bitmap* bitmap = new Bitmap(JpgFilePath); 65 PropertyItem* propertyItem = new PropertyItem; 66 67 // Get the CLSID of the JPEG encoder. 68 GetEncoderClsid(L"image/jpeg", &clsid); 69 70 71 72 if( TagID == KEYWORD_TAG ) 73 { 74 CStringToWCHAR( str, wPropertyValue ); 75 propertyItem->id = KEYWORD_TAG; 76 propertyItem->length = MAX_TAG*2; // string length including NULL terminator 77 propertyItem->type = PropertyTagTypeByte; 78 propertyItem->value = wPropertyValue; 79 } 80 else if( TagID == COMMENT_TAG ) 81 { 82 CStringToWCHAR( str, wPropertyValue ); 83 propertyItem->id = COMMENT_TAG; 84 propertyItem->length = MAX_PATH; // string length including NULL terminator 85 propertyItem->type = PropertyTagTypeByte; 86 propertyItem->value = wPropertyValue; 87 } 88 else 89 { 90 91 } 92 bitmap->SetPropertyItem(propertyItem); 93 94 stat = bitmap->Save(NewjpgPathName, &clsid, NULL); 95 if(stat == Ok) bStatus = true; 96 97 delete propertyItem; 98 delete bitmap; 99 100 GDIPLUS_UNINITIALIZE; 101 return bStatus; 102} 103 104 105// これにアクセスする。そのままでもいいが、WCHAR型なので扱いにくいため、 106// char型 -> WHCAR型 に変換して代理でやってくれるようにする。 107FUNCTION_DEFINITION 108bool WriteTagEx( const char *JpgFilePath, int iKind, const char *str, const char *NewJpgFilePath ) 109{ 110 WCHAR wJpgFilePath[MAX_PATH+1]; 111 WCHAR wJpgNewFilePath[MAX_PATH+1]; 112 int TagID; 113 114 CStringToWCHAR( JpgFilePath, wJpgFilePath ); 115 CStringToWCHAR( NewJpgFilePath, wJpgNewFilePath ); 116 117 if( iKind == ID_KEYWORD_TAG ) 118 { 119 TagID = KEYWORD_TAG; 120 } 121 else if( iKind == ID_COMMENT_TAG || iKind == ID_USER_COMMNET_TAG ) 122 { 123 TagID = COMMENT_TAG; 124 } 125return WriteTag( wJpgFilePath, TagID, str, wJpgNewFilePath ); 126}
( 実際は main.cpp に ReadTagEx関数を、read.h に WriteTag関数のプロトタイプ, read.cpp に WriteTag関数の定義... と
分割しているが、すべて記述するのは大変(主に関係性が。)なので一つにまとめます。 )
[ MinGWで作成する実行ファイル側 ( 一部 ) ]
C++
1/* 2 時数制限のため、簡略化する。 3 4 CPath::... とあるのは 自作クラス ( ただし、static付き ) で ファイルパスからディレクトリパスを取得したりする。 5 6 CSystem::... とあるのも自作クラス ( 同じくstatic ) で、システム関連操作を行う。 7 8 CJpgTag は Read関数と Write関数, コンストラクタ ... とあるとします。 9*/ 10 11bool CJpgTag::Write( const std::string JpgFilePath, const std::string tag ){ 12 13 string tag1; // 編集前のタグ 14 string tag2; // 編集後のタグ 15 string dir; // 対象ファイルのディレクトリ 16 string filename; // 対象ファイルのファイル名+拡張子 17 string new1; // 一時ファイル 18 int AddOrDelete; // 追加か削除か 19 20 21 // 同じクラスのメンバ。現在の値を取得。 22 this->Read( JpgFilePath, tag1 ); 23 24 // 第2引数が empty の場合、"タグの削除" とみなす 25 if( tag.empty() ){ 26 AddOrDelete = DELETE_TAG; 27 }else{ 28 AddOrDelete = ADD_TAG; 29 } 30 31 if( AddOrDelete == ADD_TAG ){ 32 if( this->TagID == ID_KEYWORD_TAG ){ 33 // キーワードタグがない場合は 引数の tag, ある場合は 既存のタグ+tag とする 34 if( tag1.empty() ){ 35 tag2 = tag; 36 }else{ 37 tag2 = tag1 + string( ";" ) + tag; 38 } 39 }else{ 40 tag2 = tag; 41 } 42 43 // 一時ファイルのパスを生成する 44 if( CPath::GetDirPath( JpgFilePath, dir ) ){ 45 new1 = dir + string("\\temp.jpg"); 46 }else{ 47 new1 = string("temp.jpg"); 48 } 49 50 CPath::GetFileEx( JpgFilePath, filename ); 51 52 if( WriteTagEx( JpgFilePath.c_str(), this->TagID, tag2.c_str(), new1.c_str() ) == true ){ 53 CSystem::Del( JpgFilePath ); 54 CSystem::Ren( new1, filename ); 55 return true; 56 }else{ 57 return false; 58 } 59 }else{ 60 tag2 = ""; 61 62 // 一時ファイルのパスを生成する 63 if( CPath::GetDirPath( JpgFilePath, dir ) ){ 64 new1 = dir + string("\\temp.jpg"); 65 }else{ 66 new1 = string("temp.jpg"); 67 } 68 69 CPath::GetFileEx( JpgFilePath, filename ); 70 71 if( WriteTagEx( JpgFilePath.c_str(), this->TagID, tag2.c_str(), new1.c_str() ) == true ){ 72 CSystem::Del( JpgFilePath ); 73 CSystem::Ren( new1, filename ); 74 return true; 75 }else{ 76 return false; 77 } 78 } 79}
という感じです。
動かしてみると、
追加のときや、 コメントタグ初期化 はうまくいくのですが、
キーワードタグ初期化のときは なぜか元のデータが残っています。
どうすればいいでしょうか。
[環境等]
言語: C/C++ ( WindowsAPI あり )
コンパイラ: ( 実行ファイル ) MinGW, ( DLL ) VC++ 2010 Express
宜しくお願い致します。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。