Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Use oiio plugins to handle EXR files #563

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 104 additions & 23 deletions plugins/image/io/OpenImageIO/src/writer/OpenImageIOWriterDefinitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,19 @@ enum ETuttlePluginComponents
static const std::string kParamOutputQuality = "quality";
static const std::string kParamOutputQualityLabel = "Quality";

static const std::string kParamOutputStorageType = "storage";
static const std::string kParamOutputStorageTypeLabel = "Storage type";
static const std::string kParamOutputStorageTypeHint = "Set the type of storage of the output file.\n"
"It could be ignored depending on the format.\n";
static const std::string kParamOutputStorageScanLine = "scanLine";
static const std::string kParamOutputStorageTiles = "tiles (64x64)";

enum ETuttlePluginStorage
{
eTuttlePluginStorageScanLine = 0,
eTuttlePluginStorageTiles
};

enum ETuttlePluginSubsampling
{
eETuttlePluginSubsampling420 = 0,
Expand Down Expand Up @@ -69,31 +82,99 @@ static const std::string kParamOutputOrientationR90Clockwise = "90clockwise";
static const std::string kParamOutputOrientationTransverse = "transverse";
static const std::string kParamOutputOrientationR90CounterClockwise = "90counter-clockwise";

static const std::string kParamOutputCompression = "compression";
static const std::string kParamOutputCompressionLabel = "Compression";

static const std::string kParamOutputCompressionNone = "none No compression";
static const std::string kParamOutputCompressionZip = "zip Compression zlib, with blocs of 16 scanlines.";
static const std::string kParamOutputCompressionZips = "zips Compression zlib, with blocs with only one scanline.";
static const std::string kParamOutputCompressionRle = "rle Compression Run Length Encoding.";
static const std::string kParamOutputCompressionPiz = "piz Piz-based wavelet compression.";
static const std::string kParamOutputCompressionPxr24 = "pxr24 Compression (with loss) in 24bit float";
static const std::string kParamOutputCompressionB44 =
"b44 Compression (with loss) with blocs of size 4x4 pixels. Fix rate of compression.";
static const std::string kParamOutputCompressionB44a =
"b44a Compression (with loss) with blocs of size 4x4 pixels. Non-fix rate of compression.";

enum EParamCompression
static const std::string kParamCompression = "compression";
static const std::string kParamCompressionLabel = "Compression";
static const std::string kParamCompressionNone = "None";
static const std::string kParamCompressionRLE = "RLE";
static const std::string kParamCompressionZIPS = "ZIPS";
static const std::string kParamCompressionZIP = "ZIP";
static const std::string kParamCompressionPIZ = "PIZ";
static const std::string kParamCompressionPXR24 = "PXR24";
static const std::string kParamCompressionB44 = "B44";
static const std::string kParamCompressionB44A = "B44A";

enum ETuttlePluginCompression
{
eParamCompressionNone = 0,
eParamCompressionZip,
eParamCompressionZips,
eParamCompressionRle,
eParamCompressionPiz,
eParamCompressionPxr24,
eParamCompressionB44,
eParamCompressionB44a
eTuttlePluginCompressionNone = 0,
eTuttlePluginCompressionRLE,
eTuttlePluginCompressionZIP,
eTuttlePluginCompressionZIPS,
eTuttlePluginCompressionPIZ,
eTuttlePluginCompressionPXR24,
eTuttlePluginCompressionB44,
eTuttlePluginCompressionB44A
};

static const std::string kParamCompressionHintNone = "No compression.";
static const std::string kParamCompressionHintRLE =
"Lossless, Run length encoding.\n"
"Differences between horizontally adjacent pixels are run-length encoded. This "
"method is fast, and works well for images with large flat areas, but for photographic "
"images, the compressed file size is usually between 60 and 75 percent of the "
"uncompressed size.";
static const std::string kParamCompressionHintZIP =
"Lossless zlib compression, in blocks of 16 scan lines.\n"
"Differences between horizontally adjacent pixels are compressed using the open-"
"source zlib library. ZIP decompression is faster than PIZ decompression, but ZIP "
"compression is significantly slower. Photographic images tend to shrink to between "
"45 and 55 percent of their uncompressed size.\n"
"Multi-resolution files are often used as texture maps for 3D renderers. For this "
"application, fast read accesses are usually more important than fast writes, or "
"maximum compression. For texture maps, ZIP is probably the best compression "
"method.\n"
"In scan-line based files, 16 rows of pixels are accumulated and compressed "
"together as a single block.";
static const std::string kParamCompressionHintZIPS =
"Lossless, zlib compression, one scan line at a time.\n"
"Uses the open-source zlib library for compression. Like ZIP compression, but "
"operates on one scan line at a time.";
static const std::string kParamCompressionHintPIZ =
"Lossless, piz-based wavelet compression.\n"
"A wavelet transform is applied to the pixel data, and the result is Huffman-"
"encoded. This scheme tends to provide the best compression ratio for the types of "
"images that are typically processed at Industrial Light & Magic. Files are "
"compressed and decompressed at roughly the same speed. For photographic "
"images with film grain, the files are reduced to between 35 and 55 percent of their "
"uncompressed size.\n"
"PIZ compression works well for scan-line based files, and also for tiled files with "
"large tiles, but small tiles do not shrink much. (PIZ-compressed data start with a "
"relatively long header; if the input to the compressor is short, adding the header "
"tends to offset any size reduction of the input.)\n"
"PIZ compression is only supported for flat images.";
static const std::string kParamCompressionHintPXR24 =
"Lossy, 24-bit float compression.\n"
"After reducing 32-bit floating-point data to 24 bits by rounding (while leaving 16-bit "
"floating-point data unchanged), differences between horizontally adjacent pixels "
"are compressed with zlib, similar to ZIP. PXR24 compression preserves image "
"channels of type HALF and UINT exactly, but the relative error of FLOAT data "
"increases to about 3x10^-5. This compression method works well for depth "
"buffers and similar images, where the possible range of values is very large, but "
"where full 32-bit floating-point accuracy is not necessary. Rounding improves "
"compression significantly by eliminating the pixels' 8 least significant bits, which "
"tend to be very noisy, and therefore difficult to compress.\n"
"PXR24 compression is only supported for flat images.";
static const std::string kParamCompressionHintB44 =
"Lossy, 4-by-4 pixel block compression fixed compression rate.\n"
"Channels of type HALF are split into blocks of four by four pixels or 32 bytes. Each "
"block is then packed into 14 bytes, reducing the data to 44 percent of their "
"uncompressed size. When B44 compression is applied to RGB images in "
"combination with luminance/chroma encoding (see below), the size of the "
"compressed pixels is about 22 percent of the size of the original RGB data. "
"Channels of type UINT or FLOAT are not compressed. "
"Decoding is fast enough to allow real-time playback of B44-compressed OpenEXR "
"image sequences on commodity hardware. "
"The size of a B44-compressed file depends on the number of pixels in the image, "
"but not on the data in the pixels. All images with the same resolution and the same "
"set of channels have the same size. This can be advantageous for systems that "
"support real-time playback of image sequences; the predictable file size makes it "
"easier to allocate space on storage media efficiently. "
"B44 compression is only supported for flat images.";
static const std::string kParamCompressionHintB44A =
"Lossy, 4-by-4 pixel block compression flat fields are compressed more.\n"
"Like B44, except for blocks of four by four pixels where all pixels have the same "
"value, which are packed into 3 instead of 14 bytes. For images with large uniform "
"areas, B44A produces smaller files than B44 compression. "
"B44A compression is only supported for flat images.";
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ OpenImageIOWriterPlugin::OpenImageIOWriterPlugin(OfxImageEffectHandle handle)
_components = fetchChoiceParam(kTuttlePluginChannel);
_orientation = fetchChoiceParam(kParamOutputOrientation);
_quality = fetchIntParam(kParamOutputQuality);
_storageType = fetchChoiceParam(kParamOutputStorageType);
_paramSubsampling = fetchChoiceParam(kParamOutputSubsampling);
_compression = fetchChoiceParam(kParamCompression);
}

