Disabled external gits
This commit is contained in:
671
cs440-acg/ext/openexr/OpenEXR/IlmImfUtil/ImfImage.cpp
Normal file
671
cs440-acg/ext/openexr/OpenEXR/IlmImfUtil/ImfImage.cpp
Normal file
@@ -0,0 +1,671 @@
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright (c) 2014, Industrial Light & Magic, a division of Lucas
|
||||
// Digital Ltd. LLC
|
||||
//
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Industrial Light & Magic nor the names of
|
||||
// its contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class Image
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "ImfImage.h"
|
||||
#include <ImfChannelList.h>
|
||||
#include <Iex.h>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace IMATH_NAMESPACE;
|
||||
using namespace IEX_NAMESPACE;
|
||||
using namespace std;
|
||||
|
||||
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
|
||||
|
||||
namespace {
|
||||
|
||||
int
|
||||
levelSize (int min, int max, int l, LevelRoundingMode levelRoundingMode)
|
||||
{
|
||||
assert (l >= 0);
|
||||
|
||||
if (max < min)
|
||||
return 0;
|
||||
|
||||
int a = max - min + 1;
|
||||
int b = (1 << l);
|
||||
int size = a / b;
|
||||
|
||||
if (levelRoundingMode == ROUND_UP && size * b < a)
|
||||
size += 1;
|
||||
|
||||
return std::max (size, 1);
|
||||
}
|
||||
|
||||
|
||||
Box2i
|
||||
computeDataWindowForLevel
|
||||
(const Box2i& dataWindow,
|
||||
int lx, int ly,
|
||||
LevelRoundingMode lrMode)
|
||||
{
|
||||
V2i levelMax =
|
||||
dataWindow.min +
|
||||
V2i (levelSize (dataWindow.min.x, dataWindow.max.x, lx, lrMode) - 1,
|
||||
levelSize (dataWindow.min.y, dataWindow.max.y, ly, lrMode) - 1);
|
||||
|
||||
return Box2i (dataWindow.min, levelMax);
|
||||
}
|
||||
|
||||
int
|
||||
floorLog2 (int x)
|
||||
{
|
||||
//
|
||||
// For x > 0, floorLog2(y) returns floor(log(x)/log(2)).
|
||||
//
|
||||
|
||||
int y = 0;
|
||||
|
||||
while (x > 1)
|
||||
{
|
||||
y += 1;
|
||||
x >>= 1;
|
||||
}
|
||||
|
||||
return y;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
ceilLog2 (int x)
|
||||
{
|
||||
//
|
||||
// For x > 0, ceilLog2(y) returns ceil(log(x)/log(2)).
|
||||
//
|
||||
|
||||
int y = 0;
|
||||
int r = 0;
|
||||
|
||||
while (x > 1)
|
||||
{
|
||||
if (x & 1)
|
||||
r = 1;
|
||||
|
||||
y += 1;
|
||||
x >>= 1;
|
||||
}
|
||||
|
||||
return y + r;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
roundLog2 (int x, LevelRoundingMode levelRoundingMode)
|
||||
{
|
||||
if (x < 1)
|
||||
return 1;
|
||||
|
||||
return (levelRoundingMode == ROUND_DOWN)? floorLog2 (x): ceilLog2 (x);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
computeNumXLevels
|
||||
(const Box2i& dataWindow,
|
||||
LevelMode levelMode,
|
||||
LevelRoundingMode levelRoundingMode)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
switch (levelMode)
|
||||
{
|
||||
case ONE_LEVEL:
|
||||
|
||||
n = 1;
|
||||
break;
|
||||
|
||||
case MIPMAP_LEVELS:
|
||||
|
||||
{
|
||||
int w = dataWindow.max.x - dataWindow.min.x + 1;
|
||||
int h = dataWindow.max.y - dataWindow.min.y + 1;
|
||||
n = roundLog2 (std::max (w, h), levelRoundingMode) + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case RIPMAP_LEVELS:
|
||||
|
||||
{
|
||||
int w = dataWindow.max.x - dataWindow.min.x + 1;
|
||||
n = roundLog2 (w, levelRoundingMode) + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (false);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
computeNumYLevels
|
||||
(const Box2i& dataWindow,
|
||||
LevelMode levelMode,
|
||||
LevelRoundingMode levelRoundingMode)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
switch (levelMode)
|
||||
{
|
||||
case ONE_LEVEL:
|
||||
|
||||
n = 1;
|
||||
break;
|
||||
|
||||
case MIPMAP_LEVELS:
|
||||
|
||||
{
|
||||
int w = dataWindow.max.x - dataWindow.min.x + 1;
|
||||
int h = dataWindow.max.y - dataWindow.min.y + 1;
|
||||
n = roundLog2 (std::max (w, h), levelRoundingMode) + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case RIPMAP_LEVELS:
|
||||
|
||||
{
|
||||
int h = dataWindow.max.y - dataWindow.min.y + 1;
|
||||
n = roundLog2 (h, levelRoundingMode) + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
assert (false);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
Image::Image ():
|
||||
_dataWindow (Box2i (V2i (0, 0), V2i (-1, -1))),
|
||||
_levelMode (ONE_LEVEL),
|
||||
_levelRoundingMode (ROUND_DOWN),
|
||||
_channels(),
|
||||
_levels()
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
Image::~Image ()
|
||||
{
|
||||
clearLevels();
|
||||
clearChannels();
|
||||
}
|
||||
|
||||
|
||||
LevelMode
|
||||
Image::levelMode () const
|
||||
{
|
||||
return _levelMode;
|
||||
}
|
||||
|
||||
|
||||
LevelRoundingMode
|
||||
Image::levelRoundingMode () const
|
||||
{
|
||||
return _levelRoundingMode;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Image::numLevels () const
|
||||
{
|
||||
if (_levelMode == ONE_LEVEL || _levelMode == MIPMAP_LEVELS)
|
||||
return numXLevels();
|
||||
else
|
||||
throw LogicExc ("Number of levels query for image "
|
||||
"must specify x or y direction.");
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Image::numXLevels () const
|
||||
{
|
||||
return _levels.width();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Image::numYLevels () const
|
||||
{
|
||||
return _levels.height();
|
||||
}
|
||||
|
||||
|
||||
const Box2i &
|
||||
Image::dataWindow () const
|
||||
{
|
||||
return _dataWindow;
|
||||
}
|
||||
|
||||
|
||||
const Box2i &
|
||||
Image::dataWindowForLevel (int l) const
|
||||
{
|
||||
return dataWindowForLevel (l, l);
|
||||
}
|
||||
|
||||
|
||||
const Box2i &
|
||||
Image::dataWindowForLevel (int lx, int ly) const
|
||||
{
|
||||
if (!levelNumberIsValid (lx, ly))
|
||||
{
|
||||
THROW (ArgExc,
|
||||
"Cannot get data window for invalid image "
|
||||
"level (" << lx << ", " << ly << ").");
|
||||
}
|
||||
|
||||
return _levels[ly][lx]->dataWindow();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Image::levelWidth (int lx) const
|
||||
{
|
||||
if (lx < 0 || lx >= numXLevels())
|
||||
{
|
||||
THROW (ArgExc,
|
||||
"Cannot get level width for invalid "
|
||||
"image level number " << lx << ".");
|
||||
}
|
||||
|
||||
return levelSize (_dataWindow.min.x, _dataWindow.max.x,
|
||||
lx, _levelRoundingMode);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
Image::levelHeight (int ly) const
|
||||
{
|
||||
if (ly < 0 || ly >= numYLevels())
|
||||
{
|
||||
THROW (ArgExc,
|
||||
"Cannot get level height for invalid "
|
||||
"image level number " << ly << ".");
|
||||
}
|
||||
|
||||
return levelSize (_dataWindow.min.y, _dataWindow.max.y,
|
||||
ly, _levelRoundingMode);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::resize (const Imath::Box2i &dataWindow)
|
||||
{
|
||||
resize (dataWindow, _levelMode, _levelRoundingMode);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::resize
|
||||
(const Imath::Box2i &dataWindow,
|
||||
LevelMode levelMode,
|
||||
LevelRoundingMode levelRoundingMode)
|
||||
{
|
||||
try
|
||||
{
|
||||
clearLevels();
|
||||
|
||||
int nx = computeNumXLevels (dataWindow, levelMode, levelRoundingMode);
|
||||
int ny = computeNumYLevels (dataWindow, levelMode, levelRoundingMode);
|
||||
|
||||
_levels.resizeErase (ny, nx);
|
||||
|
||||
for (int y = 0; y < ny; ++y)
|
||||
{
|
||||
for (int x = 0; x < nx; ++x)
|
||||
{
|
||||
if (levelMode == MIPMAP_LEVELS && x != y)
|
||||
{
|
||||
_levels[y][x] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
Box2i levelDataWindow =
|
||||
computeDataWindowForLevel (dataWindow,
|
||||
x, y,
|
||||
levelRoundingMode);
|
||||
|
||||
_levels[y][x] = newLevel (x, y, levelDataWindow);
|
||||
|
||||
for (ChannelMap::iterator i = _channels.begin();
|
||||
i != _channels.end();
|
||||
++i)
|
||||
{
|
||||
_levels[y][x]->insertChannel (i->first,
|
||||
i->second.type,
|
||||
i->second.xSampling,
|
||||
i->second.ySampling,
|
||||
i->second.pLinear);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_dataWindow = dataWindow;
|
||||
_levelMode = levelMode;
|
||||
_levelRoundingMode = levelRoundingMode;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
clearLevels();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::shiftPixels (int dx, int dy)
|
||||
{
|
||||
for (ChannelMap::iterator i = _channels.begin(); i != _channels.end(); ++i)
|
||||
{
|
||||
if (dx % i->second.xSampling != 0)
|
||||
{
|
||||
THROW (ArgExc, "Cannot shift image horizontally by " << dx << " "
|
||||
"pixels. The shift distance must be a multiple "
|
||||
"of the x sampling rate of all channels, but the "
|
||||
"x sampling rate channel " << i->first << " "
|
||||
"is " << i->second.xSampling << ".");
|
||||
}
|
||||
|
||||
if (dy % i->second.ySampling != 0)
|
||||
{
|
||||
THROW (ArgExc, "Cannot shift image vertically by " << dy << " "
|
||||
"pixels. The shift distance must be a multiple "
|
||||
"of the y sampling rate of all channels, but the "
|
||||
"y sampling rate channel " << i->first << " "
|
||||
"is " << i->second.ySampling << ".");
|
||||
}
|
||||
}
|
||||
|
||||
_dataWindow.min.x += dx;
|
||||
_dataWindow.min.y += dy;
|
||||
_dataWindow.max.x += dx;
|
||||
_dataWindow.max.y += dy;
|
||||
|
||||
for (int y = 0; y < _levels.height(); ++y)
|
||||
for (int x = 0; x < _levels.width(); ++x)
|
||||
if (_levels[y][x])
|
||||
_levels[y][x]->shiftPixels (dx, dy);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::insertChannel
|
||||
(const std::string &name,
|
||||
PixelType type,
|
||||
int xSampling,
|
||||
int ySampling,
|
||||
bool pLinear)
|
||||
{
|
||||
try
|
||||
{
|
||||
_channels[name] = ChannelInfo (type, xSampling, ySampling, pLinear);
|
||||
|
||||
for (int y = 0; y < _levels.height(); ++y)
|
||||
for (int x = 0; x < _levels.width(); ++x)
|
||||
if (_levels[y][x])
|
||||
_levels[y][x]->insertChannel
|
||||
(name, type, xSampling, ySampling, pLinear);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
eraseChannel (name);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::insertChannel (const string &name, const Channel &channel)
|
||||
{
|
||||
insertChannel (name,
|
||||
channel.type,
|
||||
channel.xSampling,
|
||||
channel.ySampling,
|
||||
channel.pLinear);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::eraseChannel (const std::string &name)
|
||||
{
|
||||
//
|
||||
// Note: eraseChannel() is called to clean up if an exception is
|
||||
// thrown during a call during insertChannel(), so eraseChannel()
|
||||
// must work correctly even after an incomplete insertChannel()
|
||||
// operation.
|
||||
//
|
||||
|
||||
for (int y = 0; y < _levels.height(); ++y)
|
||||
for (int x = 0; x < _levels.width(); ++x)
|
||||
if (_levels[y][x])
|
||||
_levels[y][x]->eraseChannel (name);
|
||||
|
||||
ChannelMap::iterator i = _channels.find (name);
|
||||
|
||||
if (i != _channels.end())
|
||||
_channels.erase (i);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::clearChannels ()
|
||||
{
|
||||
for (int y = 0; y < _levels.height(); ++y)
|
||||
for (int x = 0; x < _levels.width(); ++x)
|
||||
if (_levels[y][x])
|
||||
_levels[y][x]->clearChannels();
|
||||
|
||||
_channels.clear();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::renameChannel (const string &oldName, const string &newName)
|
||||
{
|
||||
if (oldName == newName)
|
||||
return;
|
||||
|
||||
ChannelMap::iterator oldChannel = _channels.find (oldName);
|
||||
|
||||
if (oldChannel == _channels.end())
|
||||
{
|
||||
THROW (ArgExc, "Cannot rename image channel " << oldName << " "
|
||||
"to " << newName << ". The image does not have "
|
||||
"a channel called " << oldName << ".");
|
||||
}
|
||||
|
||||
if (_channels.find (newName) != _channels.end())
|
||||
{
|
||||
THROW (ArgExc, "Cannot rename image channel " << oldName << " "
|
||||
"to " << newName << ". The image already has "
|
||||
"a channel called " << newName << ".");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
for (int y = 0; y < _levels.height(); ++y)
|
||||
for (int x = 0; x < _levels.width(); ++x)
|
||||
if (_levels[y][x])
|
||||
_levels[y][x]->renameChannel (oldName, newName);
|
||||
|
||||
_channels[newName] = oldChannel->second;
|
||||
_channels.erase (oldChannel);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
eraseChannel (oldName);
|
||||
eraseChannel (newName);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::renameChannels (const RenamingMap &oldToNewNames)
|
||||
{
|
||||
set <string> newNames;
|
||||
|
||||
for (ChannelMap::const_iterator i = _channels.begin();
|
||||
i != _channels.end();
|
||||
++i)
|
||||
{
|
||||
RenamingMap::const_iterator j = oldToNewNames.find (i->first);
|
||||
std::string newName = (j == oldToNewNames.end())? i->first: j->second;
|
||||
|
||||
if (newNames.find (newName) != newNames.end())
|
||||
{
|
||||
THROW (ArgExc, "Cannot rename image channels. More than one "
|
||||
"channel would be named \"" << newName << "\".");
|
||||
}
|
||||
else
|
||||
{
|
||||
newNames.insert (newName);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
renameChannelsInMap (oldToNewNames, _channels);
|
||||
|
||||
for (int y = 0; y < _levels.height(); ++y)
|
||||
for (int x = 0; x < _levels.width(); ++x)
|
||||
if (_levels[y][x])
|
||||
_levels[y][x]->renameChannels (oldToNewNames);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
clearChannels();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ImageLevel &
|
||||
Image::level (int l)
|
||||
{
|
||||
return level (l, l);
|
||||
}
|
||||
|
||||
|
||||
const ImageLevel &
|
||||
Image::level (int l) const
|
||||
{
|
||||
return level (l, l);
|
||||
}
|
||||
|
||||
|
||||
ImageLevel &
|
||||
Image::level (int lx, int ly)
|
||||
{
|
||||
if (!levelNumberIsValid (lx, ly))
|
||||
{
|
||||
THROW (ArgExc,
|
||||
"Cannot access image level with invalid "
|
||||
"level number (" << lx << ", " << ly << ").");
|
||||
}
|
||||
|
||||
return *_levels[ly][lx];
|
||||
}
|
||||
|
||||
|
||||
const ImageLevel &
|
||||
Image::level (int lx, int ly) const
|
||||
{
|
||||
if (!levelNumberIsValid (lx, ly))
|
||||
{
|
||||
THROW (ArgExc,
|
||||
"Cannot access image level with invalid "
|
||||
"level number (" << lx << ", " << ly << ").");
|
||||
}
|
||||
|
||||
return *_levels[ly][lx];
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Image::levelNumberIsValid (int lx, int ly) const
|
||||
{
|
||||
return lx >= 0 && lx < _levels.width() &&
|
||||
ly >= 0 && ly < _levels.height() &&
|
||||
_levels[ly][lx] != 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Image::clearLevels ()
|
||||
{
|
||||
_dataWindow = Box2i (V2i (0, 0), V2i (-1, -1));
|
||||
|
||||
for (int y = 0; y < _levels.height(); ++y)
|
||||
for (int x = 0; x < _levels.width(); ++x)
|
||||
delete _levels[y][x];
|
||||
|
||||
_levels.resizeErase (0, 0);
|
||||
}
|
||||
|
||||
|
||||
Image::ChannelInfo::ChannelInfo
|
||||
(PixelType type,
|
||||
int xSampling,
|
||||
int ySampling,
|
||||
bool pLinear)
|
||||
:
|
||||
type (type),
|
||||
xSampling (xSampling),
|
||||
ySampling (ySampling),
|
||||
pLinear (pLinear)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
|
||||
|
||||
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT
|
Reference in New Issue
Block a user