|
Packit |
c2c737 |
///////////////////////////////////////////////////////////////////////////
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
|
|
Packit |
c2c737 |
// Digital Ltd. LLC
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// All rights reserved.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Redistribution and use in source and binary forms, with or without
|
|
Packit |
c2c737 |
// modification, are permitted provided that the following conditions are
|
|
Packit |
c2c737 |
// met:
|
|
Packit |
c2c737 |
// * Redistributions of source code must retain the above copyright
|
|
Packit |
c2c737 |
// notice, this list of conditions and the following disclaimer.
|
|
Packit |
c2c737 |
// * Redistributions in binary form must reproduce the above
|
|
Packit |
c2c737 |
// copyright notice, this list of conditions and the following disclaimer
|
|
Packit |
c2c737 |
// in the documentation and/or other materials provided with the
|
|
Packit |
c2c737 |
// distribution.
|
|
Packit |
c2c737 |
// * Neither the name of Industrial Light & Magic nor the names of
|
|
Packit |
c2c737 |
// its contributors may be used to endorse or promote products derived
|
|
Packit |
c2c737 |
// from this software without specific prior written permission.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
c2c737 |
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
c2c737 |
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
Packit |
c2c737 |
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
Packit |
c2c737 |
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
c2c737 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
Packit |
c2c737 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
Packit |
c2c737 |
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
Packit |
c2c737 |
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
Packit |
c2c737 |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
c2c737 |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
///////////////////////////////////////////////////////////////////////////
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
#include "ImfMultiPartOutputFile.h"
|
|
Packit |
c2c737 |
#include "ImfBoxAttribute.h"
|
|
Packit |
c2c737 |
#include "ImfFloatAttribute.h"
|
|
Packit |
c2c737 |
#include "ImfTimeCodeAttribute.h"
|
|
Packit |
c2c737 |
#include "ImfChromaticitiesAttribute.h"
|
|
Packit |
c2c737 |
#include "ImfOutputPartData.h"
|
|
Packit |
c2c737 |
#include "ImfPartType.h"
|
|
Packit |
c2c737 |
#include "ImfOutputFile.h"
|
|
Packit |
c2c737 |
#include "ImfTiledOutputFile.h"
|
|
Packit |
c2c737 |
#include "ImfThreading.h"
|
|
Packit |
c2c737 |
#include "IlmThreadMutex.h"
|
|
Packit |
c2c737 |
#include "ImfMisc.h"
|
|
Packit |
c2c737 |
#include "ImfStdIO.h"
|
|
Packit |
c2c737 |
#include "ImfDeepScanLineOutputFile.h"
|
|
Packit |
c2c737 |
#include "ImfDeepTiledOutputFile.h"
|
|
Packit |
c2c737 |
#include "ImfOutputStreamMutex.h"
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
#include "ImfNamespace.h"
|
|
Packit |
c2c737 |
#include <Iex.h>
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
#include <set>
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
using IMATH_NAMESPACE::Box2i;
|
|
Packit |
c2c737 |
using ILMTHREAD_NAMESPACE::Lock;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
using std::vector;
|
|
Packit |
c2c737 |
using std::map;
|
|
Packit |
c2c737 |
using std::set;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
struct MultiPartOutputFile::Data: public OutputStreamMutex
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
vector<OutputPartData*> parts; // Contains data to initialize Output files.
|
|
Packit |
c2c737 |
bool deleteStream; // If we should delete the stream when destruction.
|
|
Packit |
c2c737 |
int numThreads; // The number of threads.
|
|
Packit |
c2c737 |
std::map<int, GenericOutputFile*> _outputFiles;
|
|
Packit |
c2c737 |
std::vector<Header> _headers;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void headerNameUniquenessCheck (const std::vector<Header> &headers);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void writeHeadersToFile (const std::vector<Header> &headers);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void writeChunkTableOffsets (std::vector<OutputPartData*> &parts;;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//-------------------------------------
|
|
Packit |
c2c737 |
// ensure that _headers is valid: called by constructors
|
|
Packit |
c2c737 |
//-------------------------------------
|
|
Packit |
c2c737 |
void do_header_sanity_checks(bool overrideSharedAttributes);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
// ------------------------------------------------
|
|
Packit |
c2c737 |
// Given a source header, we copy over all the 'shared attributes' to
|
|
Packit |
c2c737 |
// the destination header and remove any conflicting ones.
|
|
Packit |
c2c737 |
// ------------------------------------------------
|
|
Packit |
c2c737 |
void overrideSharedAttributesValues (const Header & src,
|
|
Packit |
c2c737 |
Header & dst);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
// ------------------------------------------------
|
|
Packit |
c2c737 |
// Given a source header, we check the destination header for any
|
|
Packit |
c2c737 |
// attributes that are part of the shared attribute set. For attributes
|
|
Packit |
c2c737 |
// present in both we check the values. For attribute present in
|
|
Packit |
c2c737 |
// destination but absent in source we return false.
|
|
Packit |
c2c737 |
// For attributes present in src but missing from dst we return false
|
|
Packit |
c2c737 |
// and add the attribute to dst.
|
|
Packit |
c2c737 |
// We return false for all other cases.
|
|
Packit |
c2c737 |
// If we return true then we also populate the conflictingAttributes
|
|
Packit |
c2c737 |
// vector with the names of the attributes that failed the above.
|
|
Packit |
c2c737 |
// ------------------------------------------------
|
|
Packit |
c2c737 |
bool checkSharedAttributesValues (const Header & src,
|
|
Packit |
c2c737 |
const Header & dst,
|
|
Packit |
c2c737 |
std::vector<std::string> & conflictingAttributes) const;
|
|
Packit |
c2c737 |
Data (bool deleteStream, int numThreads):
|
|
Packit |
c2c737 |
OutputStreamMutex(),
|
|
Packit |
c2c737 |
deleteStream (deleteStream),
|
|
Packit |
c2c737 |
numThreads (numThreads)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
~Data()
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if (deleteStream) delete os;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
for (size_t i = 0; i < parts.size(); i++)
|
|
Packit |
c2c737 |
delete parts[i];
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
};
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
MultiPartOutputFile::Data::do_header_sanity_checks(bool overrideSharedAttributes)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
size_t parts = _headers.size();
|
|
Packit |
c2c737 |
if (parts == 0)
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::ArgExc ("Empty header list.");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
bool isMultiPart = (parts > 1);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Do part 0 checks first.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
_headers[0].sanityCheck (_headers[0].hasTileDescription(), isMultiPart);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (isMultiPart)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
// multipart files must contain a chunkCount attribute
|
|
Packit |
c2c737 |
_headers[0].setChunkCount(getChunkOffsetTableSize(_headers[0],true));
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
for (size_t i = 1; i < parts; i++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if (_headers[i].hasType() == false)
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::ArgExc ("Every header in a multipart file should have a type");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
_headers[i].setChunkCount(getChunkOffsetTableSize(_headers[i],true));
|
|
Packit |
c2c737 |
_headers[i].sanityCheck (_headers[i].hasTileDescription(), isMultiPart);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (overrideSharedAttributes)
|
|
Packit |
c2c737 |
overrideSharedAttributesValues(_headers[0],_headers[i]);
|
|
Packit |
c2c737 |
else
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
std::vector<std::string> conflictingAttributes;
|
|
Packit |
c2c737 |
bool valid =checkSharedAttributesValues (_headers[0],
|
|
Packit |
c2c737 |
_headers[i],
|
|
Packit |
c2c737 |
conflictingAttributes);
|
|
Packit |
c2c737 |
if (valid)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
string excMsg("Conflicting attributes found for header :: ");
|
|
Packit |
c2c737 |
excMsg += _headers[i].name();
|
|
Packit |
c2c737 |
for (size_t i=0; i
|
|
Packit |
c2c737 |
excMsg += " '" + conflictingAttributes[i] + "' ";
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
THROW (IEX_NAMESPACE::ArgExc, excMsg);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
headerNameUniquenessCheck(_headers);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
}else{
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
// add chunk count offset to single part data (if not an image)
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (_headers[0].hasType() && isImage(_headers[0].type()) == false)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
_headers[0].setChunkCount(getChunkOffsetTableSize(_headers[0],true));
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
MultiPartOutputFile::MultiPartOutputFile (const char fileName[],
|
|
Packit |
c2c737 |
const Header * headers,
|
|
Packit |
c2c737 |
int parts,
|
|
Packit |
c2c737 |
bool overrideSharedAttributes,
|
|
Packit |
c2c737 |
int numThreads)
|
|
Packit |
c2c737 |
:
|
|
Packit |
c2c737 |
_data (new Data (true, numThreads))
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
// grab headers
|
|
Packit |
c2c737 |
_data->_headers.resize(parts);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
for(int i=0;i
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
_data->_headers[i]=headers[i];
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
try
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
_data->do_header_sanity_checks(overrideSharedAttributes);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Build parts and write headers and offset tables to file.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
_data->os = new StdOFStream (fileName);
|
|
Packit |
c2c737 |
for (size_t i = 0; i < _data->_headers.size(); i++)
|
|
Packit |
c2c737 |
_data->parts.push_back( new OutputPartData(_data, _data->_headers[i], i, numThreads, parts>1 ) );
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
writeMagicNumberAndVersionField(*_data->os, &_data->_headers[0],_data->_headers.size());
|
|
Packit |
c2c737 |
_data->writeHeadersToFile(_data->_headers);
|
|
Packit |
c2c737 |
_data->writeChunkTableOffsets(_data->parts);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
catch (IEX_NAMESPACE::BaseExc &e)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
delete _data;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
REPLACE_EXC (e, "Cannot open image file "
|
|
Packit |
c2c737 |
"\"" << fileName << "\". " << e);
|
|
Packit |
c2c737 |
throw;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
catch (...)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
delete _data;
|
|
Packit |
c2c737 |
throw;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
MultiPartOutputFile::MultiPartOutputFile(OStream& os,
|
|
Packit |
c2c737 |
const Header* headers,
|
|
Packit |
c2c737 |
int parts,
|
|
Packit |
c2c737 |
bool overrideSharedAttributes,
|
|
Packit |
c2c737 |
int numThreads):
|
|
Packit |
c2c737 |
_data(new Data(false,numThreads))
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
// grab headers
|
|
Packit |
c2c737 |
_data->_headers.resize(parts);
|
|
Packit |
c2c737 |
_data->os=&os;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
for(int i=0;i
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
_data->_headers[i]=headers[i];
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
try
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
_data->do_header_sanity_checks(overrideSharedAttributes);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Build parts and write headers and offset tables to file.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
for (size_t i = 0; i < _data->_headers.size(); i++)
|
|
Packit |
c2c737 |
_data->parts.push_back( new OutputPartData(_data, _data->_headers[i], i, numThreads, parts>1 ) );
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
writeMagicNumberAndVersionField(*_data->os, &_data->_headers[0],_data->_headers.size());
|
|
Packit |
c2c737 |
_data->writeHeadersToFile(_data->_headers);
|
|
Packit |
c2c737 |
_data->writeChunkTableOffsets(_data->parts);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
catch (IEX_NAMESPACE::BaseExc &e)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
delete _data;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
REPLACE_EXC (e, "Cannot open image stream "
|
|
Packit |
c2c737 |
"\"" << os.fileName() << "\". " << e);
|
|
Packit |
c2c737 |
throw;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
catch (...)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
delete _data;
|
|
Packit |
c2c737 |
throw;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
const Header &
|
|
Packit |
c2c737 |
MultiPartOutputFile::header(int n) const
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if(n<0 || n>int(_data->_headers.size()))
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::ArgExc("MultiPartOutputFile::header called with invalid part number");
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
return _data->_headers[n];
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
int
|
|
Packit |
c2c737 |
MultiPartOutputFile::parts() const
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
return _data->_headers.size();
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
MultiPartOutputFile::~MultiPartOutputFile ()
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
for (map<int, GenericOutputFile*>::iterator it = _data->_outputFiles.begin();
|
|
Packit |
c2c737 |
it != _data->_outputFiles.end(); it++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
delete it->second;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
delete _data;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
template <class T>
|
|
Packit |
c2c737 |
T*
|
|
Packit |
c2c737 |
MultiPartOutputFile::getOutputPart(int partNumber)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
Lock lock(*_data);
|
|
Packit |
c2c737 |
if (_data->_outputFiles.find(partNumber) == _data->_outputFiles.end())
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
T* file = new T(_data->parts[partNumber]);
|
|
Packit |
c2c737 |
_data->_outputFiles.insert(std::make_pair(partNumber, (GenericOutputFile*) file));
|
|
Packit |
c2c737 |
return file;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
else return (T*) _data->_outputFiles[partNumber];
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
// instance above function for all four types
|
|
Packit |
c2c737 |
template OutputFile* MultiPartOutputFile::getOutputPart<OutputFile>(int);
|
|
Packit |
c2c737 |
template TiledOutputFile * MultiPartOutputFile::getOutputPart<TiledOutputFile>(int);
|
|
Packit |
c2c737 |
template DeepScanLineOutputFile * MultiPartOutputFile::getOutputPart<DeepScanLineOutputFile> (int);
|
|
Packit |
c2c737 |
template DeepTiledOutputFile * MultiPartOutputFile::getOutputPart<DeepTiledOutputFile> (int);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
MultiPartOutputFile::Data::overrideSharedAttributesValues(const Header & src, Header & dst)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Display Window
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
const Box2iAttribute * displayWindow =
|
|
Packit |
c2c737 |
src.findTypedAttribute<Box2iAttribute> ("displayWindow");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (displayWindow)
|
|
Packit |
c2c737 |
dst.insert ("displayWindow", *displayWindow);
|
|
Packit |
c2c737 |
else
|
|
Packit |
c2c737 |
dst.erase ("displayWindow");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Pixel Aspect Ratio
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
const FloatAttribute * pixelAspectRatio =
|
|
Packit |
c2c737 |
src.findTypedAttribute<FloatAttribute> ("pixelAspectRatio");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (pixelAspectRatio)
|
|
Packit |
c2c737 |
dst.insert ("pixelAspectRatio", *pixelAspectRatio);
|
|
Packit |
c2c737 |
else
|
|
Packit |
c2c737 |
dst.erase ("pixelAspectRatio");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Timecode
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
const TimeCodeAttribute * timeCode =
|
|
Packit |
c2c737 |
src.findTypedAttribute<TimeCodeAttribute> ("timecode");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (timeCode)
|
|
Packit |
c2c737 |
dst.insert ("timecode", *timeCode);
|
|
Packit |
c2c737 |
else
|
|
Packit |
c2c737 |
dst.erase ("timecode");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Chromaticities
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
const ChromaticitiesAttribute * chromaticities =
|
|
Packit |
c2c737 |
src.findTypedAttribute<ChromaticitiesAttribute> ("chromaticities");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (chromaticities)
|
|
Packit |
c2c737 |
dst.insert ("chromaticities", *chromaticities);
|
|
Packit |
c2c737 |
else
|
|
Packit |
c2c737 |
dst.erase ("chromaticities");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
bool
|
|
Packit |
c2c737 |
MultiPartOutputFile::Data::checkSharedAttributesValues(const Header & src,
|
|
Packit |
c2c737 |
const Header & dst,
|
|
Packit |
c2c737 |
vector<string> & conflictingAttributes) const
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
bool conflict = false;
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Display Window
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
if (src.displayWindow() != dst.displayWindow())
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
conflict = true;
|
|
Packit |
c2c737 |
conflictingAttributes.push_back ("displayWindow");
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Pixel Aspect Ratio
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
if (src.pixelAspectRatio() != dst.pixelAspectRatio())
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
conflict = true;
|
|
Packit |
c2c737 |
conflictingAttributes.push_back ("pixelAspectRatio");
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Timecode
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
const TimeCodeAttribute * srcTimeCode = src.findTypedAttribute<
|
|
Packit |
c2c737 |
TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
|
|
Packit |
c2c737 |
const TimeCodeAttribute * dstTimeCode = dst.findTypedAttribute<
|
|
Packit |
c2c737 |
TimeCodeAttribute> (TimeCodeAttribute::staticTypeName());
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (dstTimeCode)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if ((srcTimeCode && (srcTimeCode->value() != dstTimeCode->value())) ||
|
|
Packit |
c2c737 |
(!srcTimeCode))
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
conflict = true;
|
|
Packit |
c2c737 |
conflictingAttributes.push_back (TimeCodeAttribute::staticTypeName());
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Chromaticities
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
const ChromaticitiesAttribute * srcChrom = src.findTypedAttribute<
|
|
Packit |
c2c737 |
ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
|
|
Packit |
c2c737 |
const ChromaticitiesAttribute * dstChrom = dst.findTypedAttribute<
|
|
Packit |
c2c737 |
ChromaticitiesAttribute> (ChromaticitiesAttribute::staticTypeName());
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (dstChrom)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if ( (srcChrom && (srcChrom->value() != dstChrom->value())) ||
|
|
Packit |
c2c737 |
(!srcChrom))
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
conflict = true;
|
|
Packit |
c2c737 |
conflictingAttributes.push_back (ChromaticitiesAttribute::staticTypeName());
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
return conflict;
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
MultiPartOutputFile::Data::headerNameUniquenessCheck (const vector<Header> &headers)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
set<string> names;
|
|
Packit |
c2c737 |
for (size_t i = 0; i < headers.size(); i++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
if (names.find(headers[i].name()) != names.end())
|
|
Packit |
c2c737 |
throw IEX_NAMESPACE::ArgExc ("Each part should have a unique name.");
|
|
Packit |
c2c737 |
names.insert(headers[i].name());
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
MultiPartOutputFile::Data::writeHeadersToFile (const vector<Header> &headers)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
for (size_t i = 0; i < headers.size(); i++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
// (TODO) consider deep files' preview images here.
|
|
Packit |
c2c737 |
if (headers[i].type() == TILEDIMAGE)
|
|
Packit |
c2c737 |
parts[i]->previewPosition = headers[i].writeTo(*os, true);
|
|
Packit |
c2c737 |
else
|
|
Packit |
c2c737 |
parts[i]->previewPosition = headers[i].writeTo(*os, false);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// If a multipart file, write zero-length attribute name to mark the end of all headers.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (headers.size() !=1)
|
|
Packit |
c2c737 |
OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*os, "");
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
void
|
|
Packit |
c2c737 |
MultiPartOutputFile::Data::writeChunkTableOffsets (vector<OutputPartData*> &parts)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
for (size_t i = 0; i < parts.size(); i++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
int chunkTableSize = getChunkOffsetTableSize(parts[i]->header,false);
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
Int64 pos = os->tellp();
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
if (pos == -1)
|
|
Packit |
c2c737 |
IEX_NAMESPACE::throwErrnoExc ("Cannot determine current file position (%T).");
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
parts[i]->chunkOffsetTablePosition = os->tellp();
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
// Fill in empty data for now. We'll write actual offsets during destruction.
|
|
Packit |
c2c737 |
//
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
for (int j = 0; j < chunkTableSize; j++)
|
|
Packit |
c2c737 |
{
|
|
Packit |
c2c737 |
Int64 empty = 0;
|
|
Packit |
c2c737 |
OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::write <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*os, empty);
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
}
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
|
|
Packit |
c2c737 |
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
|