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