Logo Search packages:      
Sourcecode: openexr version File versions  Download package

compareB44.cpp

//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2006, Industrial Light & Magic, a division of Lucasfilm
// Entertainment Company Ltd.  Portions contributed and copyright held by
// others as indicated.  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
//       any other contributors to this software 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.
//
//////////////////////////////////////////////////////////////////////////////

#include <compareB44.h>
#include <algorithm>
#include <cassert>

using namespace Imf;
using namespace std;


int
shiftAndRound (int x, int shift)
{
    x <<= 1;
    int a = (1 << shift) - 1;
    shift += 1;
    int b = (x >> shift) & 1;
    return (x + a + b) >> shift;
}


bool
withinB44ErrorBounds (const half A[4][4], const half B[4][4])
{
    //
    // Assuming that a 4x4 pixel block, B, was generated by
    // compressing and uncompressing another pixel block, A,
    // using OpenEXR's B44 compression method, check whether
    // the differences between A and B are what we would
    // expect from the compressor.
    //

    //
    // The block may not have been compressed at all if it
    // was part of a very small tile.
    //

    bool equal = true;

    for (int i = 0; i < 4; ++i)
      for (int j = 0; j < 4; ++j)
          if (A[i][j] != B[i][j])
            equal = false;

    if (equal)
      return true;

    //
    // The block was compressed.
    //
    // Perform a "light" version of the B44 compression on A
    // (see the pack() function in ImfB44Compressor.cpp).
    //

    unsigned short t[16];

    for (int i = 0; i < 16; ++i)
    {
      unsigned short Abits = A[i / 4][i % 4].bits();

      if ((Abits & 0x7c00) == 0x7c00)
          t[i] = 0x8000;
      else if (Abits & 0x8000)
          t[i] = ~Abits;
      else
          t[i] = Abits | 0x8000;
    }

    unsigned short tMax = 0;

    for (int i = 0; i < 16; ++i)
      if (tMax < t[i])
          tMax = t[i];

    int shift = -1;
    int d[16];
    int r[15];
    int rMin;
    int rMax;

    do
    {
      shift += 1;

      for (int i = 0; i < 16; ++i)
          d[i] = shiftAndRound (tMax - t[i], shift);

      const int bias = 0x20;

      r[ 0] = d[ 0] - d[ 4] + bias;
      r[ 1] = d[ 4] - d[ 8] + bias;
      r[ 2] = d[ 8] - d[12] + bias;

      r[ 3] = d[ 0] - d[ 1] + bias;
      r[ 4] = d[ 4] - d[ 5] + bias;
      r[ 5] = d[ 8] - d[ 9] + bias;
      r[ 6] = d[12] - d[13] + bias;

      r[ 7] = d[ 1] - d[ 2] + bias;
      r[ 8] = d[ 5] - d[ 6] + bias;
      r[ 9] = d[ 9] - d[10] + bias;
      r[10] = d[13] - d[14] + bias;

      r[11] = d[ 2] - d[ 3] + bias;
      r[12] = d[ 6] - d[ 7] + bias;
      r[13] = d[10] - d[11] + bias;
      r[14] = d[14] - d[15] + bias;

      rMin = r[0];
      rMax = r[0];

      for (int i = 1; i < 15; ++i)
      {
          if (rMin > r[i])
            rMin = r[i];

          if (rMax < r[i])
            rMax = r[i];
      }
    }
    while (rMin < 0 || rMax > 0x3f);

    t[0] = tMax - (d[0] << shift);

    //
    // Now perform a "light" version of the decompression method.
    // (see the unpack() function in ImfB44Compressor.cpp).
    //

    unsigned short A1[16];
    const int bias = 0x20 << shift;

    A1[ 0] =  t[ 0];
    A1[ 4] = A1[ 0] + (r[ 0] << shift) - bias;
    A1[ 8] = A1[ 4] + (r[ 1] << shift) - bias;
    A1[12] = A1[ 8] + (r[ 2] << shift) - bias;

    A1[ 1] = A1[ 0] + (r[ 3] << shift) - bias;
    A1[ 5] = A1[ 4] + (r[ 4] << shift) - bias;
    A1[ 9] = A1[ 8] + (r[ 5] << shift) - bias;
    A1[13] = A1[12] + (r[ 6] << shift) - bias;

    A1[ 2] = A1[ 1] + (r[ 7] << shift) - bias;
    A1[ 6] = A1[ 5] + (r[ 8] << shift) - bias;
    A1[10] = A1[ 9] + (r[ 9] << shift) - bias;
    A1[14] = A1[13] + (r[10] << shift) - bias;

    A1[ 3] = A1[ 2] + (r[11] << shift) - bias;
    A1[ 7] = A1[ 6] + (r[12] << shift) - bias;
    A1[11] = A1[10] + (r[13] << shift) - bias;
    A1[15] = A1[14] + (r[14] << shift) - bias;

    //
    // Compare the result with B, allowing for an difference
    // of a couple of units in the last place.
    //

    for (int i = 0; i < 16; ++i)
    {
      unsigned short A1bits = A1[i];
      unsigned short Bbits = B[i / 4][i % 4].bits();

      if (Bbits & 0x8000)
          Bbits = ~Bbits;
      else
          Bbits = Bbits | 0x8000;

      if (Bbits > A1bits + 5 || Bbits < A1bits - 5)
          return false;
    }

    return true;
}


