Skip to content

Commit f767cad

Browse files
OCIOZ archive feature (#1627) (#1696)
* OCIOZ archive feature (#1627) Signed-off-by: Cedrik Fuoco <[email protected]> * Add OCIOZ extension if not present. Signed-off-by: Cedrik Fuoco <[email protected]> * - Changing getLutData (return vector instead of passing by reference) in order to respect C++ idiom and letting compiler optimize with NRVO and Copy elision - Improving how cmake find zlib (renamed getZLIB to Findzlib) - Make sure that ZLIB is statically linked on all platform (it wasn't on windows) - Fix issue with Python Unit test when using Python 2 (problem discovered on OSX) - Change how OpenEXR finds ZLIB by using our custom Findzlib - Patching Minizip-ng makefile to change cmake minimum version Signed-off-by: Cedrik Fuoco <[email protected]> * - Remove the minizip-ng patch as it doesn't work and further discussion needs to happend. - Responding to Remi's comments. Notable changes: - Comments typo and styles fix. - Unit tests fixes. - Removing the usage of std::ifstream in getLutData and getConfig since it is not needed at all - It was slowing down getLutData. - Implicitly converting python list to std::vector<uint8_t> (for getLutData) - When archiving a config, the file won't added (overwridden) multiple times if the file matches multiple supported format. Signed-off-by: Cedrik Fuoco <[email protected]> * - Added implicit conversion from bytearray to std::vector<uint8_t> - In ConfigIOProxy Python Unit test, changed getLutData to return a bytearray instead of a list. I think this makes more sense and it works with Python 2 and 3. Signed-off-by: Cedrik Fuoco <[email protected]> * Update comments to be in line with the current implementations Signed-off-by: Cedrik Fuoco <[email protected]> * - Changing ci workflow in order to install cmake version 3.13.3 for Linux (matrix.vfx-cy == '2019'). Signed-off-by: Cedrik Fuoco <[email protected]> * - Fixing issue with the install location of zlib library - Removing unused CMAKE variables from ZLIB_CMAKE_ARGS Signed-off-by: Cedrik Fuoco <[email protected]> Signed-off-by: Cedrik Fuoco <[email protected]> Co-authored-by: Doug Walker <[email protected]>
1 parent 521ed08 commit f767cad

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+3903
-72
lines changed

.github/workflows/ci_workflow.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ jobs:
252252
steps:
253253
- name: Checkout
254254
uses: actions/checkout@v2
255+
# minizip-ng requires CMake 3.13+ but VFX2019 image ships with 3.12
256+
- name: Upgrade VFX2019 CMake
257+
run: pip install cmake==3.13.3
258+
if: matrix.vfx-cy == '2019'
255259
- name: Install docs env
256260
run: share/ci/scripts/linux/yum/install_docs_env.sh
257261
if: matrix.build-docs == 'ON'

include/OpenColorIO/OpenColorIO.h

Lines changed: 190 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
#include <limits>
1111
#include <stdexcept>
1212
#include <string>
13+
#include <fstream>
14+
#include <vector>
1315

1416
#include "OpenColorABI.h"
1517
#include "OpenColorTypes.h"
1618
#include "OpenColorTransforms.h"
1719
#include "OpenColorAppHelpers.h"
1820

19-
2021
/*
2122
2223
C++ API
@@ -174,6 +175,8 @@ extern OCIOEXPORT void LogMessage(LoggingLevel level, const char * message);
174175
/**
175176
* \brief Set the Compute Hash Function to use; otherwise, use the default.
176177
*
178+
* This is not used when using CreateFromFile with an OCIOZ archive or CreateFromConfigIOProxy.
179+
*
177180
* \param ComputeHashFunction
178181
*/
179182
extern OCIOEXPORT void SetComputeHashFunction(ComputeHashFunction hashFunction);
@@ -201,6 +204,26 @@ extern OCIOEXPORT ConstConfigRcPtr GetCurrentConfig();
201204
/// Set the current configuration. This will then store a copy of the specified config.
202205
extern OCIOEXPORT void SetCurrentConfig(const ConstConfigRcPtr & config);
203206

207+
/**
208+
* \brief Extract an OCIO Config archive.
209+
*
210+
* Converts an archived config file (.ocioz file) back to its original form as a config file
211+
* and associated LUT files. This creates destinationDir and then creates a config.ocio file
212+
* at the root of that working directory and then unpacks the LUT files into their relative
213+
* locations relative to that working directory, creating any necessary sub-directories in the
214+
* process. Note that configs which contain LUT files outside the working directory are not
215+
* archivable, and so this function will not create directories outside the working directory.
216+
*
217+
* \param archivePath Absolute path to the .ocioz file.
218+
* \param destinationDir Absolute path of the directory you want to be created to contain the
219+
* contents of the unarchived config.
220+
* \throw Exception If the archive is not found or there is a problem extracting it.
221+
*/
222+
extern OCIOEXPORT void ExtractOCIOZArchive(
223+
const char * archivePath,
224+
const char * destinationDir
225+
);
226+
204227
/**
205228
* \brief
206229
* A config defines all the color spaces to be available at runtime.
@@ -245,49 +268,89 @@ class OCIOEXPORT Config
245268
* \brief Create an empty config of the current version.
246269
*
247270
* Note that an empty config will not pass validation since required elements will be missing.
271+
* \return The Config object.
248272
*/
249273
static ConfigRcPtr Create();
274+
250275
/**
251276
* \brief Create a fall-back config.
252277
*
253278
* This may be useful to allow client apps to launch in cases when the
254279
* supplied config path is not loadable.
280+
* \return The Config object.
255281
*/
256282
static ConstConfigRcPtr CreateRaw();
283+
257284
/**
258285
* \brief Create a configuration using the OCIO environment variable.
259286
*
260-
* Also support OCIO URI format. See CreateFromFile.
287+
* Also supports the OCIO URI format for Built-in configs and supports archived configs.
288+
* See \ref Config::CreateFromFile.
261289
*
262290
* If the variable is missing or empty, returns the same result as
263-
* \ref Config::CreateRaw .
291+
* \ref Config::CreateRaw.
292+
* \return The Config object.
264293
*/
265294
static ConstConfigRcPtr CreateFromEnv();
295+
266296
/**
267297
* \brief Create a configuration using a specific config file.
268298
*
269-
* Also support the following OCIO URI format :
299+
* Also supports the following OCIO URI format for Built-in configs:
270300
* "ocio://default" - Default Built-in config.
271-
* "ocio://configName" - Built-in config named configName
272-
*
301+
* "ocio://<CONFIG NAME>" - A specific Built-in config. For the list of available
302+
* <CONFIG NAME> strings, see \ref Config::CreateFromBuiltinConfig.
303+
*
304+
* Also supports archived configs (.ocioz files).
305+
*
306+
* \throw Exception If the file may not be read or does not parse.
307+
* \return The Config object.
273308
*/
274309
static ConstConfigRcPtr CreateFromFile(const char * filename);
275-
/// Create a configuration using a stream.
310+
311+
/**
312+
* \brief Create a configuration using a stream.
313+
*
314+
* Note that CreateFromStream does not set the working directory so the caller would need to
315+
* set that separately in order to resolve FileTransforms. This function is typically only
316+
* used for self-contained configs (no LUTs).
317+
*
318+
* Configs created from CreateFromStream can not be archived unless the working directory is
319+
* set and contains any necessary LUT files.
320+
*
321+
* \param istream Stream to the config.
322+
* \throw Exception If the stream does not parse.
323+
* \return The Config object.
324+
*/
276325
static ConstConfigRcPtr CreateFromStream(std::istream & istream);
277326

327+
/**
328+
* \brief Create a config from the supplied ConfigIOProxy object. This allows the calling
329+
* program to directly provide the config and associated LUTs rather than reading them from
330+
* the standard file system.
331+
*
332+
* See the \ref ConfigIOProxy class documentation for more info.
333+
*
334+
* \param ciop ConfigIOProxy object providing access to the config's files.
335+
* \throw Exception If the config may not be read from the proxy, or does not parse.
336+
* \return The Config object.
337+
*/
338+
static ConstConfigRcPtr CreateFromConfigIOProxy(ConfigIOProxyRcPtr ciop);
339+
278340
/**
279341
* \brief Create a configuration using an OCIO built-in config.
280342
*
281-
* \param configName Built-in config name
343+
* \param configName Built-in config name.
282344
*
283345
* The available configNames are:
284346
* "cg-config-v0.1.0_aces-v1.3_ocio-v2.1.1" -- ACES CG config, basic color spaces for computer
285-
* graphics apps. More information is available at:
347+
* graphics apps. More information about these configs is available at:
286348
* %https://github.com/AcademySoftwareFoundation/OpenColorIO-Config-ACES
287349
*
288-
* \throw Exception If the configName is not recognized.
350+
* Information about the available configs is available from the \ref BuiltinConfigRegistry.
289351
*
290-
* \return one of the configs built into OCIO library
352+
* \throw Exception If the configName is not recognized.
353+
* \return One of the configs built into the OCIO library.
291354
*/
292355
static ConstConfigRcPtr CreateFromBuiltinConfig(const char * configName);
293356

@@ -1149,6 +1212,62 @@ class OCIOEXPORT Config
11491212
const char * dstColorSpaceName,
11501213
const char * dstInterchangeName);
11511214

1215+
/// Set the ConfigIOProxy object used to provision the config and LUTs from somewhere other
1216+
/// than the file system. (This is set on the config's embedded Context object.)
1217+
void setConfigIOProxy(ConfigIOProxyRcPtr ciop);
1218+
ConfigIOProxyRcPtr getConfigIOProxy() const;
1219+
1220+
/**
1221+
* \brief Verify if the config is archivable.
1222+
*
1223+
* A config is not archivable if any of the following are true:
1224+
* -- The working directory is not set
1225+
* -- It contains FileTransforms with a src outside the working directory
1226+
* -- The search path contains paths outside the working directory
1227+
* -- The search path contains paths that start with a context variable
1228+
*
1229+
* Context variables are allowed but the intent is that they may only resolve to paths that
1230+
* are within or below the working directory. This is because the archiving function will
1231+
* only archive files that are within the working directory in order to ensure that if it is
1232+
* later expanded, that it will not create any files outside this directory.
1233+
*
1234+
* For example, a context variable on the search path intended to contain the name of a
1235+
* sub-directory under the working directory must have the form "./$DIR_NAME" rather than just
1236+
* "$DIR_NAME" to be considered archivable. This is imperfect since there is no way to
1237+
* prevent the context variable from creating a path outside the working dir, but it should
1238+
* at least draw attention to the fact that the archive would fail if used with context vars
1239+
* that try to abuse the intended functionality.
1240+
*
1241+
* \return bool Archivable if true.
1242+
*/
1243+
bool isArchivable() const;
1244+
1245+
/**
1246+
* \brief Archive the config and its LUTs into the specified output stream.
1247+
*
1248+
* The config is archived by serializing the Config object into a file named "config.ocio" and
1249+
* then walking through the current working directory and any sub-directories. Any files that
1250+
* have an extension matching a supported LUT file format are added to the archive. Any files
1251+
* that do not have an extension (or have some unsupported LUT extension, including .ocio),
1252+
* will not be added to the archive. To reiterate, it is the in-memory Config object that is
1253+
* archived, and not any .ocio file in the current working directory. The directory structure
1254+
* relative to the working directory is preserved. No files outside the working directory are
1255+
* archived so that if it is later expanded, no files will be created outside the working dir.
1256+
*
1257+
* The reason the archive is created using all supported LUT file extensions rather than by
1258+
* trying to resolve all the FileTransforms in the Config to specific files is because of the
1259+
* goal to allow context variables to continue to work.
1260+
*
1261+
* If a Config is created with CreateFromStream, CreateFromFile with an OCIOZ archive, or
1262+
* CreateFromConfigIOProxy, it cannot be archived unless the working directory is manually set
1263+
* to a directory that contains any necessary LUT files.
1264+
*
1265+
* The provided output stream must be closed by the caller, if necessary (e.g., an ofstream).
1266+
*
1267+
* \param ostream The output stream to write to.
1268+
*/
1269+
void archive(std::ostream & ostream) const;
1270+
11521271
Config(const Config &) = delete;
11531272
Config& operator= (const Config &) = delete;
11541273

@@ -3269,6 +3388,11 @@ class OCIOEXPORT Context
32693388
/// used to resolve the filename (empty if no context variables were used).
32703389
const char * resolveFileLocation(const char * filename, ContextRcPtr & usedContextVars) const;
32713390

3391+
/// Set the ConfigIOProxy object used to provision the config and LUTs from somewhere other
3392+
/// than the file system.
3393+
void setConfigIOProxy(ConfigIOProxyRcPtr ciop);
3394+
ConfigIOProxyRcPtr getConfigIOProxy() const;
3395+
32723396
Context(const Context &) = delete;
32733397
Context& operator= (const Context &) = delete;
32743398
/// Do not use (needed only for pybind11).
@@ -3437,6 +3561,61 @@ class OCIOEXPORT SystemMonitors
34373561
virtual ~SystemMonitors() = default;
34383562
};
34393563

