如何使用MFC将“注释”添加到JPEG文件

时间:2017-01-19 23:06:49

标签: mfc exif

在JPEG图像的属性窗口中,有一个名为“摘要”的选项卡。在这个标签中,有一个名为'Comments'的字段我想写一些MFC代码,它会在这个字段中添加一个给定的字符串,例如“这是一张照片”。

有些灵魂知道怎么做吗?

非常感谢。

2 个答案:

答案 0 :(得分:0)

MFC不提供此功能,但您可以使用GDI+执行此任务。 Image类能够读取和编写Exif元数据。

这几乎是微不足道的,并在Reading and Writing Metadata下解释。但是,由于 UserComment 元数据标记允许不同的字符编码,因此事情会更加复杂。以下代码 1)实现了一个命令行实用程序,允许设置(或替换,如果存在) UserComment 字段:

#include <vector>
using std::vector;
#include <iterator>
using std::back_inserter;

vector<BYTE> MakeUnicodeComment(const wchar_t* text){
    // Exif 2.2 header for Unicode (UCS-2): 'U', 'N', 'I', 'C', 'O', 'D', 'E', '\0'
    static const char header[]{"UNICODE"};
    static const size_t headerSize{ sizeof(header) / sizeof(header[0]) };

    // UserComment field contains the 8-byte header followed by UTF-16LE encoded code units
    vector<BYTE> buffer;
    std::copy(header, header + headerSize, back_inserter(buffer));
    // Append comment text (NUL terminator is not required)
    auto current = text;
    while (*current) {
        buffer.push_back(*current & 0xFF);
        buffer.push_back((*current >> 8) & 0xFF);
        ++current;
    }

    return buffer;
}

构建一个格式正确的注释需要一些工作。这在以下函数中实现:

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
    UINT  num = 0;          // number of image encoders
    UINT  size = 0;         // size of the image encoder array in bytes

    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return -1;  // Failure

    pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
    if (pImageCodecInfo == NULL)
        return -1;  // Failure

    GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j) {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;  // Success
        }
    }

    free(pImageCodecInfo);
    return -1;  // Failure
}

Retrieving the Class Identifier for an Encoder复制从其MIME类型中检索JPEG编码器以供参考:

const Organization = Bookshelf.Model.extend({
  tableName: "organization",
  idAttribute: "idorganization",
  members: function() {
    return this.belongsToMany(Member);
  }
});

const Member = Bookshelf.Model.extend({
  tableName: "member",
  idAttribute: "idmember",
  organization: function() {
    return this.belongsTo(Organization);
  }
});

<小时/> 1) 为简洁起见,错误处理已被删除。

答案 1 :(得分:0)

好的,最后我设法解决了问题!有代码:

OK,Finally I manage to solove the problem!There is the code:

#include "stdafx.h"
#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")   
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT num= 0;
    UINT size= 0;
    ImageCodecInfo* pImageCodecInfo= NULL;
    GetImageEncodersSize(&num, &size);
    if(size== 0)
    {
        return -1;
    }
    pImageCodecInfo= (ImageCodecInfo*)(malloc(size));
    if(pImageCodecInfo== NULL)
    {
        return -1;
    }
    GetImageEncoders(num, size, pImageCodecInfo);
    for(UINT j=0; j< num; ++j)
    {
        if(wcscmp(pImageCodecInfo[j].MimeType, format)== 0)
        {
            *pClsid= pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;
        }
    }
    free(pImageCodecInfo);
    return -1;
}
// load bitmap from memory,sync way
Bitmap* LoadBitmapFromMemory(const void* memory, DWORD size)
{
    Bitmap* bmp = NULL;
    IStream* stream = NULL;
    if (CreateStreamOnHGlobal(NULL, TRUE, &stream) == S_OK)
    {
        ULARGE_INTEGER uli;
        uli.QuadPart = size;
        stream->SetSize(uli);
        if (stream->Write(memory, size, NULL) == S_OK)
            bmp = new Bitmap(stream);
        stream->Release();
    }
    return bmp;
}
// load bitmap from file,sync way
Bitmap* LoadBitmapFromFile(const TCHAR* file_name)
{
    Bitmap* bmp = NULL;
    HANDLE file_handle = CreateFile(file_name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    if (file_handle != INVALID_HANDLE_VALUE)
    {
        DWORD temp = 0;
        DWORD file_size = GetFileSize(file_handle, &temp);
        if (file_size && !temp)  // the file must be less than 4G
        {
            unsigned char* buffer = new unsigned char[file_size];
            if (ReadFile(file_handle, buffer, file_size, &temp, NULL))
                bmp = LoadBitmapFromMemory(buffer, temp);
            delete [] buffer;
        }
        CloseHandle(file_handle);
    }
    return bmp;
}
int _tmain(int argc, _TCHAR* argv[])
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
    Status stat;
    CLSID  clsid;
    char   propertyValue[] = "Fake Photograph";
     Bitmap* bitmap = LoadBitmapFromFile(L"E:/sandbox/stone.jpg");
    PropertyItem* propertyItem = new PropertyItem;
    // Get the CLSID of the JPEG encoder.
    GetEncoderClsid(L"image/jpeg", &clsid);
    propertyItem->id = PropertyTagCopyright;
    propertyItem->length = 16;  // string length including NULL terminator
    propertyItem->type = PropertyTagTypeASCII; 
    propertyItem->value = propertyValue;
    bitmap->SetPropertyItem(propertyItem);
 
    stat = bitmap->Save(L"E:/sandbox/stone.jpg", &clsid, NULL);
    if(stat == Ok)
        printf("FakePhoto2.jpg saved successfully.\n");
    delete propertyItem;
    delete bitmap;
    GdiplusShutdown(gdiplusToken);
    return 0;
    return 0;
}