GDI+ Image::SetPropertyItem not working as expected

Viewed 107

I am trying to use SetPropertyItem to set a Date Taken property to a file (click here for MSDN docs description).

I have tried assigning a newly initialized FILETIME to an input image with no success (or error messages). To ensure that it was not an issue with Date Taken, I also tried following this MSDN example to no avail.

Currently, I am attempting to extract a Date Taken property item from one input file (works fine) and attempting to set it to a different file. This approach does not work either, and the Status code returned is always 0 (Ok).

The code I am using is below. I can only assume I am making a simple mistake or perhaps misunderstanding what SetPropertyItem is supposed to do. I thought that SetPropertyItem changed the metadata value such that it can be viewed through the Windows properties menu, like in this screenshot.

#include <windows.h>
#include <gdiplus.h>
#include <stdio.h>
#include <iostream>
using namespace Gdiplus;

#pragma comment(lib, "gdiplus.lib")

int main()
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    Image* image = new Image(L"FakePhoto.jpg"); // input image

    UINT totalBufferSize;
    UINT numProperties; // setup the buffer
    image->GetPropertySize(&totalBufferSize, &numProperties);

   // extract all metadata property items
   PropertyItem* pAllItems = (PropertyItem*)malloc(totalBufferSize);
   image->GetAllPropertyItems(totalBufferSize, numProperties, pAllItems);

   for (UINT j = 0; j < numProperties; ++j)
   { // loop through each property
       if (pAllItems[j].id == PropertyTagExifDTOrig)
       { // if it's the Date Taken property
            PropertyItem* propItem = new PropertyItem;
            Image* newImage = new Image(L"Test2.jpg");
            Status status; // second image

            propItem->id = PropertyTagExifDTOrig;
            propItem->length = pAllItems[j].length;
            propItem->type = PropertyTagTypeASCII;
            propItem->value = pAllItems[j].value;
            // create a new property item with the input photo Date Taken metadata
            status = newImage->SetPropertyItem(propItem);

            if (status == Ok)
                std::cout << "No errors.";
        }
    }

    free(pAllItems);
    delete image;
    GdiplusShutdown(gdiplusToken);
}

Any help is greatly appreciated. Also, I apologise about any obvious/potential errors. I am still learning the ropes as this is my first time using C++.

1 Answers

You code works fine, but you must save the image back, for example like this

...
newImage->SetPropertyItem(propItem);

CLSID clsid;
GetEncoderClsid(L"image/jpeg", &clsid);
newImage->Save(L"Test2.jpg", &clsid);
...

BOOL GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
    UINT num = 0;
    UINT size = 0;
    ImageCodecInfo* info = NULL;

    ZeroMemory(pClsid, sizeof(CLSID));
    GetImageEncodersSize(&num, &size);
    if (size == 0)
        return FALSE;

    info = (ImageCodecInfo*)(malloc(size));
    if (info == NULL)
        return FALSE;

    GetImageEncoders(num, size, info);
    for (UINT j = 0; j < num; ++j)
    {
        if (!wcscmp(info[j].MimeType, format))
        {
            *pClsid = info[j].Clsid;
            free(info);
            return TRUE;
        }
    }

    free(info);
    return FALSE;
}
Related