openexr-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Openexr-devel] Key Codes -- Decision


From: Florian Kainz
Subject: [Openexr-devel] Key Codes -- Decision
Date: Thu, 14 Oct 2004 12:25:01 -0700
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.3) Gecko/20030314

Everyone who replied to my previous mail (see below) either
favored A), or did not express a clear opinion.  Therefore
option A), including the "perfs per count" field, has been
implemented and checked into CVS.

New versions of all files in IlmImf that are affected by the
new key code attribute are attached to this mail.  In addition
to those files, the changes checked into CVS include updates
to IlmImfTest (tests file I/O for the key code attribute),
exrstdattr (allows adding a key code attribute to an image
file) and exrheader (prints key code attributes).

Florian


>
>     A) DPX-style film edge codes, as listed in section 6.1 of SMPTE 268M,
>        "File Format for Digital Moving-Picture Exchange", but with two
>        additional fields (perfs per frame, perfs per count).
>
>
>         film manufacturer ID code
>         film type
>         prefix
>         count
>         offset in perfs
>         perfs per frame (default value: 4)
>         perfs per count (default value: 64)
>
>
>        The "perfs per frame" field is necessary to convert the "offset
>        in perfs" to a frame number (count + frame).  This covers the 35mm
>        3-perf format.
>        In order to cover 65mm formats, where the count increments every
>        80 or 120 fields, an additional "perfs per count" field is needed
>        in order to determine the number of frames between two given film
>        edge codes.
>
>
>     B) "Film feet edge numbers" as specified by SMPTE RP 195, "Use of the
>        Reference Mark in Manufacturer-Printed Latent Image Key Numbers
>        for Unambiguous Film Frame Identification", represented as a
>        StringAttribute (with no syntactic checking performed by the
>        IlmImf library).
>
>
>     C) Don't care.
>
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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.
//
///////////////////////////////////////////////////////////////////////////


#ifndef INCLUDED_IMF_KEY_CODE_H
#define INCLUDED_IMF_KEY_CODE_H

//-----------------------------------------------------------------------------
//
//      class KeyCode
//      
//      A KeyCode object uniquely identifies a motion picture film frame.
//      The following fields specifiy film manufacturer, film type, film
//      roll and the frame's position within the roll:
//
//          filmMfcCode         film manufacturer code
//                              range: 0 - 99
//
//          filmType            film type code
//                              range: 0 - 99
//
//          prefix              prefix to identify film roll
//                              range: 0 - 999999
//
//          count               count, increments once every perfsPerCount
//                              perforations (see below)
//                              range: 0 - 9999
//
//          perfOffset          offset of frame, in perforations from
//                              zero-frame reference mark
//                              range: 0 - 119
//
//          perfsPerFrame       number of perforations per frame 
//                              range: 1 - 15
//
//                              typical values:
//
//                                  1 for 16mm film
//                                  3, 4, or 8 for 35mm film
//                                  5, 8 or 15 for 65mm film
//
//          perfsPerCount       number of perforations per count 
//                              range: 20 - 120
//
//                              typical values:
//
//                                  20 for 16mm film
//                                  64 for 35mm film
//                                  80 or 120 for 65mm film
//
//      For more information about the interpretation of those fields see
//      the following standards and recommended practice publications:
//
//          SMPTE 254   Motion-Picture Film (35-mm) - Manufacturer-Printed
//                      Latent Image Identification Information
//
//          SMPTE 268M  File Format for Digital Moving-Picture Exchange (DPX)
//                      (section 6.1)
//
//          SMPTE 270   Motion-Picture Film (65-mm) - Manufacturer- Printed
//                      Latent Image Identification Information
//
//          SMPTE 271   Motion-Picture Film (16-mm) - Manufacturer- Printed
//                      Latent Image Identification Information
//
//-----------------------------------------------------------------------------

namespace Imf {

   
class KeyCode
{
  public:

    //-------------------------------------
    // Constructors and assignment operator
    //-------------------------------------

    KeyCode (int filmMfcCode = 0,
             int filmType = 0,
             int prefix = 0,
             int count = 0,
             int perfOffset = 0,
             int perfsPerFrame = 4,
             int perfsPerCount = 64);

    KeyCode (const KeyCode &other);
    KeyCode & operator = (const KeyCode &other);


    //----------------------------
    // Access to individual fields
    //----------------------------

    int         filmMfcCode () const;
    void        setFilmMfcCode (int filmMfcCode);

    int         filmType () const;
    void        setFilmType (int filmType);

    int         prefix () const;
    void        setPrefix (int prefix);

    int         count () const;
    void        setCount (int count);

    int         perfOffset () const;
    void        setPerfOffset (int perfOffset);

    int         perfsPerFrame () const;
    void        setPerfsPerFrame (int perfsPerFrame);

    int         perfsPerCount () const;
    void        setPerfsPerCount (int perfsPerCount);

  private:

    int         _filmMfcCode;
    int         _filmType;
    int         _prefix;
    int         _count;
    int         _perfOffset;
    int         _perfsPerFrame;
    int         _perfsPerCount;
};


} // namespace Imf

#endif
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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 KeyCode
//
//-----------------------------------------------------------------------------

