Example #1
0
bool
OpenEXROutput::put_parameter (const std::string &name, TypeDesc type,
                              const void *data)
{
    // Translate
    std::string xname = name;
    if (istarts_with (xname, "oiio:"))
        return false;
    else if (iequals(xname, "worldtocamera"))
        xname = "worldToCamera";
    else if (iequals(xname, "worldtoscreen"))
        xname = "worldToNDC";
    else if (iequals(xname, "DateTime"))
        xname = "capDate";
    else if (iequals(xname, "description") || iequals(xname, "ImageDescription"))
        xname = "comments";
    else if (iequals(xname, "Copyright"))
        xname = "owner";
    else if (iequals(xname, "PixelAspectRatio"))
        xname = "pixelAspectRatio";
    else if (iequals(xname, "ExposureTime"))
        xname = "expTime";
    else if (iequals(xname, "FNumber"))
        xname = "aperture";
    else if (istarts_with (xname, format_prefix))
        xname = std::string (xname.begin()+format_prefix.size(), xname.end());

//    std::cerr << "exr put '" << name << "' -> '" << xname << "'\n";

    // Special cases
    if (iequals(xname, "Compression") && type == TypeDesc::STRING) {
        const char *str = *(char **)data;
        m_header->compression() = Imf::ZIP_COMPRESSION;  // Default
        if (str) {
            if (iequals (str, "none"))
                m_header->compression() = Imf::NO_COMPRESSION;
            else if (iequals (str, "deflate") || iequals (str, "zip")) 
                m_header->compression() = Imf::ZIP_COMPRESSION;
            else if (iequals (str, "rle")) 
                m_header->compression() = Imf::RLE_COMPRESSION;
            else if (iequals (str, "zips")) 
                m_header->compression() = Imf::ZIPS_COMPRESSION;
            else if (iequals (str, "piz")) 
                m_header->compression() = Imf::PIZ_COMPRESSION;
            else if (iequals (str, "pxr24")) 
                m_header->compression() = Imf::PXR24_COMPRESSION;
#ifdef IMF_B44_COMPRESSION
            // The enum Imf::B44_COMPRESSION is not defined in older versions
            // of OpenEXR, and there are no explicit version numbers in the
            // headers.  BUT this other related #define is present only in
            // the newer version.
            else if (iequals (str, "b44"))
                m_header->compression() = Imf::B44_COMPRESSION;
            else if (iequals (str, "b44a"))
                m_header->compression() = Imf::B44A_COMPRESSION;
#endif
        }
        return true;
    }

    if (iequals (xname, "openexr:lineOrder") && type == TypeDesc::STRING) {
        const char *str = *(char **)data;
        m_header->lineOrder() = Imf::INCREASING_Y;   // Default
        if (str) {
            if (iequals (str, "randomY"))
                m_header->lineOrder() = Imf::RANDOM_Y;
            else if (iequals (str, "decreasingY"))
                m_header->lineOrder() = Imf::DECREASING_Y;
        }
        return true;
    }

    // Supress planarconfig!
    if (iequals (xname, "planarconfig") || iequals (xname, "tiff:planarconfig"))
        return true;

    // General handling of attributes
    // FIXME -- police this if we ever allow arrays
    if (type == TypeDesc::INT || type == TypeDesc::UINT) {
        m_header->insert (xname.c_str(), Imf::IntAttribute (*(int*)data));
        return true;
    }
    if (type == TypeDesc::INT16) {
        m_header->insert (xname.c_str(), Imf::IntAttribute (*(short*)data));
        return true;
    }
    if (type == TypeDesc::UINT16) {
        m_header->insert (xname.c_str(), Imf::IntAttribute (*(unsigned short*)data));
        return true;
    }
    if (type == TypeDesc::FLOAT) {
        m_header->insert (xname.c_str(), Imf::FloatAttribute (*(float*)data));
        return true;
    }
    if (type == TypeDesc::HALF) {
        m_header->insert (xname.c_str(), Imf::FloatAttribute ((float)*(half*)data));
        return true;
    }
    if (type == TypeDesc::TypeMatrix) {
        m_header->insert (xname.c_str(), Imf::M44fAttribute (*(Imath::M44f*)data));
        return true;
    }
    if (type == TypeDesc::TypeString) {
        m_header->insert (xname.c_str(), Imf::StringAttribute (*(char**)data));
        return true;
    }
    if (type == TypeDesc::TypeVector) {
        m_header->insert (xname.c_str(), Imf::V3fAttribute (*(Imath::V3f*)data));
        return true;
    }

#ifdef DEBUG
    std::cerr << "Don't know what to do with " << type.c_str() << ' ' << xname << "\n";
#endif

    return false;
}
Example #2
0
void
applyCtlExrToExr
    (Imf::Header inHeader,
     Imf::Header &outHeader,
     const Imf::Array2D<Imf::Rgba> &inPixels,
     Imf::Array2D<Imf::Rgba> &outPixels,
     int w,
     int h,
     const std::vector<std::string> &transformNames,
     const AttrMap &extraAttrs)
{
    //
    // Make sure that the input and output headers contain
    // chromaticities and adoptedNeutral attributes.
    //

    if (!hasChromaticities (inHeader))
	addChromaticities (inHeader, Chromaticities());

    if (!hasAdoptedNeutral (inHeader))
	addAdoptedNeutral (inHeader, chromaticities(inHeader).white);

    if (!hasChromaticities (outHeader))
	addChromaticities (outHeader, chromaticities (inHeader));

    if (!hasAdoptedNeutral (outHeader))
	addAdoptedNeutral (outHeader, adoptedNeutral (inHeader));

    //
    // Add extraAttrs to the input header, possibly overriding
    // the values of existing input header attributes.
    //

    for (AttrMap::const_iterator i = extraAttrs.begin();
	 i != extraAttrs.end();
	 ++i)
    {
	inHeader.insert (i->first.c_str(), *i->second);
    }

    //
    // Initialize an "environment" header with the same data that
    // would be available to rendering transforms in an image viewing
    // program.  This allows transforms to bake color rendering into
    // the output file's pixels.
    //

    Header envHeader;
    initializeEnvHeader (envHeader);

    //
    // Set up input and output FrameBuffer objects for the transforms.
    //

    FrameBuffer inFb;
    initializeFrameBuffer (w, h, inPixels, inFb);

    FrameBuffer outFb;
    initializeFrameBuffer (w, h, outPixels, outFb);

    //
    // Run the CTL transforms
    //

    Box2i transformWindow (V2i (0, 0), V2i (w - 1, h - 1));

    SimdInterpreter interpreter;

    #ifdef CTL_MODULE_BASE_PATH

	//
	// The configuration script has defined a default
	// location for CTL modules.  Include this location
	// in the CTL module search path.
	//

	vector<string> paths = interpreter.modulePaths();
	paths.push_back (CTL_MODULE_BASE_PATH);
	interpreter.setModulePaths (paths);

    #endif

    ImfCtl::applyTransforms (interpreter,
			     transformNames,
			     transformWindow,
			     envHeader,
			     inHeader,
			     inFb,
			     outHeader,
			     outFb);
}
Example #3
0
bool
OpenEXROutput::open (const std::string &name, const ImageSpec &userspec,
                     OpenMode mode)
{
    if (mode == AppendSubimage) {
        error ("%s does not support subimages", format_name());
        return false;
    }

    if (mode == AppendMIPLevel && (m_output_scanline || m_output_tiled)) {
        // Special case for appending to an open file -- we don't need
        // to close and reopen
        if (m_spec.tile_width && m_levelmode != Imf::ONE_LEVEL) {
            // OpenEXR does not support differing tile sizes on different
            // MIP-map levels.  Reject the open() if not using the original
            // tile sizes.
            if (userspec.tile_width != m_spec.tile_width ||
                userspec.tile_height != m_spec.tile_height) {
                error ("OpenEXR tiles must have the same size on all MIPmap levels");
                return false;
            }
            // Copy the new mip level size.  Keep everything else from the
            // original level.
            m_spec.width = userspec.width;
            m_spec.height = userspec.height;
            // N.B. do we need to copy anything else from userspec?
            ++m_miplevel;
            return true;
        }
    }

    m_spec = userspec;  // Stash the spec

    if (m_spec.width < 1 || m_spec.height < 1) {
        error ("Image resolution must be at least 1x1, you asked for %d x %d",
               userspec.width, userspec.height);
        return false;
    }
    if (m_spec.depth < 1)
        m_spec.depth = 1;
    if (m_spec.depth > 1) {
        error ("%s does not support volume images (depth > 1)", format_name());
        return false;
    }

    if (m_spec.full_width <= 0)
        m_spec.full_width = m_spec.width;
    if (m_spec.full_height <= 0)
        m_spec.full_height = m_spec.height;

    // Force use of one of the three data types that OpenEXR supports
    switch (m_spec.format.basetype) {
    case TypeDesc::UINT:
        m_spec.format = TypeDesc::UINT;
        break;
    case TypeDesc::FLOAT:
    case TypeDesc::DOUBLE:
        m_spec.format = TypeDesc::FLOAT;
        break;
    default:
        // Everything else defaults to half
        m_spec.format = TypeDesc::HALF;
    }

    Imath::Box2i dataWindow (Imath::V2i (m_spec.x, m_spec.y),
                             Imath::V2i (m_spec.width + m_spec.x - 1,
                                         m_spec.height + m_spec.y - 1));
    Imath::Box2i displayWindow (Imath::V2i (m_spec.full_x, m_spec.full_y),
                                Imath::V2i (m_spec.full_width+m_spec.full_x-1,
                                            m_spec.full_height+m_spec.full_y-1));
    m_header = new Imf::Header (displayWindow, dataWindow);

    // Insert channels into the header.  Also give the channels names if
    // the user botched it.
    static const char *default_chan_names[] = { "R", "G", "B", "A" };
    m_spec.channelnames.resize (m_spec.nchannels);
    for (int c = 0;  c < m_spec.nchannels;  ++c) {
        if (m_spec.channelnames[c].empty())
            m_spec.channelnames[c] = (c<4) ? default_chan_names[c]
                                           : Strutil::format ("unknown %d", c);
        TypeDesc format = m_spec.channelformats.size() ?
                                  m_spec.channelformats[c] : m_spec.format;
        Imf::PixelType ptype;
        switch (format.basetype) {
        case TypeDesc::UINT:
            ptype = Imf::UINT;
            format = TypeDesc::UINT;
            break;
        case TypeDesc::FLOAT:
        case TypeDesc::DOUBLE:
            ptype = Imf::FLOAT;
            format = TypeDesc::FLOAT;
            break;
        default:
            // Everything else defaults to half
            ptype = Imf::HALF;
            format = TypeDesc::HALF;
        }
        
#ifdef OPENEXR_VERSION_IS_1_6_OR_LATER
        // Hint to lossy compression methods that indicates whether
        // human perception of the quantity represented by this channel
        // is closer to linear or closer to logarithmic.  Compression
        // methods may optimize image quality by adjusting pixel data
        // quantization acording to this hint.
        
        bool pLinear = iequals (m_spec.get_string_attribute ("oiio:ColorSpace", "Linear"), "Linear");
#endif
        m_pixeltype.push_back (ptype);
        if (m_spec.channelformats.size())
            m_spec.channelformats[c] = format;
        m_header->channels().insert (m_spec.channelnames[c].c_str(),
                                     Imf::Channel(ptype, 1, 1
#ifdef OPENEXR_VERSION_IS_1_6_OR_LATER
                                     , pLinear
#endif
                                     ));
    }
    ASSERT (m_pixeltype.size() == (size_t)m_spec.nchannels);

    // Default to ZIP compression if no request came with the user spec.
    if (! m_spec.find_attribute("compression"))
        m_spec.attribute ("compression", "zip");

    // Default to increasingY line order, same as EXR.
    if (! m_spec.find_attribute("openexr:lineOrder"))
        m_spec.attribute ("openexr:lineOrder", "increasingY");

    // Automatically set date field if the client didn't supply it.
    if (! m_spec.find_attribute("DateTime")) {
        time_t now;
        time (&now);
        struct tm mytm;
        Sysutil::get_local_time (&now, &mytm);
        std::string date = Strutil::format ("%4d:%02d:%02d %2d:%02d:%02d",
                               mytm.tm_year+1900, mytm.tm_mon+1, mytm.tm_mday,
                               mytm.tm_hour, mytm.tm_min, mytm.tm_sec);
        m_spec.attribute ("DateTime", date);
    }

    m_nsubimages = 1;
    m_subimage = 0;
    m_nmiplevels = 1;
    m_miplevel = 0;

    // Figure out if we are a mipmap or an environment map
    ImageIOParameter *param = m_spec.find_attribute ("textureformat");
    const char *textureformat = param ? *(char **)param->data() : NULL;
    m_levelmode = Imf::ONE_LEVEL;  // Default to no MIP-mapping
    m_roundingmode = m_spec.get_int_attribute ("openexr:roundingmode",
                                               Imf::ROUND_DOWN);

    if (textureformat) {
        if (iequals (textureformat, "Plain Texture")) {
            m_levelmode = m_spec.get_int_attribute ("openexr:levelmode",
                                                    Imf::MIPMAP_LEVELS);
        } else if (iequals (textureformat, "CubeFace Environment")) {
            m_levelmode = m_spec.get_int_attribute ("openexr:levelmode",
                                                    Imf::MIPMAP_LEVELS);
            m_header->insert ("envmap", Imf::EnvmapAttribute(Imf::ENVMAP_CUBE));
        } else if (iequals (textureformat, "LatLong Environment")) {
            m_levelmode = m_spec.get_int_attribute ("openexr:levelmode",
                                                    Imf::MIPMAP_LEVELS);
            m_header->insert ("envmap", Imf::EnvmapAttribute(Imf::ENVMAP_LATLONG));
        } else if (iequals (textureformat, "Shadow")) {
            m_levelmode = Imf::ONE_LEVEL;  // Force one level for shadow maps
        }

        if (m_levelmode == Imf::MIPMAP_LEVELS) {
            // Compute how many mip levels there will be
            int w = m_spec.width;
            int h = m_spec.height;
            while (w > 1 && h > 1) {
                if (m_roundingmode == Imf::ROUND_DOWN) {
                    w = w / 2;
                    h = h / 2;
                } else {
                    w = (w + 1) / 2;
                    h = (h + 1) / 2;
                }
                w = std::max (1, w);
                h = std::max (1, h);
                ++m_nmiplevels;
            }
        }
    }

    // Deal with all other params
    for (size_t p = 0;  p < m_spec.extra_attribs.size();  ++p)
        put_parameter (m_spec.extra_attribs[p].name().string(),
                       m_spec.extra_attribs[p].type(),
                       m_spec.extra_attribs[p].data());

    try {
        if (m_spec.tile_width) {
            m_header->setTileDescription (
                Imf::TileDescription (m_spec.tile_width, m_spec.tile_height,
                                      Imf::LevelMode(m_levelmode),
                                      Imf::LevelRoundingMode(m_roundingmode)));
            m_output_tiled = new Imf::TiledOutputFile (name.c_str(), *m_header);
        } else {
            m_output_scanline = new Imf::OutputFile (name.c_str(), *m_header);
        }
    }
    catch (const std::exception &e) {
        error ("OpenEXR exception: %s", e.what());
        m_output_scanline = NULL;
        return false;
    }
    if (! m_output_scanline && ! m_output_tiled) {
        error ("Unknown error opening EXR file");
        return false;
    }

    return true;
}