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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

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

Q&A

解決済

1回答

1735閲覧

GDI+での キーワードタグ削除について

BeatStar

総合スコア4958

Win32 API

Win32 APIはMicrosoft Windowsの32bitプロセッサのOSで動作するAPIです。

C++

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

0グッド

0クリップ

投稿2016/11/08 02:10

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

宜しくお願い致します。

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

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

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

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

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

guest

回答1

0

ベストアンサー

propertyItem->lengthにMAX_PATHなどの固定値をセットしているのが気になります。
正確な文字長(ヌル文字含む)をセットしてはどうでしょうか?

投稿2016/11/08 09:00

can110

総合スコア38260

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問