#include <ImfKeyCode.h>
#include <Iex.h>

namespace Imf {

   
KeyCode::KeyCode (int filmMfcCode,
                  int filmType,
                  int prefix,
                  int count,
                  int perfOffset,
                  int perfsPerFrame,
                  int perfsPerCount)
{
    setFilmMfcCode (filmMfcCode);
    setFilmType (filmType);
    setPrefix (prefix);
    setCount (count);
    setPerfOffset (perfOffset);
    setPerfsPerFrame (perfsPerFrame);
    setPerfsPerCount (perfsPerCount);
}


KeyCode::KeyCode (const KeyCode &other)
{
    _filmMfcCode = other._filmMfcCode;
    _filmType = other._filmType;
    _prefix = other._prefix;
    _count = other._count;
    _perfOffset = other._perfOffset;
    _perfsPerFrame = other._perfsPerFrame;
    _perfsPerCount = other._perfsPerCount;
}


KeyCode &
KeyCode::operator = (const KeyCode &other)
{
    _filmMfcCode = other._filmMfcCode;
    _filmType = other._filmType;
    _prefix = other._prefix;
    _count = other._count;
    _perfOffset = other._perfOffset;
    _perfsPerFrame = other._perfsPerFrame;
    _perfsPerCount = other._perfsPerCount;

    return *this;
}


int             
KeyCode::filmMfcCode () const
{
    return _filmMfcCode;
}


void    
KeyCode::setFilmMfcCode (int filmMfcCode)
{
    if (filmMfcCode < 0 || filmMfcCode > 99)
        throw Iex::ArgExc ("Invalid key code film manufacturer code "
                           "(must be between 0 and 99).");

    _filmMfcCode = filmMfcCode;
}

int             
KeyCode::filmType () const
{
    return _filmType;
}


void    
KeyCode::setFilmType (int filmType)
{
    if (filmType < 0 || filmType > 99)
        throw Iex::ArgExc ("Invalid key code film type "
                           "(must be between 0 and 99).");

    _filmType = filmType;
}

int             
KeyCode::prefix () const
{
    return _prefix;
}


void    
KeyCode::setPrefix (int prefix)
{
    if (prefix < 0 || prefix > 999999)
        throw Iex::ArgExc ("Invalid key code prefix "
                           "(must be between 0 and 999999).");

    _prefix = prefix;
}


int             
KeyCode::count () const
{
    return _count;
}


void    
KeyCode::setCount (int count)
{
    if (count < 0 || count > 9999)
        throw Iex::ArgExc ("Invalid key code count "
                           "(must be between 0 and 9999).");

    _count = count;
}


int             
KeyCode::perfOffset () const
{
    return _perfOffset;
}


void    
KeyCode::setPerfOffset (int perfOffset)
{
    if (perfOffset < 0 || perfOffset > 119)
        throw Iex::ArgExc ("Invalid key code perforation offset "
                           "(must be between 0 and 119).");

    _perfOffset = perfOffset;
}


int     
KeyCode::perfsPerFrame () const
{
    return _perfsPerFrame;
}


void
KeyCode::setPerfsPerFrame (int perfsPerFrame)
{
    if (perfsPerFrame < 1 || perfsPerFrame > 15)
        throw Iex::ArgExc ("Invalid key code number of perforations per frame "
                           "(must be between 1 and 15).");

    _perfsPerFrame = perfsPerFrame;
}


int     
KeyCode::perfsPerCount () const
{
    return _perfsPerCount;
}


void
KeyCode::setPerfsPerCount (int perfsPerCount)
{
    if (perfsPerCount < 20 || perfsPerCount > 120)
        throw Iex::ArgExc ("Invalid key code number of perforations per count "
                           "(must be between 20 and 120).");

    _perfsPerCount = perfsPerCount;
}

} // namespace Imf
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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.
//
///////////////////////////////////////////////////////////////////////////


#ifndef INCLUDED_IMF_KEY_CODE_ATTRIBUTE_H
#define INCLUDED_IMF_KEY_CODE_ATTRIBUTE_H


//-----------------------------------------------------------------------------
//
//      class KeyCodeAttribute
//
//-----------------------------------------------------------------------------

#include <ImfAttribute.h>
#include <ImfKeyCode.h>


namespace Imf {


typedef TypedAttribute<KeyCode> KeyCodeAttribute;

template <>
const char *KeyCodeAttribute::staticTypeName ();

template <>
void KeyCodeAttribute::writeValueTo (OStream &, int) const;

template <>
void KeyCodeAttribute::readValueFrom (IStream &, int, int);


} // namespace Imf

// Metrowerks compiler wants the .cpp file inlined, too
#ifdef __MWERKS__
#include <ImfKeyCodeAttribute.cpp>
#endif

#endif
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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 KeyCodeAttribute
//
//-----------------------------------------------------------------------------

#include <ImfKeyCodeAttribute.h>