3564+
3565+
///////////////////////////////////////////////////////////////////////////
3566+
// ConfigIOProxy
3567+
3568+
/**
3569+
* ConfigIOProxy is a proxy class to allow the calling program to supply the config and any
3570+
* associated LUT files directly, without relying on the standard file system.
3571+
*
3572+
* The OCIOZ archive feature is implemented using this mechanism.
3573+
*/
3574+
class OCIOEXPORT ConfigIOProxy
3575+
{
3576+
public:
3577+
ConfigIOProxy() = default;
3578+
virtual ~ConfigIOProxy() = default;
3579+
3580+
/**
3581+
* \brief Provide the contents of a LUT file as a buffer of uint8_t data.
3582+
*
3583+
* \param filepath Fully resolved path to the "file."
3584+
*
3585+
* The file path is based on the Config's current working directory and is the same absolute
3586+
* path that would have been provided to the file system.
3587+
*
3588+
* \return Vector of uint8 with the content of the LUT.
3589+
*/
3590+
virtual std::vector<uint8_t> getLutData(const char * filepath) const = 0;
3591+
3592+
/**
3593+
* \brief Provide the config file Yaml to be parsed.
3594+
*
3595+
* \return String with the config Yaml.
3596+
*/
3597+
virtual std::string getConfigData() const = 0;
3598+
3599+
/**
3600+
* \brief Provide a fast unique ID for a LUT file.
3601+
*
3602+
* This is intended to supply the string that will be used in OCIO's FileCacheMap.
3603+
* This should be highly performant and typically should not require extensive
3604+
* computation such as calculating the md5 hash of the file, unless it is pre-computed.
3605+
*
3606+
* If the "file" does not exist, in other words, if the proxy is unable to supply the requested
3607+
* file contents, the function must return an empty string.
3608+
*
3609+
* \param filepath Fully resolve the path to the "file."
3610+
*
3611+
* The file path is based on the Config's current working directory and is the same absolute
3612+
* path that would have been provided to the file system.
3613+
*
3614+
* \return The file hash string.
3615+
*/
3616+
virtual std::string getFastLutFileHash(const char * filepath) const = 0;
3617+
};
3618+
34403619
} // namespace OCIO_NAMESPACE
34413620

