0.内容概览
1.下载源码
- 项目地址:XMP-Toolkit-SDK
>> git clone --recursive git@github.com:adobe/XMP-Toolkit-SDK.git
2.下载第三方库
2.1 expat
- (1) 下载expat库:下载地址:expat源码
- (2) 进入工程对应目录:
>> cd XMP-Toolkit-SDK/third-party/expat
- (3) 解压到当前目录
# 1.源码解压缩
>> tar -xf expat-2.6.4.tar.xz
# 2.移动解压文件到根目录
>> cd expat-2.6.4 && mv * ../
# 3.删除无用文件及目录
>> cd .. && rm -r expat-2.6.4 && rm expat-2.6.4.tar.xz
2.2 zlib
# 1.进入zlib目录
>> cd XMP-Toolkit-SDK/third-party/zlib
# 2.下载zlib源码
>> wget https://www.zlib.net/zlib-1.3.1.tar.gz
# 3.源代码解压
>> tar -xf zlib-1.3.1.tar.gz
# 4.移动解压文件到根目录
>> cd zlib-1.3.1 && mv * ../
# 5.删除无用文件及目录
>> cd .. && rm -r zlib-1.3.1 && rm zlib-1.3.1.tar.gz
3.修改相关脚本配置
- (1)
build/shared/SharedConfig_Common.cmake
文件,注释掉下面行,修改为如下内容:
# workaround for visibility problem and gcc 4.1.x
# if(${${COMPONENT}_VERSIONING_GCC_VERSION} LESS 413)
# only remove inline hidden...
string(REGEX REPLACE "-fvisibility-inlines-hidden" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# endif()
# if(${${COMPONENT}_VERSIONING_GCC_VERSION} EQUAL 482)
#include path -I ${GNU_BASE}/include/c++/4.8.2/x86_64-unknown-linux-gnu
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I ${CMAKE_FIND_ROOT_PATH}/include/c++/4.8.2/x86_64-unknown-linux-gnu")
# endif()
- (2)
build/ProductConfig.cmake
文件,171行修改为如下内容:
set(XMP_PLATFORM_LINK "-z defs -Xlinker -Bsymbolic -Wl,--no-undefined ${XMP_EXTRA_LINK_FLAGS} ${XMP_TOOLCHAIN_LINK_FLAGS} -lrt -Wl,--no-as-needed -ldl -lpthread")
注意:下面的修改是为了适配Visual Studio 2019,如果你按照了Visual Studio 2022,就无需对下面内容进行修改
- (3) 全局搜索
Visual Studio 17 2022
并修改为Visual Studio 16 2019
- (4) 全局搜索
vc17
并修改为vc16
4.源码编译
4.1 Windows平台
- (1) 进入
XMP-Toolkit-SDK/build
文件夹,双击cmake_all.bat
文件生成vc工程 - (2) 进入
XMP-Toolkit-SDK/build/vc16/dynamic/windows_x64
打开XMPToolkitSDK64.sln
进行编译即可 - (3) 编译生成的头文件和库文件分别位于:
XMP-Toolkit-SDK/public/include
XMP-Toolkit-SDK/public/libraries
4.2 Linux平台
- (1) 工程编译,生成动态库:
>> cd XMP-Toolkit-SDK/build
>> make DynamicAll
- (2) 头文件和库文件目录:
XMP-Toolkit-SDK/public/include
XMP-Toolkit-SDK/public/libraries
5.测试代码
// =================================================================================================
// Copyright 2008 Adobe
// All Rights Reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
// of the Adobe license agreement accompanying it.
// =================================================================================================
/**
* Tutorial solution for the Walkthrough 1 in the XMP Programmers Guide, Opening files and reading XMP.
* Demonstrates the basic use of the XMPFiles and XMPCore components, obtaining read-only XMP from a file
* and examining it through the XMP object.
*/
#include <cstdio>
#include <vector>
#include <string>
#include <cstring>
//#define ENABLE_XMP_CPP_INTERFACE 1
// Must be defined to instantiate template classes
#define TXMP_STRING_TYPE std::string
// Must be defined to give access to XMPFiles
#define XMP_INCLUDE_XMPFILES 1
// Ensure XMP templates are instantiated
#include "public/include/XMP.incl_cpp"
// Provide access to the API
#include "public/include/XMP.hpp"
#include <iostream>
#include <fstream>
using namespace std;
/**
* Client defined callback function to dump XMP to a file. In this case an output file stream is used
* to write a buffer, of length bufferSize, to a text file. This callback is called multiple
* times during the DumpObject() operation. See the XMP API reference for details of
* XMP_TextOutputProc() callbacks.
*/
XMP_Status DumpXMPToFile(void * refCon, XMP_StringPtr buffer, XMP_StringLen bufferSize)
{
XMP_Status status = 0;
try
{
ofstream * outFile = static_cast<ofstream*>(refCon);
(*outFile).write(buffer, bufferSize);
}
catch(XMP_Error & e)
{
cout << e.GetErrMsg() << endl;
return -1; // Return a bad status
}
return status;
}
/**
* Initializes the toolkit and attempts to open a file for reading metadata. Initially
* an attempt to open the file is done with a handler, if this fails then the file is opened with
* packet scanning. Once the file is open several properties are read and displayed in the console.
* The XMP object is then dumped to a text file and the resource file is closed.
*/
int main ( int argc, const char * argv[] )
{
if ( argc != 2 ) // 2 := command and 1 parameter
{
cout << "usage: ReadingXMP (filename)" << endl;
return 0;
}
string filename = string( argv[1] );
if(!SXMPMeta::Initialize())
{
cout << "Could not initialize toolkit!";
return -1;
}
XMP_OptionBits options = 0;
#if UNIX_ENV
options |= kXMPFiles_ServerMode;
#endif
// Must initialize SXMPFiles before we use it
if ( ! SXMPFiles::Initialize ( options ) )
{
cout << "Could not initialize SXMPFiles.";
return -1;
}
try
{
// Options to open the file with - read only and use a file handler
XMP_OptionBits opts = kXMPFiles_OpenForRead | kXMPFiles_OpenUseSmartHandler;
bool ok;
SXMPFiles myFile;
std::string status = "";
// First we try and open the file
ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts);
if( ! ok )
{
status += "No smart handler available for " + filename + "\n";
status += "Trying packet scanning.\n";
// Now try using packet scanning
opts = kXMPFiles_OpenForUpdate | kXMPFiles_OpenUsePacketScanning;
ok = myFile.OpenFile(filename, kXMP_UnknownFile, opts);
}
// If the file is open then read the metadata
if(ok)
{
cout << status << endl;
cout << filename << " is opened successfully" << endl;
// Create the xmp object and get the xmp data
SXMPMeta meta;
myFile.GetXMP(&meta);
bool exists;
// Read a simple property
string simpleValue; //Stores the value for the property
exists = meta.GetProperty(kXMP_NS_XMP, "CreatorTool", &simpleValue, NULL);
if(exists)
cout << "CreatorTool = " << simpleValue << endl;
else
simpleValue.clear();
// Get the first element in the dc:creator array
string elementValue;
exists = meta.GetArrayItem(kXMP_NS_DC, "creator", 1, &elementValue, NULL);
if(exists)
cout << "dc:creator = " << elementValue << endl;
else
elementValue.clear();
// Get the the entire dc:subject array
string propValue;
int arrSize = meta.CountArrayItems(kXMP_NS_DC, "subject");
for(int i = 1; i <= arrSize;i++)
{
meta.GetArrayItem(kXMP_NS_DC, "subject", i, &propValue, 0);
cout << "dc:subject[" << i << "] = " << propValue << endl;
}
// Get the dc:title for English and French
string itemValue;
string actualLang;
meta.GetLocalizedText(kXMP_NS_DC, "title", "en", "en-US", NULL, &itemValue, NULL);
cout << "dc:title in English = " << itemValue << endl;
meta.GetLocalizedText(kXMP_NS_DC, "title", "fr", "fr-FR", NULL, &itemValue, NULL);
cout << "dc:title in French = " << itemValue << endl;
// Get dc:MetadataDate
XMP_DateTime myDate;
if(meta.GetProperty_Date(kXMP_NS_XMP, "MetadataDate", &myDate, NULL))
{
// Convert the date struct into a convenient string and display it
string myDateStr;
SXMPUtils::ConvertFromDate(myDate, &myDateStr);
cout << "meta:MetadataDate = " << myDateStr << endl;
}
// See if the flash struct exists and see if it was used
string path, value;
exists = meta.DoesStructFieldExist(kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF,"Fired");
if(exists)
{
bool flashFired;
SXMPUtils::ComposeStructFieldPath(kXMP_NS_EXIF, "Flash", kXMP_NS_EXIF, "Fired", &path);
meta.GetProperty_Bool(kXMP_NS_EXIF, path.c_str(), &flashFired, NULL);
string flash = (flashFired) ? "True" : "False";
cout << "Flash Used = " << flash << endl;
}
// Dump the current xmp object to a file
ofstream dumpFile;
dumpFile.open("XMPDump.txt", ios::out);
meta.DumpObject(DumpXMPToFile, &dumpFile);
dumpFile.close();
cout << endl << "XMP dumped to XMPDump.txt" << endl;
// Close the SXMPFile. The resource file is already closed if it was
// opened as read only but this call must still be made.
myFile.CloseFile();
}
else
{
cout << "Unable to open " << filename << endl;
}
}
catch(XMP_Error & e)
{
cout << "ERROR: " << e.GetErrMsg() << endl;
}
// Terminate the toolkit
SXMPFiles::Terminate();
SXMPMeta::Terminate();
return 0;
}
6.项目结构
.
├── 3rdLibs
│ ├── XMP-Toolkit-SDK
│ ├── include
│ │ ├── TXMPFiles.hpp
│ │ ├── TXMPIterator.hpp
│ │ ├── TXMPMeta.hpp
│ │ ├── TXMPUtils.hpp
│ │ ├── XMP.hpp
│ │ ├── XMP.incl_cpp
│ │ ├── XMPCommon
│ │ │ ├── Interfaces
│ │ │ │ ├── BaseInterfaces
│ │ │ │ │ ├── IConfigurable.h
│ │ │ │ │ ├── ISharedObject.h
│ │ │ │ │ ├── IThreadSafe.h
│ │ │ │ │ └── IVersionable.h
│ │ │ │ ├── IConfigurationManager.h
│ │ │ │ ├── IError.h
│ │ │ │ ├── IErrorNotifier.h
│ │ │ │ ├── IMemoryAllocator.h
│ │ │ │ ├── IObjectFactory.h
│ │ │ │ └── IUTF8String.h
│ │ │ ├── Utilities
│ │ │ │ ├── TWrapperFunctions.h
│ │ │ │ └── TWrapperFunctions2.h
│ │ │ ├── XMPCommonDefines.h
│ │ │ ├── XMPCommonErrorCodes.h
│ │ │ ├── XMPCommonFwdDeclarations.h
│ │ │ ├── XMPCommonLatestInterfaceVersions.h
│ │ │ └── source
│ │ │ ├── IConfigurable.cpp
│ │ │ ├── IConfigurationManager.cpp
│ │ │ ├── IError.cpp
│ │ │ ├── IErrorNotifier.cpp
│ │ │ └── IUTF8String.cpp
│ │ ├── XMPCore
│ │ │ ├── Interfaces
│ │ │ │ ├── IArrayNode.h
│ │ │ │ ├── IClientDOMParser.h
│ │ │ │ ├── IClientDOMSerializer.h
│ │ │ │ ├── ICompositeNode.h
│ │ │ │ ├── ICoreConfigurationManager.h
│ │ │ │ ├── ICoreObjectFactory.h
│ │ │ │ ├── IDOMImplementationRegistry.h
│ │ │ │ ├── IDOMParser.h
│ │ │ │ ├── IDOMSerializer.h
│ │ │ │ ├── IMetadata.h
│ │ │ │ ├── IMetadataConverterUtils.h
│ │ │ │ ├── INameSpacePrefixMap.h
│ │ │ │ ├── INode.h
│ │ │ │ ├── INodeIterator.h
│ │ │ │ ├── IPath.h
│ │ │ │ ├── IPathSegment.h
│ │ │ │ ├── ISimpleNode.h
│ │ │ │ └── IStructureNode.h
│ │ │ ├── XMPCoreDefines.h
│ │ │ ├── XMPCoreErrorCodes.h
│ │ │ ├── XMPCoreFwdDeclarations.h
│ │ │ ├── XMPCoreLatestInterfaceVersions.h
│ │ │ └── source
│ │ │ ├── IArrayNode.cpp
│ │ │ ├── IClientDOMParser.cpp
│ │ │ ├── IClientDOMSerializer.cpp
│ │ │ ├── ICompositeNode.cpp
│ │ │ ├── ICoreConfigurationManager.cpp
│ │ │ ├── ICoreObjectFactory.cpp
│ │ │ ├── IDOMImplementationRegistry.cpp
│ │ │ ├── IDOMParser.cpp
│ │ │ ├── IDOMSerializer.cpp
│ │ │ ├── IMetadata.cpp
│ │ │ ├── IMetadataConverterUtils.cpp
│ │ │ ├── INameSpacePrefixMap.cpp
│ │ │ ├── INode.cpp
│ │ │ ├── INodeIterator.cpp
│ │ │ ├── IPath.cpp
│ │ │ ├── IPathSegment.cpp
│ │ │ ├── ISimpleNode.cpp
│ │ │ └── IStructureNode.cpp
│ │ ├── XMP_Const.h
│ │ ├── XMP_Environment.h
│ │ ├── XMP_IO.hpp
│ │ ├── XMP_Version.h
│ │ └── client-glue
│ │ ├── TXMPFiles.incl_cpp
│ │ ├── TXMPIterator.incl_cpp
│ │ ├── TXMPMeta.incl_cpp
│ │ ├── TXMPUtils.incl_cpp
│ │ ├── WXMPFiles.hpp
│ │ ├── WXMPIterator.hpp
│ │ ├── WXMPMeta.hpp
│ │ ├── WXMPUtils.hpp
│ │ └── WXMP_Common.hpp
│ └── libs
│ ├── XMPCore.dll
│ ├── XMPCore.exp
│ ├── XMPCore.lib
│ ├── XMPCore.map
│ ├── XMPCore.pdb
│ ├── XMPFiles.dll
│ ├── XMPFiles.exp
│ ├── XMPFiles.lib
│ ├── XMPFiles.map
│ ├── XMPFiles.pdb
│ ├── libXMPCore.so
│ └── libXMPFiles.so
│
├── CMakeLists.txt
├── ReadMe.md
├── source
└── XMPModify.cc
7.CMake工程
cmake_minimum_required(VERSION 3.1...3.26)
project(XMPEditor LANGUAGES CXX C)
# Set C and C++ standard version
set(CMAKE_C_STANDARD_REQUIRED True)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include_directories(
${CMAKE_CURRENT_LIST_DIR}/3rdLibs/XMP-Toolkit-SDK/include
)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Release")
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release")
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
set (OBJECTS_TO_LINK "")
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
message("-- current platform: Linux ")
file (GLOB libs ${CMAKE_CURRENT_LIST_DIR}/3rdLibs/XMP-Toolkit-SDK/libs/*.so)
list (APPEND OBJECTS_TO_LINK ${libs})
add_compile_definitions(-DUNIX_ENV)
elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
message("-- current platform: Windows ")
file (GLOB libs ${CMAKE_CURRENT_LIST_DIR}/3rdLibs/XMP-Toolkit-SDK/libs/*.lib)
list (APPEND OBJECTS_TO_LINK ${libs})
add_compile_definitions(-DWIN_ENV)
endif()
add_executable(TestXMPModify source/TestXMPModify.cc)
target_link_libraries(TestXMPModify ${OBJECTS_TO_LINK})