namespace Imf {


template <>
const char *
KeyCodeAttribute::staticTypeName ()
{
    return "keycode";
}


template <>
void
KeyCodeAttribute::writeValueTo (OStream &os, int version) const
{
    Xdr::write <StreamIO> (os, _value.filmMfcCode());
    Xdr::write <StreamIO> (os, _value.filmType());
    Xdr::write <StreamIO> (os, _value.prefix());
    Xdr::write <StreamIO> (os, _value.count());
    Xdr::write <StreamIO> (os, _value.perfOffset());
    Xdr::write <StreamIO> (os, _value.perfsPerFrame());
    Xdr::write <StreamIO> (os, _value.perfsPerCount());
}


template <>
void
KeyCodeAttribute::readValueFrom (IStream &is, int size, int version)
{
    int tmp;

    Xdr::read <StreamIO> (is, tmp);
    _value.setFilmMfcCode (tmp);

    Xdr::read <StreamIO> (is, tmp);
    _value.setFilmType (tmp);

    Xdr::read <StreamIO> (is, tmp);
    _value.setPrefix (tmp);

    Xdr::read <StreamIO> (is, tmp);
    _value.setCount (tmp);

    Xdr::read <StreamIO> (is, tmp);
    _value.setPerfOffset (tmp);

    Xdr::read <StreamIO> (is, tmp);
    _value.setPerfsPerFrame (tmp);

    Xdr::read <StreamIO> (is, tmp);
    _value.setPerfsPerCount (tmp);
}


} // namespace Imf
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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.
//
///////////////////////////////////////////////////////////////////////////


#ifndef INCLUDED_IMF_STANDARD_ATTRIBUTES_H
#define INCLUDED_IMF_STANDARD_ATTRIBUTES_H

//-----------------------------------------------------------------------------
//
//      Optional Standard Attributes -- these attributes are "optional"
//      because not every image file header has them, but they define a
//      "standard" way to represent commonly used data in the file header.
//
//      For each attribute, with name "foo", and type "T", the following
//      functions are automatically generated via macros:
//
//      void                       addFoo (Header &header, const T &value);
//      bool                       hasFoo (const Header &header);
//      const TypedAttribute<T> &  fooAttribute (const Header &header);
//      TypedAttribute<T> &        fooAttribute (Header &header);
//      const T &                  foo (const Header &Header);
//      T &                        foo (Header &Header);
//
//-----------------------------------------------------------------------------

#include <ImfHeader.h>
#include <ImfFloatAttribute.h>
#include <ImfStringAttribute.h>
#include <ImfChromaticitiesAttribute.h>
#include <ImfEnvmapAttribute.h>
#include <ImfKeyCodeAttribute.h>


#define IMF_STD_ATTRIBUTE_DEF(name,suffix,type)                               \
                                                                              \
    void                         add##suffix (Header &header, const type &v); \
    bool                         has##suffix (const Header &header);          \
    const TypedAttribute<type> & name##Attribute (const Header &header);      \
    TypedAttribute<type> &       name##Attribute (Header &header);            \
    const type &                 name (const Header &header);                 \
    type &                       name (Header &header);


namespace Imf {

//
// chromaticities -- for RGB images, specifies the CIE (x,y)
// chromaticities of the primaries and the white point
//

IMF_STD_ATTRIBUTE_DEF (chromaticities, Chromaticities, Chromaticities)


//
// whiteLuminance -- for RGB images, defines the luminance, in Nits
// (candelas per square meter) of the RGB value (1.0, 1.0, 1.0).
//
// If the chromaticities and the whiteLuminance of an RGB image are
// known, then it is possible to convert the image's pixels from RGB
// to CIE XYZ tristimulus values (see function RGBtoXYZ() in header
// file ImfChromaticities.h).
// 
//

IMF_STD_ATTRIBUTE_DEF (whiteLuminance, WhiteLuminance, float)


//
// xDensity -- horizontal output density, in pixels per inch.
// The image's vertical output density is xDensity * pixelAspectRatio.
//

IMF_STD_ATTRIBUTE_DEF (xDensity, XDensity, float)


//
// owner -- name of the owner of the image
//

IMF_STD_ATTRIBUTE_DEF (owner, Owner, std::string)
   

//
// comments -- additional image information in human-readable
// form, for example a verbal description of the image
//

IMF_STD_ATTRIBUTE_DEF (comments, Comments, std::string)


//
// capDate -- the date when the image was created or captured,
// in local time, and formatted as
//
//    YYYY:MM:DD hh:mm:ss
//
// where YYYY is the year (4 digits, e.g. 2003), MM is the month
// (2 digits, 01, 02, ... 12), DD is the day of the month (2 digits,
// 01, 02, ... 31), hh is the hour (2 digits, 00, 01, ... 23), mm
// is the minute, and ss is the second (2 digits, 00, 01, ... 59).
//
//

IMF_STD_ATTRIBUTE_DEF (capDate, CapDate, std::string)


//
// utcOffset -- offset of local time at capDate from
// Universal Coordinated Time (UTC), in seconds:
//
//    UTC == local time + utcOffset
//

IMF_STD_ATTRIBUTE_DEF (utcOffset, utcOffset, float)


//
// longitude, latitude, altitude -- for images of real objects, the
// location where the image was recorded.  Longitude and latitude are
// in degrees east of Greenwich and north of the equator.  Altitude
// is in meters above sea level.  For example, Kathmandu, Nepal is
// at longitude 85.317, latitude 27.717, altitude 1305.
//

IMF_STD_ATTRIBUTE_DEF (longitude, Longitude, float)
IMF_STD_ATTRIBUTE_DEF (latitude, Latitude, float)
IMF_STD_ATTRIBUTE_DEF (altitude, Altitude, float)


//
// focus -- the camera's focus distance, in meters
//

IMF_STD_ATTRIBUTE_DEF (focus, Focus, float)


//
// exposure -- exposure time, in seconds
//

IMF_STD_ATTRIBUTE_DEF (expTime, ExpTime, float)


//
// aperture -- the camera's lens aperture, in f-stops (focal length
// of the lens divided by the diameter of the iris opening)
//

IMF_STD_ATTRIBUTE_DEF (aperture, Aperture, float)


//
// isoSpeed -- the ISO speed of the film or image sensor
// that was used to record the image
//

IMF_STD_ATTRIBUTE_DEF (isoSpeed, IsoSpeed, float)


//
// envmap -- if this attribute is present, the image represents
// an environment map.  The attribute's value defines how 3D
// directions are mapped to 2D pixel locations.  For details
// see header file ImfEnvmap.h
//

IMF_STD_ATTRIBUTE_DEF (envmap, Envmap, Envmap)


//
// keyCode -- for motion picture film frames.  Identifies film
// manufacturer, film type, film roll and frame position within
// the roll.
//

IMF_STD_ATTRIBUTE_DEF (keyCode, KeyCode, KeyCode)


} // namespace Imf

