web-dev-qa-db-ja.com

C#を使用してJPEGファイルに「コメント」を追加する方法

JPEG画像のプロパティウィンドウ内に、「概要」というタブがあります。このタブ内に、「コメント」というフィールドがあります。このフィールドに特定の文字列を追加するc#コードを記述します(例:「これは写真です」)。

そこにいる親切な魂はこれを行う方法を知っていますか?

どうもありがとう。

18
John P

次のコードは私の問題を解決し、特定のJPEG画像にコメントを追加します。

public void addImageComment(string imageFlePath, string comments)
    {
        string jpegDirectory = Path.GetDirectoryName(imageFlePath);
        string jpegFileName = Path.GetFileNameWithoutExtension(imageFlePath);

        BitmapDecoder decoder = null;
        BitmapFrame bitmapFrame = null;
        BitmapMetadata metadata = null;
        FileInfo originalImage = new FileInfo(imageFlePath);

        if (File.Exists(imageFlePath))
        {
            // load the jpg file with a JpegBitmapDecoder    
            using (Stream jpegStreamIn = File.Open(imageFlePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
            {
                decoder = new JpegBitmapDecoder(jpegStreamIn, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
            }

            bitmapFrame = decoder.Frames[0];
            metadata = (BitmapMetadata)bitmapFrame.Metadata;

            if (bitmapFrame != null)
            {
                BitmapMetadata metaData = (BitmapMetadata)bitmapFrame.Metadata.Clone();

                if (metaData != null)
                {
                    // modify the metadata   
                    metaData.SetQuery("/app1/ifd/exif:{uint=40092}", comments);

                    // get an encoder to create a new jpg file with the new metadata.      
                    JpegBitmapEncoder encoder = new JpegBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metaData, bitmapFrame.ColorContexts));
                    //string jpegNewFileName = Path.Combine(jpegDirectory, "JpegTemp.jpg");

                    // Delete the original
                    originalImage.Delete();

                    // Save the new image 
                    using (Stream jpegStreamOut = File.Open(imageFlePath, FileMode.CreateNew, FileAccess.ReadWrite))
                    {
                        encoder.Save(jpegStreamOut);
                    }
                }
            }
        }
    }

これは基本的に、コナミマンが親切に提供したリンクの下にあるコードのわずかに変更されたバージョンです。

これを機能させるには、PresentationCoreおよびWindowsBaseに.NET参照を追加する必要があることに注意してください。 Visual Studio 2008を使用している場合、これは次の方法で実現できます。

  1. ソリューションエクスプローラーでプロジェクトを右クリックします

  2. ドロップダウンリストから、[追加] '[参照...]を選択します。

  3. 開いた新しいボックスから、[。NET]タブを選択します

  4. 上記の2つの参照までスクロールし、それぞれで[OK]をクリックします

この件に関してあなたの助けをくれたdanbystromとKonamimanの両方に感謝します。迅速な対応に心から感謝しています。

12
John P

他の回答に基づいて、さまざまなメタデータ操作を可能にする次のクラスを作成しました。あなたはそれをこのように使います:

var jpeg = new JpegMetadataAdapter(pathToJpeg);
jpeg.Metadata.Comment = "Some comments";
jpeg.Metadata.Title = "A title";
jpeg.Save();              // Saves the jpeg in-place
jpeg.SaveAs(someNewPath);  // Saves with a new path

私のソリューションと他のソリューションの違いは大きくありません。主に、これをよりクリーンになるようにリファクタリングしました。また、BitmapMetadataメソッドではなく、SetQueryの高レベルのプロパティを使用します。

これが完全なコードであり、 MIT licencePresentationCoreWindowsBaseへの参照を追加する必要があります。 、およびSystem.Xaml

public class JpegMetadataAdapter
{
    private readonly string path;
    private BitmapFrame frame;
    public readonly BitmapMetadata Metadata;

    public JpegMetadataAdapter(string path)
    {
        this.path = path;            
        frame = getBitmapFrame(path);
        Metadata = (BitmapMetadata)frame.Metadata.Clone();
    }

    public void Save()
    {
        SaveAs(path);
    }

    public void SaveAs(string path)
    {
        JpegBitmapEncoder encoder = new JpegBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(frame, frame.Thumbnail, Metadata, frame.ColorContexts));
        using (Stream stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite))
        {
            encoder.Save(stream);
        }
    }

    private BitmapFrame getBitmapFrame(string path)
    {
        BitmapDecoder decoder = null;
        using (Stream stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
        {
            decoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
        }
        return decoder.Frames[0];
    }
}
16
Martin Eden