OpenImageIOWriterProcessParams OpenImageIOWriterPlugin::getProcessParams(const OfxTime time)
Expand All @@ -30,7 +32,9 @@ OpenImageIOWriterProcessParams OpenImageIOWriterPlugin::getProcessParams(const O
params._filepath = getAbsoluteFilenameAt(time);
params._components = static_cast<ETuttlePluginComponents>(this->_components->getValue());
params._bitDepth = static_cast<ETuttlePluginBitDepth>(this->_paramBitDepth->getValue());
params._storageType = static_cast<ETuttlePluginStorage>(this->_storageType->getValue());
params._subsampling = static_cast<ETuttlePluginSubsampling>(_paramSubsampling->getValue());
params._compression = static_cast<ETuttlePluginCompression>(_compression->getValue());
params._quality = _quality->getValue();
params._orientation = static_cast<int>(_orientation->getValue());
params._premultiply = this->_paramPremult->getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ struct OpenImageIOWriterProcessParams
std::string _filepath; ///< filepath
ETuttlePluginComponents _components; ///< Force RGB
ETuttlePluginBitDepth _bitDepth; ///< Output bit depth (real bit depth, not the buffer passed to OpenImageIO)
ETuttlePluginStorage _storageType; ///< Output storage type
ETuttlePluginSubsampling _subsampling; ///< Output subsampling
ETuttlePluginCompression _compression; ///< Output compression

bool _premultiply; ///< Output premultiply
int _quality; ///< Output quality
Expand All @@ -43,8 +45,10 @@ class OpenImageIOWriterPlugin : public WriterPlugin
public:
OFX::ChoiceParam* _components; ///< Choose components RGBA/RGB
OFX::IntParam* _quality;
OFX::ChoiceParam* _storageType;
OFX::ChoiceParam* _paramSubsampling;
OFX::ChoiceParam* _orientation;
OFX::ChoiceParam* _compression;
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ void OpenImageIOWriterPluginFactory::describeInContext(OFX::ImageEffectDescripto
quality->setDisplayRange(0, 100);
quality->setDefault(80);

OFX::ChoiceParamDescriptor* storageType = desc.defineChoiceParam(kParamOutputStorageType);
storageType->setLabel(kParamOutputStorageTypeLabel);
storageType->setHint(kParamOutputStorageTypeHint);
storageType->appendOption(kParamOutputStorageScanLine);
storageType->appendOption(kParamOutputStorageTiles);
storageType->setDefault(eTuttlePluginStorageScanLine);

OFX::ChoiceParamDescriptor* subsampling = desc.defineChoiceParam(kParamOutputSubsampling);
subsampling->setLabel(kParamOutputSubsamplingLabel);
subsampling->setHint(kParamOutputSubsamplingHint);
Expand All @@ -126,23 +133,17 @@ void OpenImageIOWriterPluginFactory::describeInContext(OFX::ImageEffectDescripto
orientation->appendOption(kParamOutputOrientationR90CounterClockwise);
orientation->setDefault(0);

OFX::ChoiceParamDescriptor* compression = desc.defineChoiceParam(kParamOutputCompression);
compression->setLabel(kParamOutputOrientationLabel);
#if(TUTTLE_EXPERIMENTAL)
compression->appendOption(kParamOutputCompressionNone);
#endif
compression->appendOption(kParamOutputCompressionZip);
#if(TUTTLE_EXPERIMENTAL)
compression->appendOption(kParamOutputCompressionZips);
compression->appendOption(kParamOutputCompressionRle);
compression->appendOption(kParamOutputCompressionPiz);
compression->appendOption(kParamOutputCompressionPxr24);
compression->appendOption(kParamOutputCompressionB44);
compression->appendOption(kParamOutputCompressionB44a);
compression->setDefault(eParamCompressionNone);
#else
compression->setDefault(0);
#endif
OFX::ChoiceParamDescriptor* compression = desc.defineChoiceParam(kParamCompression);
compression->setLabel(kParamCompressionLabel);
compression->appendOption(kParamCompressionNone, kParamCompressionHintNone);
compression->appendOption(kParamCompressionRLE, kParamCompressionHintRLE);
compression->appendOption(kParamCompressionZIP, kParamCompressionHintZIP);
compression->appendOption(kParamCompressionZIPS, kParamCompressionHintZIPS);
compression->appendOption(kParamCompressionPIZ, kParamCompressionHintPIZ);
compression->appendOption(kParamCompressionPXR24, kParamCompressionHintPXR24);
compression->appendOption(kParamCompressionB44, kParamCompressionHintB44);
compression->appendOption(kParamCompressionB44A, kParamCompressionHintB44A);
compression->setDefault(eTuttlePluginCompressionZIP);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,36 @@ void OpenImageIOWriterProcess<View>::writeImage(View& src, const std::string& fi
spec.attribute("CompressionQuality", params._quality);
spec.attribute("Orientation", params._orientation);

// Set the output compression used
// If the format doesn't support the selected compression, this attribute is ignored.
switch(params._compression)
{
case eTuttlePluginCompressionNone:
spec.attribute("compression", "none");
break;
case eTuttlePluginCompressionRLE:
spec.attribute("compression", "rle");
break;
case eTuttlePluginCompressionZIP:
spec.attribute("compression", "zip");
break;
case eTuttlePluginCompressionZIPS:
spec.attribute("compression", "zips");
break;
case eTuttlePluginCompressionPIZ:
spec.attribute("compression", "piz");
break;
case eTuttlePluginCompressionPXR24:
spec.attribute("compression", "pxr24");
break;
case eTuttlePluginCompressionB44:
spec.attribute("compression", "b44");
break;
case eTuttlePluginCompressionB44A:
spec.attribute("compression", "b44a");
break;
}

// controlling chroma-subsampling of jpeg
// Other formats don't have this attribute and ignore it.
switch(params._subsampling)
Expand All @@ -573,6 +603,13 @@ void OpenImageIOWriterProcess<View>::writeImage(View& src, const std::string& fi
spec.attribute("XResolution", par);
spec.attribute("YResolution", 1);

// Write image data in tiles of 64x64 pixels
if(params._storageType == eTuttlePluginStorageTiles)
{
spec.tile_width = 64;
spec.tile_height = 64;
}

if(!out->open(filepath, spec))
{
BOOST_THROW_EXCEPTION(exception::Unknown() << exception::user("OIIO Writer: " + out->geterror())
Expand Down