#endif
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2003, 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.
//
///////////////////////////////////////////////////////////////////////////


//-----------------------------------------------------------------------------
//
//      Optional Standard Attributes
//
//-----------------------------------------------------------------------------

#include <ImfStandardAttributes.h>


#define IMF_STRING(name) #name

#define IMF_STD_ATTRIBUTE_IMP(name,suffix,type)                          \
                                                                         \
    void                                                                 \
    add##suffix (Header &header, const type &value)                      \
    {                                                                    \
        header.insert (IMF_STRING (name), TypedAttribute<type> (value)); \
    }                                                                    \
                                                                         \
    bool                                                                 \
    has##suffix (const Header &header)                                   \
    {                                                                    \
        return header.findTypedAttribute <TypedAttribute <type> >        \
                (IMF_STRING (name)) != 0;                                \
    }                                                                    \
                                                                         \
    const TypedAttribute<type> &                                         \
    name##Attribute (const Header &header)                               \
    {                                                                    \
        return header.typedAttribute <TypedAttribute <type> >            \
                (IMF_STRING (name));                                     \
    }                                                                    \
                                                                         \
    TypedAttribute<type> &                                               \
    name##Attribute (Header &header)                                     \
    {                                                                    \
        return header.typedAttribute <TypedAttribute <type> >            \
                (IMF_STRING (name));                                     \
    }                                                                    \
                                                                         \
    const type &                                                         \
    name (const Header &header)                                          \
    {                                                                    \
        return name##Attribute(header).value();                          \
    }                                                                    \
                                                                         \
    type &                                                               \
    name (Header &header)                                                \
    {                                                                    \
        return name##Attribute(header).value();                          \
    }


namespace Imf {

   
IMF_STD_ATTRIBUTE_IMP (chromaticities, Chromaticities, Chromaticities)
IMF_STD_ATTRIBUTE_IMP (whiteLuminance, WhiteLuminance, float)
IMF_STD_ATTRIBUTE_IMP (xDensity, XDensity, float)
IMF_STD_ATTRIBUTE_IMP (owner, Owner, std::string)
IMF_STD_ATTRIBUTE_IMP (comments, Comments, std::string)
IMF_STD_ATTRIBUTE_IMP (capDate, CapDate, std::string)
IMF_STD_ATTRIBUTE_IMP (utcOffset, utcOffset, float)
IMF_STD_ATTRIBUTE_IMP (longitude, Longitude, float)
IMF_STD_ATTRIBUTE_IMP (latitude, Latitude, float)
IMF_STD_ATTRIBUTE_IMP (altitude, Altitude, float)
IMF_STD_ATTRIBUTE_IMP (focus, Focus, float)
IMF_STD_ATTRIBUTE_IMP (expTime, ExpTime, float)
IMF_STD_ATTRIBUTE_IMP (aperture, Aperture, float)
IMF_STD_ATTRIBUTE_IMP (isoSpeed, IsoSpeed, float)
IMF_STD_ATTRIBUTE_IMP (envmap, Envmap, Envmap)
IMF_STD_ATTRIBUTE_IMP (keyCode, KeyCode, KeyCode)


} // namespace Imf
///////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2004, 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 Header
//
//-----------------------------------------------------------------------------

#include <ImfHeader.h>
#include <ImfStdIO.h>
#include <ImfVersion.h>
#include <ImfCompressor.h>
#include <ImfMisc.h>

