#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
// 获取JPEG图像编码器CLSID
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;
}
// 获取含有可用图像编码器信息的ImageCodecInfo对象数组,根据图像类型名称做对比,取出图像编码器CLSID
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)
// 从内存创建Bitmap图片
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的文件
{
//申请存放图片数据的内存空间
unsigned char* buffer = new unsigned char[file_size];
// 将图片文件读到内存后,再从内存创建Bitmap
if (ReadFile(file_handle, buffer, file_size, &temp, NULL))
bmp = LoadBitmapFromMemory(buffer, temp);
delete[] buffer;
}
// 关闭文件句柄
CloseHandle(file_handle);
}
else
{
DWORD dwErrorCode = GetLastError();
std::cout << "CreateFile fail.ErrorCode=" << dwErrorCode << endl;
}
return bmp;
}
// 更新文件版权信息
BOOL UpdataJpegExifCopyRightInfo(const wchar_t* filename, const char* exifCopyrightInfo)
{
BOOL bResult = FALSE;
// GDI+接口初始化
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
// 从文件名获取图片信息,
Bitmap* image = LoadBitmapFromFile(filename);// Bitmap::FromFile(filename);//Bitmap::FromFile这种方式文件是已独占方式打开,无法修改EXIF属性信息
if (image == NULL){
// 清理GDI+资源
GdiplusShutdown(gdiplusToken);
return bResult;
}
image->GetPropertyItemSize(PropertyTagCopyright);
// 给EXIF属性申请内存空间
PropertyItem* propertyItem = (PropertyItem*)malloc(sizeof(PropertyItem));
memset(propertyItem, 0, sizeof(PropertyItem));
// 设置EXIF版本属性值
propertyItem->id = PropertyTagCopyright; //版权信息对应的Tag值
propertyItem->type = PropertyTagTypeASCII; //版权信息值类型
propertyItem->value = (void*)exifCopyrightInfo;
// 设置属性字符串长度
propertyItem->length = strlen(exifCopyrightInfo) + 1;
// 获取JPEG图像编码器CLSID
CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
// 设置属性值
image->SetPropertyItem(propertyItem);
// 保存图片
Status status = image->Save(filename, &clsid, NULL);
if (status == Ok)
bResult = TRUE;
// 删除申请的内存空间
free(propertyItem);
delete image;
// 清理GDI+资源
GdiplusShutdown(gdiplusToken);
return bResult;
}
程序中调用的是GDI+接口来实现修改JPG图片的EXIF属性信息,切记打开文件不要用Bitmap::FromFile方式,此方式文件将会被占用,导致修改属性失败。