JPEG (.JPG) adding user tags values to a photo file via a program API (C/C++) ?

Yuri Budilov 21 Reputation points
2021-10-15T09:45:53.787+00:00

Hello everyone

I am using Windows 10 (soon Windows 11?).

I am aware that I can add user Tags values (separated by semi-colons) to a JPEG photo file (.JPG file) via editing Properties, click on Add Tag, etc.

However, I have tens of thousands of JPG files to which I want to add various user tags via a program (such as Visual C/C++ API)

What set of Windows API calls can I use to do this?

I also want to be able to read/retrieve and add/remove user Tags from JPG files via C/C++ API.

If anyone can link a Visual C++ code sample dealing with JPG Tags (read and write) it would help me greatly.

I suspect WIC (Windows Imaging Component) may be the "winner" in Windows 10/11 but I dont know specifically which methods/functions to use for this task. https://learn.microsoft.com/en-us/windows/win32/wic/-wic-lh

thank you

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,422 questions
0 comments No comments
{count} votes

Accepted answer
  1. RLWA32 40,286 Reputation points
    2021-10-15T11:57:01.577+00:00

    Following example shows reading and writing tags to the properties of a .jpg image -

    #include <ShlObj.h>  
    #include <propvarutil.h>  
    #include <propkey.h>  
      
    #pragma comment(lib, "propsys")  
      
    #include <stdio.h>  
    #include <tchar.h>  
      
    HRESULT ReadTags(PCWSTR szImage)  
    {  
        HRESULT hr;  
        IPropertyStore* pStore{};  
        hr = SHGetPropertyStoreFromParsingName(szImage, nullptr, GPS_DEFAULT, IID_PPV_ARGS(&pStore));  
        if (SUCCEEDED(hr) && pStore)  
        {  
            PROPVARIANT propTags;  
      
            PropVariantInit(&propTags);  
            hr = pStore->GetValue(PKEY_Keywords, &propTags);  
            if (SUCCEEDED(hr))  
            {  
                switch (propTags.vt)  
                {  
                case VT_EMPTY:  
                    wprintf_s(L"Image %s has no tags\n", szImage);  
                    break;  
      
                case VT_VECTOR | VT_LPWSTR:  
                {  
                    PWSTR pwszTags[10]{};  
                    ULONG cElem{ 0 };  
                    hr = PropVariantToStringVector(propTags, pwszTags, ARRAYSIZE(pwszTags), &cElem);  
                    if (SUCCEEDED(hr))  
                    {  
                        wprintf_s(L"Image %s contained %d tags\n", szImage, cElem);  
                        for (ULONG i = 0; i < cElem; i++)  
                        {  
                            wprintf_s(L"Tag %d is %s\n", i, pwszTags[i]);  
                            CoTaskMemFree(pwszTags[i]);  
                        }  
                    }  
                    else  
                        wprintf_s(L"PropVariantToStringVector failed error was 0x%X\n", hr);  
      
                    PropVariantClear(&propTags);  
                }  
                break;  
      
                default:  
                    wprintf(L"Unexpected type %d in propvariant\n", propTags.vt);  
                }  
      
            }  
            pStore->Release();  
        }  
      
        return hr;  
    }  
      
    HRESULT WriteTags(PCWSTR szImage)  
    {  
        HRESULT hr;  
        IPropertyStore* pStore{};  
        hr = SHGetPropertyStoreFromParsingName(szImage, nullptr, GPS_READWRITE, IID_PPV_ARGS(&pStore));  
        if (SUCCEEDED(hr) && pStore)  
        {  
            PROPVARIANT propTags;  
            PCWSTR aTags[] =  
            {  
                L"First",  
                L"Second",  
                L"Third"  
            };  
      
            PropVariantInit(&propTags);  
      
            hr = InitPropVariantFromStringVector(aTags, ARRAYSIZE(aTags), &propTags);  
            if (SUCCEEDED(hr))  
            {  
                hr = pStore->SetValue(PKEY_Keywords, propTags);  
                if (SUCCEEDED(hr))  
                {  
                    hr = pStore->Commit();  
                    if (SUCCEEDED(hr))  
                        wprintf_s(L"Property Tags Written to %s\n", szImage);  
                    else  
                        wprintf_s(L"IPropertyStore::Commit failed error was 0x%X\n", hr);  
                }  
                else  
                    wprintf_s(L"IPropertyStore::SetValue failed error was 0x%X\n", hr);  
            }  
      
            PropVariantClear(&propTags);  
      
            pStore->Release();  
        }  
      
        return hr;  
    }  
      
    int main()  
    {  
        if (SUCCEEDED(CoInitialize(NULL)))  
        {  
            PCWSTR pwszImage = L"C:\\Users\\Rlwa32\\Pictures\\IMG_1874.jpg";  
            ReadTags(pwszImage);  
            WriteTags(pwszImage);  
            ReadTags(pwszImage);  
        }  
      
        CoUninitialize();  
      
        return 0;  
    }  
      
    

    Properties before -

    140817-beforetags.png

    Program output -

    140862-jpgtags.png

    Properties after -

    140892-aftertags.png

    1 person found this answer helpful.
    0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Castorix31 81,636 Reputation points
    2021-10-15T10:04:46.86+00:00
    0 comments No comments

  2. Yuri Budilov 21 Reputation points
    2021-10-15T21:00:26.337+00:00

    many thanks!!

    0 comments No comments