#include <ImfBoxAttribute.h>
#include <ImfChannelListAttribute.h>
#include <ImfChromaticitiesAttribute.h>
#include <ImfCompressionAttribute.h>
#include <ImfDoubleAttribute.h>
#include <ImfEnvmapAttribute.h>
#include <ImfFloatAttribute.h>
#include <ImfIntAttribute.h>
#include <ImfKeyCodeAttribute.h>
#include <ImfLineOrderAttribute.h>
#include <ImfMatrixAttribute.h>
#include <ImfOpaqueAttribute.h>
#include <ImfPreviewImageAttribute.h>
#include <ImfStringAttribute.h>
#include <ImfTileDescriptionAttribute.h>
#include <ImfVecAttribute.h>

#include <Iex.h>

#include <sstream>

#include <stdlib.h>
#include <time.h>


namespace Imf {

using Imath::Box2i;
using Imath::V2i;
using Imath::V2f;

namespace {


void
staticInitialize ()
{
    static bool initialized = false;

    if (!initialized)
    {
        //
        // One-time initialization -- register
        // some predefined attribute types.
        //
        
        Box2fAttribute::registerAttributeType();
        Box2iAttribute::registerAttributeType();
        ChannelListAttribute::registerAttributeType();
        ChromaticitiesAttribute::registerAttributeType();
        DoubleAttribute::registerAttributeType();
        EnvmapAttribute::registerAttributeType();
        FloatAttribute::registerAttributeType();
        IntAttribute::registerAttributeType();
        KeyCodeAttribute::registerAttributeType();
        LineOrderAttribute::registerAttributeType();
        M33fAttribute::registerAttributeType();
        M44fAttribute::registerAttributeType();
        PreviewImageAttribute::registerAttributeType();
        StringAttribute::registerAttributeType();
        TileDescriptionAttribute::registerAttributeType();
        V2fAttribute::registerAttributeType();
        V2iAttribute::registerAttributeType();
        V3fAttribute::registerAttributeType();
        V3iAttribute::registerAttributeType();

        initialized = true;
    }
}


void
initialize (Header &header,
            const Box2i &displayWindow,
            const Box2i &dataWindow,
            float pixelAspectRatio,
            const V2f &screenWindowCenter,
            float screenWindowWidth,
            LineOrder lineOrder,
            Compression compression)
{
    header.insert ("displayWindow", Box2iAttribute (displayWindow));
    header.insert ("dataWindow", Box2iAttribute (dataWindow));
    header.insert ("pixelAspectRatio", FloatAttribute (pixelAspectRatio));
    header.insert ("screenWindowCenter", V2fAttribute (screenWindowCenter));
    header.insert ("screenWindowWidth", FloatAttribute (screenWindowWidth));
    header.insert ("lineOrder", LineOrderAttribute (lineOrder));
    header.insert ("compression", CompressionAttribute (compression));
    header.insert ("channels", ChannelListAttribute ());
}


} // namespace


Header::Header (int width,
                int height,
                float pixelAspectRatio,
                const V2f &screenWindowCenter,
                float screenWindowWidth,
                LineOrder lineOrder,
                Compression compression)
:
    _map()
{
    staticInitialize();

    Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));

    initialize (*this,
                displayWindow,
                displayWindow,
                pixelAspectRatio,
                screenWindowCenter,
                screenWindowWidth,
                lineOrder,
                compression);
}


Header::Header (int width,
                int height,
                const Box2i &dataWindow,
                float pixelAspectRatio,
                const V2f &screenWindowCenter,
                float screenWindowWidth,
                LineOrder lineOrder,
                Compression compression)
:
    _map()
{
    staticInitialize();

    Box2i displayWindow (V2i (0, 0), V2i (width - 1, height - 1));

    initialize (*this,
                displayWindow,
                dataWindow,
                pixelAspectRatio,
                screenWindowCenter,
                screenWindowWidth,
                lineOrder,
                compression);
}


Header::Header (const Box2i &displayWindow,
                const Box2i &dataWindow,
                float pixelAspectRatio,
                const V2f &screenWindowCenter,
                float screenWindowWidth,
                LineOrder lineOrder,
                Compression compression)
:
    _map()
{
    staticInitialize();

    initialize (*this,
                displayWindow,
                dataWindow,
                pixelAspectRatio,
                screenWindowCenter,
                screenWindowWidth,
                lineOrder,
                compression);
}


Header::Header (const Header &other): _map()
{
    for (AttributeMap::const_iterator i = other._map.begin();
         i != other._map.end();
         ++i)
    {
        insert (*i->first, *i->second);
    }
}


Header::~Header ()
{
    for (AttributeMap::iterator i = _map.begin();
         i != _map.end();
         ++i)
    {
         delete i->second;
    }
}


Header &                
Header::operator = (const Header &other)
{
    if (this != &other)
    {
        for (AttributeMap::iterator i = _map.begin();
             i != _map.end();
             ++i)
        {
             delete i->second;
        }

        _map.erase (_map.begin(), _map.end());

        for (AttributeMap::const_iterator i = other._map.begin();
             i != other._map.end();
             ++i)
        {
            insert (*i->first, *i->second);
        }
    }

    return *this;
}