void
compareB44 (int width,
          int height,
          const Array2D<half> &p1,
          const Array2D<half> &p2)
{
    for (int y = 0; y < height; y += 4)
    {
      for (int x = 0; x < width; x += 4)
      {
          half A[4][4];
          half B[4][4];

          for (int y1 = 0; y1 < 4; ++y1)
          {
            for (int x1 = 0; x1 < 4; ++x1)
            {
                int y2 = min (y + y1, height - 1);
                int x2 = min (x + x1, width - 1);
                A[y1][x1] = p1[y2][x2];
                B[y1][x1] = p2[y2][x2];
            }
          }

          assert (withinB44ErrorBounds (A, B));
      }
    }
}


void
compareB44 (int width,
          int height,
          const Array2D<Rgba> &p1,
          const Array2D<Rgba> &p2,
          RgbaChannels channels)
{
    if (channels & WRITE_R)
    {
      for (int y = 0; y < height; y += 4)
      {
          for (int x = 0; x < width; x += 4)
          {
            half A[4][4];
            half B[4][4];

            for (int y1 = 0; y1 < 4; ++y1)
            {
                for (int x1 = 0; x1 < 4; ++x1)
                {
                  int y2 = min (y + y1, height - 1);
                  int x2 = min (x + x1, width - 1);
                  A[y1][x1] = p1[y2][x2].r;
                  B[y1][x1] = p2[y2][x2].r;
                }
            }

            assert (withinB44ErrorBounds (A, B));
          }
      }
    }
    else
    {
      for (int y = 0; y < height; y += 1)
          for (int x = 0; x < width; x += 1)
            assert (p2[y][x].r == 0);
    }

    if (channels & WRITE_G)
    {
      for (int y = 0; y < height; y += 4)
      {
          for (int x = 0; x < width; x += 4)
          {
            half A[4][4];
            half B[4][4];

            for (int y1 = 0; y1 < 4; ++y1)
            {
                for (int x1 = 0; x1 < 4; ++x1)
                {
                  int y2 = min (y + y1, height - 1);
                  int x2 = min (x + x1, width - 1);
                  A[y1][x1] = p1[y2][x2].g;
                  B[y1][x1] = p2[y2][x2].g;
                }
            }

            assert (withinB44ErrorBounds (A, B));
          }
      }
    }
    else
    {
      for (int y = 0; y < height; y += 1)
          for (int x = 0; x < width; x += 1)
            assert (p2[y][x].g == 0);
    }

    if (channels & WRITE_B)
    {
      for (int y = 0; y < height; y += 4)
      {
          for (int x = 0; x < width; x += 4)
          {
            half A[4][4];
            half B[4][4];

            for (int y1 = 0; y1 < 4; ++y1)
            {
                for (int x1 = 0; x1 < 4; ++x1)
                {
                  int y2 = min (y + y1, height - 1);
                  int x2 = min (x + x1, width - 1);
                  A[y1][x1] = p1[y2][x2].b;
                  B[y1][x1] = p2[y2][x2].b;
                }
            }

            assert (withinB44ErrorBounds (A, B));
          }
      }
    }
    else
    {
      for (int y = 0; y < height; y += 1)
          for (int x = 0; x < width; x += 1)
            assert (p2[y][x].b == 0);
    }

    if (channels & WRITE_A)
    {
      for (int y = 0; y < height; y += 4)
      {
          for (int x = 0; x < width; x += 4)
          {
            half A[4][4];
            half B[4][4];

            for (int y1 = 0; y1 < 4; ++y1)
            {
                for (int x1 = 0; x1 < 4; ++x1)
                {
                  int y2 = min (y + y1, height - 1);
                  int x2 = min (x + x1, width - 1);
                  A[y1][x1] = p1[y2][x2].a;
                  B[y1][x1] = p2[y2][x2].a;
                }
            }

            assert (withinB44ErrorBounds (A, B));
          }
      }
    }
    else
    {
      for (int y = 0; y < height; y += 1)
          for (int x = 0; x < width; x += 1)
            assert (p2[y][x].a == 1);
    }
}

Generated by  Doxygen 1.6.0   Back to index