MFC读写EXIF信息,图片非占用-阿里云开发者社区

开发者社区> 云计算> 正文
登录阅读全文

MFC读写EXIF信息,图片非占用

简介: MFC读写EXIF信息 读取有类库可以直接调用,网络上有直接可以用的;但是写Exif的资料非常少,我花了一点时间研究收集,终于成功。 将相关的资料共享。主要是借助gdi+,需要注意的地方很多   // ConsoleApplication2.cpp : 定义控制台应用程序的入口点。

MFC读写EXIF信息

读取有类库可以直接调用,网络上有直接可以用的;但是写Exif的资料非常少,我花了一点时间研究收集,终于成功。
将相关的资料共享。主要是借助gdi+,需要注意的地方很多
 
// ConsoleApplication2.cpp : 定义控制台应用程序的入口点。
//
#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;
}
// 从内存加载图片,失败返回NULL
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;
}
// 从文件加载图片,不独占文件,失败返回NULL
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)  // 不处理大于4G的文件
        {
            // 将图片文件读到内存后,再从内存创建Bitmap
            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;
}

 

这段console代码共4个函数。main函数,GetEncoderClsid LoadBitmapFromMemory和LoadBitmapFromFile函数。其中GetEncoderClsid 函数是GDI+自己用于获得图片格式的。之所以要使用非占用的方式打开图片,是因为写入EXIF的信息也是图片自己信息的一部分,如果采用直接打开的方法,那么原始资源被占用,造成EXIF信息写不进去。
main函数中,就是主要过程。采用GDI+写入SetPropertyItem的方法进行写入。函数中E:/sandbox/stone.jpg是文件名,按照自己需要修改。
在本例中,我改写的EXIF项目PropertyTagCopyright这个是GDI+自己提供的,如果需要修改其他项目,跟到原始文件中,有一个长长的定义,从中选择自己需要的项目就可以。这个过程可能是需要查阅一些文件和进行对比的。
感谢阅读至此,希望有所收获。
 
目前方向:图像拼接融合、图像识别 联系方式:jsxyhelu@foxmail.com

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:
云计算
使用钉钉扫一扫加入圈子
+ 订阅

时时分享云计算技术内容,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

其他文章