void
Header::insert (const char name[], const Attribute &attribute)
{
    if (name[0] == 0)
        THROW (Iex::ArgExc, "Image attribute name cannot be an empty string.");

    AttributeMap::iterator i = _map.find (name);

    if (i == _map.end())
    {
        Attribute *tmp = attribute.copy();

        try
        {
            _map[name] = tmp;
        }
        catch (...)
        {
            delete tmp;
            throw;
        }
    }
    else
    {
        if (strcmp (i->second->typeName(), attribute.typeName()))
            THROW (Iex::TypeExc, "Cannot assign a value of "
                                 "type \"" << attribute.typeName() << "\" "
                                 "to image attribute \"" << name << "\" of "
                                 "type \"" << i->second->typeName() << "\".");

        Attribute *tmp = attribute.copy();
        delete i->second;
        i->second = tmp;
    }
}


Attribute &             
Header::operator [] (const char name[])
{
    AttributeMap::iterator i = _map.find (name);

    if (i == _map.end())
        THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");

    return *i->second;
}


const Attribute &       
Header::operator [] (const char name[]) const
{
    AttributeMap::const_iterator i = _map.find (name);

    if (i == _map.end())
        THROW (Iex::ArgExc, "Cannot find image attribute \"" << name << "\".");

    return *i->second;
}


Header::Iterator
Header::begin ()
{
    return _map.begin();
}


Header::ConstIterator
Header::begin () const
{
    return _map.begin();
}


Header::Iterator
Header::end ()
{
    return _map.end();
}


Header::ConstIterator
Header::end () const
{
    return _map.end();
}


Header::Iterator
Header::find (const char name[])
{
    return _map.find (name);
}


Header::ConstIterator
Header::find (const char name[]) const
{
    return _map.find (name);
}


Imath::Box2i &  
Header::displayWindow ()
{
    return static_cast <Box2iAttribute &>
        ((*this)["displayWindow"]).value();
}


const Imath::Box2i &
Header::displayWindow () const
{
    return static_cast <const Box2iAttribute &>
        ((*this)["displayWindow"]).value();
}

Imath::Box2i &  
Header::dataWindow ()
{
    return static_cast <Box2iAttribute &>
        ((*this)["dataWindow"]).value();
}


const Imath::Box2i &
Header::dataWindow () const
{
    return static_cast <const Box2iAttribute &>
        ((*this)["dataWindow"]).value();
}


float &         
Header::pixelAspectRatio ()
{
    return static_cast <FloatAttribute &>
        ((*this)["pixelAspectRatio"]).value();
}


const float &   
Header::pixelAspectRatio () const
{
    return static_cast <const FloatAttribute &>
        ((*this)["pixelAspectRatio"]).value();
}


Imath::V2f &    
Header::screenWindowCenter ()
{
    return static_cast <V2fAttribute &>
        ((*this)["screenWindowCenter"]).value();
}


const Imath::V2f &      
Header::screenWindowCenter () const
{
    return static_cast <const V2fAttribute &>
        ((*this)["screenWindowCenter"]).value();
}


float &         
Header::screenWindowWidth ()
{
    return static_cast <FloatAttribute &>
        ((*this)["screenWindowWidth"]).value();
}


const float &   
Header::screenWindowWidth () const
{
    return static_cast <const FloatAttribute &>
        ((*this)["screenWindowWidth"]).value();
}


ChannelList &   
Header::channels ()
{
    return static_cast <ChannelListAttribute &>
        ((*this)["channels"]).value();
}


const ChannelList &     
Header::channels () const
{
    return static_cast <const ChannelListAttribute &>
        ((*this)["channels"]).value();
}


LineOrder &
Header::lineOrder ()
{
    return static_cast <LineOrderAttribute &>
        ((*this)["lineOrder"]).value();
}


const LineOrder &
Header::lineOrder () const
{
    return static_cast <const LineOrderAttribute &>
        ((*this)["lineOrder"]).value();
}


Compression &
Header::compression ()
{
    return static_cast <CompressionAttribute &>
        ((*this)["compression"]).value();
}


const Compression &
Header::compression () const
{
    return static_cast <const CompressionAttribute &>
        ((*this)["compression"]).value();
}


void
Header::setTileDescription(const TileDescription& td)
{
    insert ("tiles", TileDescriptionAttribute (td));
}


bool
Header::hasTileDescription() const
{
    return findTypedAttribute <TileDescriptionAttribute> ("tiles") != 0;
}


TileDescription &
Header::tileDescription ()
{
    return typedAttribute <TileDescriptionAttribute> ("tiles").value();
}


const TileDescription &
Header::tileDescription () const
{
    return typedAttribute <TileDescriptionAttribute> ("tiles").value();
}

void            
Header::setPreviewImage (const PreviewImage &pi)
{
    insert ("preview", PreviewImageAttribute (pi));
}


PreviewImage &
Header::previewImage ()
{
    return typedAttribute <PreviewImageAttribute> ("preview").value();
}


const PreviewImage &
Header::previewImage () const
{
    return typedAttribute <PreviewImageAttribute> ("preview").value();
}


bool            
Header::hasPreviewImage () const
{
    return findTypedAttribute <PreviewImageAttribute> ("preview") != 0;
}


