天天看點

MFC讀寫EXIF資訊,圖檔非占用

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+自己提供的,如果需要修改其他項目,跟到原始檔案中,有一個長長的定義,從中選擇自己需要的項目就可以。這個過程可能是需要查閱一些檔案和進行對比的。

感謝閱讀至此,希望有所收獲。

 目前方向:圖像拼接融合、圖像識别

聯系方式:[email protected]

繼續閱讀