質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

0回答

2217閲覧

GDI+ でのjpgタグ操作

BeatStar

総合スコア4958

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2016/09/26 01:47

C/C++ ( いわゆる BetterC ) でやっています。

基本的には MinGW ( g++ ) でやっていますが、GDI+ を使うため VC++ で DLL作成しています。

Jpgタグで "キーワードタグ" ってありますよね。

Windows 付属の Explorer で jpgファイルを選択し、

「プロパティ(R)」 → 「詳細」タブ → 「タグ」

で追加・削除できるやつです。

これの編集ができるソフトを作りたいと思い、

「C言語 jpgタグ 編集」等で検索したところ、
GDI+ というライブラリでできるようです。

なので、GDI+ についていたヘルプファイル のサンプルコードを流用して組んでみました。

しかし、挙動が変なのです。

たとえば、

"友人;中学校;卒業;涙;abc;太郎;次郎;三郎"

というタグが埋め込まれているとします。

読み込んだとき、

なぜか、

"友人;中学校;卒業;涙;ab"

と途中までしか表示されません。

長さが足りないのかと思い、
キーワードタグを短くすると、
同じように途中までしか表示されません。( むしろ、表示できる部分が狭くなっている。 )

実際のキーワードタグ全体の長さ - 55

等のようになっているのかもしれません。

ですが、ソースコードのどこを書き換えるべきなのか。。。

[ DLL ( VC++作成 ) 側 ]:

C++