簡単な部分:

このプロパティアイテムを追加します。

var data = System.Text.Encoding.UTF8.GetBytes( "Some comments" );
PropertyItem pi;
*** create an empty PropertyItem here
pi.Type = 2;
pi.Id = 37510;
pi.Len = data.Length;
pi.Value = data;

画像のPropertItemsコレクションへ。

やや面倒な部分:パブリックコンストラクターがないため、新しいPropertyItemをどのように作成しますか?

一般的な「トリック」は、PropertyItemを盗むことができる空の画像を周囲に置くことです。 ため息

2
Dan Byström

以前のヒントのおかげで、私は以下をまとめることができました。私はそれをテストしました、そしてそれはうまくいくようです。最大の障害の1つは、割り当てたいフィールドに必要なIDを決定することでした。

string fileName = "c:/SomeImage.jpg";
// Retrieve the Image
System.Drawing.Image originalImage = System.Drawing.Image.FromFile(fileName);

// Get the list of existing PropertyItems. i.e. the metadata
PropertyItem[] properties = originalImage.PropertyItems;

// Create a bitmap image to assign attributes and do whatever else..
Bitmap bmpImage = new Bitmap((Bitmap)originalImage);

// Don't need this anymore
originalImage.Dispose();

// Get / setup a PropertyItem
PropertyItem item = properties[0]; // We have to copy an existing one since no constructor exists

// This will assign "Joe Doe" to the "Authors" metadata field
string sTmp = "Joe DoeX"; // The X will be replaced with a null.  String must be null terminated.
var itemData = System.Text.Encoding.UTF8.GetBytes(sTmp);
itemData[itemData.Length - 1] = 0;// Strings must be null terminated or they will run together
item.Type = 2; //String (ASCII)
item.Id = 315; // Author(s), 315 is mapped to the "Authors" field
item.Len = itemData.Length; // Number of items in the byte array
item.Value = itemData; // The byte array
bmpImage.SetPropertyItem(item); // Assign / add to the bitmap

// This will assign "MyApplication" to the "Program Name" field
sTmp = "MyApplicationX";
itemData = System.Text.Encoding.UTF8.GetBytes(sTmp);
itemData[itemData.Length - 1] = 0; // Strings must be null terminated or they will run together
item.Type = 2; //String (ASCII)
item.Id = 305; // Program Name, 305 is mapped to the "Program Name" field
item.Len = itemData.Length;
item.Value = itemData;
bmpImage.SetPropertyItem(item);

// Save the image
bmpImage.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg);

//Clean up
bmpImage.Dispose();
1
Peter Kistler

ここでの回答のおかげで、メモリのみを使用してコメントを設定するソリューションをコーディングしました。

public static Image SetImageComment(Image image, string comment) {
  using (var memStream = new MemoryStream()) {
    image.Save(memStream, ImageFormat.Jpeg);
    memStream.Position = 0;
    var decoder = new JpegBitmapDecoder(memStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad);
    BitmapMetadata metadata;
    if (decoder.Metadata == null) {
      metadata = new BitmapMetadata("jpg");
    } else {
      metadata = decoder.Metadata;
    }

    metadata.Comment = comment;

    var bitmapFrame = decoder.Frames[0];
    BitmapEncoder encoder = new JpegBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metadata, bitmapFrame.ColorContexts));

    var imageStream = new MemoryStream();
    encoder.Save(imageStream);
    imageStream.Position = 0;
    image.Dispose();
    image = null;
    return Image.FromStream(imageStream);
  }
}

このメソッドによって返される画像を破棄することを忘れないでください。 (たとえば、画像をファイルに保存した後)

1
Bas de Raad