void            
Header::sanityCheck (bool isTiled) const
{
    //
    // The display window and the data window
    // must contain at least one pixel each.
    //

    const Box2i &displayWindow = this->displayWindow();

    if (displayWindow.min.x > displayWindow.max.x ||
        displayWindow.min.y > displayWindow.max.y)
        throw Iex::ArgExc ("Invalid display window in image header.");

    const Box2i &dataWindow = this->dataWindow();

    if (dataWindow.min.x > dataWindow.max.x ||
        dataWindow.min.y > dataWindow.max.y)
        throw Iex::ArgExc ("Invalid data window in image header.");

    //
    // The pixel aspect ratio must be greater than 0.
    // In applications, numbers like the the display or
    // data window dimensions are likely to be multiplied
    // or divided by the pixel aspect ratio; to avoid
    // arithmetic exceptions, we limit the pixel aspect
    // ratio to a range that is smaller than theoretically
    // possible (real aspect ratios are likely to be close
    // to 1.0 anyway).
    //

    float pixelAspectRatio = this->pixelAspectRatio();

    const float MIN_PIXEL_ASPECT_RATIO = 1e-6;
    const float MAX_PIXEL_ASPECT_RATIO = 1e+6;

    if (pixelAspectRatio < MIN_PIXEL_ASPECT_RATIO ||
        pixelAspectRatio > MAX_PIXEL_ASPECT_RATIO)
    {
        throw Iex::ArgExc ("Invalid pixel aspect ratio in image header.");
    }

    //
    // The screen window width must be greater than 0.
    // The size of the screen window can vary over a wide
    // range (fish-eye lens to astronomical telescope),
    // so we can't limit the screen window width to a
    // small range.
    //

    float screenWindowWidth = this->screenWindowWidth();

    if (screenWindowWidth < 0)
        throw Iex::ArgExc ("Invalid screen window width in image header.");

    //
    // If the file is tiled, verify that the tile description has resonable
    // values and check to see if the lineOrder is one of the predefined 3.
    // If the file is not tiled, then the lineOrder can only be INCREASING_Y
    // or DECREASING_Y.
    //

    LineOrder lineOrder = this->lineOrder();

    if (isTiled)
    {
        if (!hasTileDescription())
        {
            throw Iex::ArgExc ("Tiled image has no tile "
                               "description attribute.");
        }

        const TileDescription &tileDesc = tileDescription();

        if (tileDesc.xSize <= 0 || tileDesc.ySize <= 0)
            throw Iex::ArgExc ("Invalid tile size in image header.");

        if (tileDesc.mode != ONE_LEVEL &&
            tileDesc.mode != MIPMAP_LEVELS &&
            tileDesc.mode != RIPMAP_LEVELS)
            throw Iex::ArgExc ("Invalid level mode in image header.");

        if (tileDesc.roundingMode != ROUND_UP &&
            tileDesc.roundingMode != ROUND_DOWN)
            throw Iex::ArgExc ("Invalid level rounding mode in image header.");

        if (lineOrder != INCREASING_Y &&
            lineOrder != DECREASING_Y &&
            lineOrder != RANDOM_Y)
            throw Iex::ArgExc ("Invalid line order in image header.");
    }
    else
    {
        if (lineOrder != INCREASING_Y &&
            lineOrder != DECREASING_Y)
            throw Iex::ArgExc ("Invalid line order in image header.");
    }

    //
    // The compression method must be one of the predefined values.
    //

    if (!isValidCompression (this->compression()))
        throw Iex::ArgExc ("Unknown compression type in image header.");

    //
    // Check the channel list:
    //
    // If the file is tiled then for each channel, the type must be one of the
    // predefined values, and the x and y sampling must both be 1.
    //
    // If the file is not tiled then for each channel, the type must be one
    // of the predefined values, the x and y coordinates of the data window's
    // upper left corner must be divisible by the x and y subsampling factors,
    // and the width and height of the data window must be divisible by the
    // x and y subsampling factors.
    //

    const ChannelList &channels = this->channels();
    
    if (isTiled)
    {
        for (ChannelList::ConstIterator i = channels.begin();
             i != channels.end();
             ++i)
        {
            if (i.channel().type != UINT &&
                i.channel().type != HALF &&
                i.channel().type != FLOAT)
            {
                THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
                                    "image channel is invalid.");
            }

            if (i.channel().xSampling != 1)
            {
                THROW (Iex::ArgExc, "The x subsampling factor for the "
                                    "\"" << i.name() << "\" channel "
                                    "is not 1.");
            }   

            if (i.channel().ySampling != 1)
            {
                THROW (Iex::ArgExc, "The y subsampling factor for the "
                                    "\"" << i.name() << "\" channel "
                                    "is not 1.");
            }   
        }
    }
    else
    {
        for (ChannelList::ConstIterator i = channels.begin();
             i != channels.end();
             ++i)
        {
            if (i.channel().type != UINT &&
                i.channel().type != HALF &&
                i.channel().type != FLOAT)
            {
                THROW (Iex::ArgExc, "Pixel type of \"" << i.name() << "\" "
                                    "image channel is invalid.");
            }

            if (i.channel().xSampling < 1)
            {
                THROW (Iex::ArgExc, "The x subsampling factor for the "
                                    "\"" << i.name() << "\" channel "
                                    "is invalid.");
            }

            if (i.channel().ySampling < 1)
            {
                THROW (Iex::ArgExc, "The y subsampling factor for the "
                                    "\"" << i.name() << "\" channel "
                                    "is invalid.");
            }

            if (dataWindow.min.x % i.channel().xSampling)
            {
                THROW (Iex::ArgExc, "The minimum x coordinate of the "
                                    "image's data window is not a multiple "
                                    "of the x subsampling factor of "
                                    "the \"" << i.name() << "\" channel.");
            }

            if (dataWindow.min.y % i.channel().ySampling)
            {
                THROW (Iex::ArgExc, "The minimum y coordinate of the "
                                    "image's data window is not a multiple "
                                    "of the y subsampling factor of "
                                    "the \"" << i.name() << "\" channel.");
            }

            if ((dataWindow.max.x - dataWindow.min.x + 1) %
                    i.channel().xSampling)
            {
                THROW (Iex::ArgExc, "Number of pixels per row in the "
                                    "image's data window is not a multiple "
                                    "of the x subsampling factor of "
                                    "the \"" << i.name() << "\" channel.");
            }

            if ((dataWindow.max.y - dataWindow.min.y + 1) %
                    i.channel().ySampling)
            {
                THROW (Iex::ArgExc, "Number of pixels per column in the "
                                    "image's data window is not a multiple "
                                    "of the y subsampling factor of "
                                    "the \"" << i.name() << "\" channel.");
            }
        }
    }
}


