question

YuriBudilov-3502 avatar image
0 Votes"
YuriBudilov-3502 asked YuriBudilov-3502 answered

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

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://docs.microsoft.com/en-us/windows/win32/wic/-wic-lh


thank you

windows-api
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

RLWA32-6355 avatar image
1 Vote"
RLWA32-6355 answered RLWA32-6355 edited

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



beforetags.png (18.4 KiB)
jpgtags.png (27.5 KiB)
aftertags.png (23.3 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Castorix31 avatar image
0 Votes"
Castorix31 answered
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

YuriBudilov-3502 avatar image
0 Votes"
YuriBudilov-3502 answered

many thanks!!

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.