34423621
#endif // INCLUDED_OCIO_OPENCOLORIO_H

include/OpenColorIO/OpenColorTypes.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class OCIOEXPORT GradingRGBCurve;
114114
typedef OCIO_SHARED_PTR<const GradingRGBCurve> ConstGradingRGBCurveRcPtr;
115115
typedef OCIO_SHARED_PTR<GradingRGBCurve> GradingRGBCurveRcPtr;
116116

117+
class OCIOEXPORT ConfigIOProxy;
118+
typedef OCIO_SHARED_PTR<const ConfigIOProxy> ConstConfigIOProxyRcPtr;
119+
typedef OCIO_SHARED_PTR<ConfigIOProxy> ConfigIOProxyRcPtr;
120+
117121
typedef std::array<float, 3> Float3;
118122

119123

@@ -960,6 +964,13 @@ extern OCIOEXPORT const char * OCIO_DISABLE_CACHE_FALLBACK;
960964

961965
/** @}*/
962966

967+
968+
// Archive config feature
969+
// Default filename (with extension) of an config.
970+
extern OCIOEXPORT const char * OCIO_CONFIG_DEFAULT_NAME;
971+
extern OCIOEXPORT const char * OCIO_CONFIG_DEFAULT_FILE_EXT;
972+
extern OCIOEXPORT const char * OCIO_CONFIG_ARCHIVE_FILE_EXT;
973+
963974
} // namespace OCIO_NAMESPACE
964975