1/* ライブラリ内の関数をオープンにするためのもの */ 2#define FUNCTION_DEFINITION extern "C" __declspec(dllexport) 3 4 5/* GDI+ をリンクする */ 6#pragma comment (lib, "gdiplus.lib") 7 8/* GDI+ で必要最低限のもの */ 9// 定義済みとする 10 11void PropertyTypeFromWORD(WORD index, WCHAR* string); 12int GetEncoderClsid(const WCHAR* format, CLSID* pClsid); 13 14#define MAX_TAG 177 15 16 17/* コール時に受け取る可能性のある種類 */ 18#define ID_KEYWORD_TAG (0) 19#define ID_COMMENT_TAG (1) 20#define ID_USER_COMMNET_TAG (1) 21 22/* 変換用 */ 23#define ID_TO_GIF (0) 24#define ID_TO_JPG (1) 25#define ID_TO_PNG (2) 26#define ID_TO_BMP (3) 27 28/* 現在 取得および設定可能なタグ */ 29#define KEYWORD_TAG 0x9c9e 30#define COMMENT_TAG 0x9c9c 31 32#define GDIPLUS_INITIALIZE GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) 33 34 35 36// GD+のヘルプファイルから。 37// Helper function 38void PropertyTypeFromWORD(WORD index, WCHAR* string) 39{ 40 WCHAR* propertyTypes[] = { 41 L"Nothing", // 0 42 L"PropertyTagTypeByte", // 1 43 L"PropertyTagTypeASCII", // 2 44 L"PropertyTagTypeShort", // 3 45 L"PropertyTagTypeLong", // 4 46 L"PropertyTagTypeRational", // 5 47 L"Nothing", // 6 48 L"PropertyTagTypeUndefined", // 7 49 L"Nothing", // 8 50 L"PropertyTagTypeSLONG", // 9 51 L"PropertyTagTypeSRational"}; // 10 52 53 wcscpy(string, propertyTypes[index]); 54} 55 56// GD+のヘルプファイルから。 57int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) 58{ 59 UINT num = 0; // number of image encoders 60 UINT size = 0; // size of the image encoder array in bytes 61 62 ImageCodecInfo* pImageCodecInfo = NULL; 63 64 GetImageEncodersSize(&num, &size); 65 if(size == 0) 66 return -1; // Failure 67 68 pImageCodecInfo = (ImageCodecInfo*)(malloc(size)); 69 if(pImageCodecInfo == NULL) 70 return -1; // Failure 71 72 GetImageEncoders(num, size, pImageCodecInfo); 73 74 for(UINT j = 0; j < num; ++j) 75 { 76 if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) 77 { 78 *pClsid = pImageCodecInfo[j].Clsid; 79 free(pImageCodecInfo); 80 return j; // Success 81 } 82 } 83 84 free(pImageCodecInfo); 85 return -1; // Failure 86} 87 88 89 90// C言語のchar型配列を WCHAR型配列 に変換 91void CStringToWCHAR( char *cStr, WCHAR *wStr ) 92{ 93 const int len = (int)strlen( cStr ); 94 95 setlocale( LC_CTYPE, "" ); 96 97 mbstowcs( wStr, cStr, len + 1 ); 98} 99 100 101// WCHAR型配列 を C言語のchar型配列 に変換 102void WcharToCString( WCHAR *wStr, char *cStr ) 103{ 104 const int len = (int)wcslen( wStr ); 105 setlocale( LC_CTYPE, "" ); 106 107 wcstombs( cStr, wStr, len + 1 ); 108} 109 110// GD+のヘルプファイルから。 111bool WriteTag( WCHAR *JpgFilePath, int TagID, char *str, WCHAR *NewjpgPathName ) 112{ 113 // Initialize GDI+. 114 GDIPLUS_INITIALIZE; 115 116 bool bStatus = false; 117 118 Status stat; 119 CLSID clsid; 120 WCHAR wPropertyValue[6000]; 121 122 Bitmap* bitmap = new Bitmap(JpgFilePath); 123 PropertyItem* propertyItem = new PropertyItem; 124 125 // Get the CLSID of the JPEG encoder. 126 GetEncoderClsid(L"image/jpeg", &clsid); 127 128 129 130 if( TagID == KEYWORD_TAG ) 131 { 132 CStringToWCHAR( str, wPropertyValue ); 133 propertyItem->id = KEYWORD_TAG; 134 propertyItem->length = MAX_TAG*2; // string length including NULL terminator 135 propertyItem->type = PropertyTagTypeByte; 136 propertyItem->value = wPropertyValue; 137 } 138 bitmap->SetPropertyItem(propertyItem); 139 140 stat = bitmap->Save(NewjpgPathName, &clsid, NULL); 141 if(stat == Ok) bStatus = true; 142 143 delete propertyItem; 144 delete bitmap; 145 146 GDIPLUS_UNINITIALIZE; 147 return bStatus; 148} 149 150// GDI+ のヘルプファイルから。 151bool ReadTag( WCHAR *JpgFilePath, int TagID, char *result ) 152{ 153 // Initialize GDI+. 154 GDIPLUS_INITIALIZE; 155 156 UINT size = 0; 157 UINT count = 0; 158 WCHAR strPropertyType[50] = L""; 159 160 char strID[9]; 161 bool flag = false; 162 163 Bitmap* bitmap = new Bitmap( JpgFilePath ); 164 165 bitmap->GetPropertySize(&size, &count); 166 167 168 // GetAllPropertyItems returns an array of PropertyItem objects. 169 // Allocate a buffer large enough to receive that array. 170 PropertyItem* pPropBuffer =(PropertyItem*)malloc(size); 171 172 // Get the array of PropertyItem objects. 173 bitmap->GetAllPropertyItems(size, count, pPropBuffer); 174 175 // For each PropertyItem in the array, display the id, type, and length. 176 for(UINT j = 0; j < count; ++j) 177 { 178 // Convert the property type from a WORD to a string. 179 PropertyTypeFromWORD(pPropBuffer[j].type, strPropertyType); 180 181 sprintf( strID, "0x%x", pPropBuffer[j].id ); 182 183 if( strcmp( strID, "0x9c9e" ) == 0 ) // "キーワード" タグ 184 { 185 WcharToCString( (WCHAR*)pPropBuffer[j].value, result ); 186 flag = true; 187 break; 188 } 189 } 190 191 free(pPropBuffer); 192 delete bitmap; 193 194 GDIPLUS_UNINITIALIZE; 195return flag; 196} 197 198FUNCTION_DEFINITION 199bool ReadTagEx( char *JpgFilePath, int iKind, char *result ) 200{ 201 202 WCHAR wJpgFilePath[MAX_PATH+1]; 203 int TagID; 204 205 CStringToWCHAR( JpgFilePath, wJpgFilePath ); 206 207 if( iKind == ID_KEYWORD_TAG ) 208 { 209 TagID = KEYWORD_TAG; 210 } 211 else if( iKind == ID_COMMENT_TAG || iKind == ID_USER_COMMNET_TAG ) 212 { 213 TagID = COMMENT_TAG; 214 } 215return ReadTag( wJpgFilePath, TagID, result ); 216} 217 218 219 220FUNCTION_DEFINITION 221bool WriteTagEx( char *JpgFilePath, int iKind, char *str, char *NewJpgFilePath ) 222{ 223 WCHAR wJpgFilePath[MAX_PATH+1]; 224 WCHAR wJpgNewFilePath[MAX_PATH+1]; 225 int TagID; 226 227 CStringToWCHAR( JpgFilePath, wJpgFilePath ); 228 CStringToWCHAR( NewJpgFilePath, wJpgNewFilePath ); 229 230 if( iKind == ID_KEYWORD_TAG ) 231 { 232 TagID = KEYWORD_TAG; 233 } 234 else if( iKind == ID_COMMENT_TAG || iKind == ID_USER_COMMNET_TAG ) 235 { 236 TagID = COMMENT_TAG; 237 } 238return WriteTag( wJpgFilePath, TagID, str, wJpgNewFilePath ); 239} 240

キーワードタグ用のIDは サンプルコードで ID がある間ループさせ,
それっぽい ID をチェックしたのですが、
ここからどうすればいいか。。。

[環境等]
言語: C/C++ ( いわゆる Better C )
コンパイラ: VC++ & MinGW

宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問