Int64
Header::writeTo (OStream &os, bool isTiled) const
{
    //
    // Write a "magic number" to identify the file as an image file.
    // Write the current file format version number.
    //

    Xdr::write <StreamIO> (os, MAGIC);

    int version = isTiled ? makeTiled (EXR_VERSION) : EXR_VERSION;
    Xdr::write <StreamIO> (os, version);

    //
    // Write all attributes.  If we have a preview image attribute,
    // keep track of its position in the file.
    //

    Int64 previewPosition = 0;

    const Attribute *preview =
            findTypedAttribute <PreviewImageAttribute> ("preview");

    for (ConstIterator i = begin(); i != end(); ++i)
    {
        //
        // Write the attribute's name and type.
        //

        Xdr::write <StreamIO> (os, i.name());
        Xdr::write <StreamIO> (os, i.attribute().typeName());

        //
        // Write the size of the attribute value,
        // and the value itself.
        //

        StdOSStream oss;
        i.attribute().writeValueTo (oss, version);

        std::string s = oss.str();
        Xdr::write <StreamIO> (os, (int) s.length());

        if (&i.attribute() == preview)
            previewPosition = os.tellp();

        os.write (s.data(), s.length());
    }

    //
    // Write zero-length attribute name to mark the end of the header.
    //

    Xdr::write <StreamIO> (os, "");

    return previewPosition;
}


void
Header::readFrom (IStream &is, int &version)
{
    //
    // Read the magic number and the file format version number.
    // Then check if we can read the rest of this file.
    //

    int magic;

    Xdr::read <StreamIO> (is, magic);
    Xdr::read <StreamIO> (is, version);

    if (magic != MAGIC)
    {
        throw Iex::InputExc ("File is not an image file.");
    }

    if (getVersion (version) != EXR_VERSION)
    {
        THROW (Iex::InputExc, "Cannot read "
                              "version " << getVersion (version) << " "
                              "image files.  Current file format version "
                              "is " << EXR_VERSION << ".");
    }
    
    if (!supportsFlags (getFlags (version)))
    {
        THROW (Iex::InputExc, "The file format version number's flag field "
                              "contains unrecognized flags.");
    }

    //
    // Read all attributes.
    //

    while (true)
    {
        //
        // Read the name of the attribute.
        // A zero-length attribute name indicates the end of the header.
        //

        char name[100];
        Xdr::read <StreamIO> (is, sizeof (name), name);

        if (name[0] == 0)
            break;

        //
        // Read the attribute type and the size of the attribute value.
        //

        char typeName[100];
        int size;

        Xdr::read <StreamIO> (is, sizeof (typeName), typeName);
        Xdr::read <StreamIO> (is, size);

        AttributeMap::iterator i = _map.find (name);

        if (i != _map.end())
        {
            //
            // The attribute already exists (for example,
            // because it is a predefined attribute).
            // Read the attribute's new value from the file.
            //

            if (strncmp (i->second->typeName(), typeName, sizeof (typeName)))
                THROW (Iex::InputExc, "Unexpected type for image attribute "
                                      "\"" << name << "\".");

            i->second->readValueFrom (is, size, version);
        }
        else
        {
            //
            // The new attribute does not exist yet.
            // If the attribute type is of a known type,
            // read the attribute value.  If the attribute
            // is of an unknown type, read its value and
            // store it as an OpaqueAttribute.
            //

            Attribute *attr;

            if (Attribute::knownType (typeName))
                attr = Attribute::newAttribute (typeName);
            else
                attr = new OpaqueAttribute (typeName);

            try
            {
                attr->readValueFrom (is, size, version);
                _map[name] = attr;
            }
            catch (...)
            {
                delete attr;
                throw;
            }
        }
    }
}


} // namespace Imf

reply via email to

[Prev in Thread] Current Thread [Next in Thread]