965976
#endif

share/cmake/modules/FindExtPackages.cmake

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ find_package(pystring 1.1.3 REQUIRED)
4141
set(_Imath_ExternalProject_VERSION "3.1.5")
4242
find_package(Imath 3.0 REQUIRED)
4343

44+
# ZLIB
45+
# https://github.com/madler/zlib
46+
set(_zlib_ExternalProject_VERSION "1.2.12")
47+
find_package(zlib REQUIRED)
48+
49+
# minizip-ng
50+
# https://github.com/zlib-ng/minizip-ng
51+
find_package(minizip-ng 3.0.6 REQUIRED)
52+
4453
if(OCIO_BUILD_APPS)
4554

4655
# NOTE: Depending of the compiler version lcms2 2.2 does not compile with

share/cmake/modules/FindOpenEXR.cmake

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ if(NOT OpenEXR_FOUND AND NOT OCIO_INSTALL_EXT_PACKAGES STREQUAL NONE)
8585
set(_EXT_BUILD_ROOT "${CMAKE_BINARY_DIR}/ext/build")
8686

8787
# Required dependency
88-
find_package(ZLIB)
88+
# OCIO custom module to find ZLIB. (Findzlib)
89+
find_package(zlib)
8990
if(NOT ZLIB_FOUND)
9091
message(STATUS "ZLib is required to build OpenEXR.")
9192
return()

0 commit comments

Comments
 (0)