static void headerToCompoundData( const Imf::Header &header, CompoundData *blindData ) { for ( Imf::Header::ConstIterator attrIt = header.begin(); attrIt != header.end(); attrIt++ ) { std::string name = attrIt.name(); DataPtr data = attributeToData( attrIt.attribute() ); if ( data ) { addHeaderAttribute( name, data, blindData ); } } }
void OpenEXRInput::PartInfo::parse_header (const Imf::Header *header) { if (initialized) return; ASSERT (header); spec = ImageSpec(); top_datawindow = header->dataWindow(); top_displaywindow = header->displayWindow(); spec.x = top_datawindow.min.x; spec.y = top_datawindow.min.y; spec.z = 0; spec.width = top_datawindow.max.x - top_datawindow.min.x + 1; spec.height = top_datawindow.max.y - top_datawindow.min.y + 1; spec.depth = 1; topwidth = spec.width; // Save top-level mipmap dimensions topheight = spec.height; spec.full_x = top_displaywindow.min.x; spec.full_y = top_displaywindow.min.y; spec.full_z = 0; spec.full_width = top_displaywindow.max.x - top_displaywindow.min.x + 1; spec.full_height = top_displaywindow.max.y - top_displaywindow.min.y + 1; spec.full_depth = 1; spec.tile_depth = 1; if (header->hasTileDescription()) { const Imf::TileDescription &td (header->tileDescription()); spec.tile_width = td.xSize; spec.tile_height = td.ySize; levelmode = td.mode; roundingmode = td.roundingMode; if (levelmode == Imf::MIPMAP_LEVELS) nmiplevels = numlevels (std::max(topwidth,topheight), roundingmode); else if (levelmode == Imf::RIPMAP_LEVELS) nmiplevels = numlevels (std::max(topwidth,topheight), roundingmode); else nmiplevels = 1; } else { spec.tile_width = 0; spec.tile_height = 0; levelmode = Imf::ONE_LEVEL; nmiplevels = 1; } query_channels (header); // also sets format #ifdef USE_OPENEXR_VERSION2 spec.deep = Strutil::istarts_with (header->type(), "deep"); #endif // Unless otherwise specified, exr files are assumed to be linear. spec.attribute ("oiio:ColorSpace", "Linear"); if (levelmode != Imf::ONE_LEVEL) spec.attribute ("openexr:roundingmode", roundingmode); const Imf::EnvmapAttribute *envmap; envmap = header->findTypedAttribute<Imf::EnvmapAttribute>("envmap"); if (envmap) { cubeface = (envmap->value() == Imf::ENVMAP_CUBE); spec.attribute ("textureformat", cubeface ? "CubeFace Environment" : "LatLong Environment"); // OpenEXR conventions for env maps if (! cubeface) spec.attribute ("oiio:updirection", "y"); spec.attribute ("oiio:sampleborder", 1); // FIXME - detect CubeFace Shadow? } else { cubeface = false; if (spec.tile_width && levelmode == Imf::MIPMAP_LEVELS) spec.attribute ("textureformat", "Plain Texture"); // FIXME - detect Shadow } const Imf::CompressionAttribute *compressattr; compressattr = header->findTypedAttribute<Imf::CompressionAttribute>("compression"); if (compressattr) { const char *comp = NULL; switch (compressattr->value()) { case Imf::NO_COMPRESSION : comp = "none"; break; case Imf::RLE_COMPRESSION : comp = "rle"; break; case Imf::ZIPS_COMPRESSION : comp = "zips"; break; case Imf::ZIP_COMPRESSION : comp = "zip"; break; case Imf::PIZ_COMPRESSION : comp = "piz"; break; case Imf::PXR24_COMPRESSION : comp = "pxr24"; break; #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. case Imf::B44_COMPRESSION : comp = "b44"; break; case Imf::B44A_COMPRESSION : comp = "b44a"; break; #endif #if defined(OPENEXR_VERSION_MAJOR) && \ (OPENEXR_VERSION_MAJOR*10000+OPENEXR_VERSION_MINOR*100+OPENEXR_VERSION_PATCH) >= 20200 case Imf::DWAA_COMPRESSION : comp = "dwaa"; break; case Imf::DWAB_COMPRESSION : comp = "dwab"; break; #endif default: break; } if (comp) spec.attribute ("compression", comp); } for (Imf::Header::ConstIterator hit = header->begin(); hit != header->end(); ++hit) { const Imf::IntAttribute *iattr; const Imf::FloatAttribute *fattr; const Imf::StringAttribute *sattr; const Imf::M44fAttribute *mattr; const Imf::V3fAttribute *v3fattr; const Imf::V3iAttribute *v3iattr; const Imf::V2fAttribute *v2fattr; const Imf::V2iAttribute *v2iattr; const Imf::Box2iAttribute *b2iattr; const Imf::Box2fAttribute *b2fattr; const Imf::TimeCodeAttribute *tattr; const Imf::KeyCodeAttribute *kcattr; #ifdef USE_OPENEXR_VERSION2 const Imf::StringVectorAttribute *svattr; #endif const char *name = hit.name(); std::string oname = exr_tag_to_ooio_std[name]; if (oname.empty()) // Empty string means skip this attrib continue; // if (oname == name) // oname = std::string(format_name()) + "_" + oname; const Imf::Attribute &attrib = hit.attribute(); std::string type = attrib.typeName(); if (type == "string" && (sattr = header->findTypedAttribute<Imf::StringAttribute> (name))) spec.attribute (oname, sattr->value().c_str()); else if (type == "int" && (iattr = header->findTypedAttribute<Imf::IntAttribute> (name))) spec.attribute (oname, iattr->value()); else if (type == "float" && (fattr = header->findTypedAttribute<Imf::FloatAttribute> (name))) spec.attribute (oname, fattr->value()); else if (type == "m44f" && (mattr = header->findTypedAttribute<Imf::M44fAttribute> (name))) spec.attribute (oname, TypeDesc::TypeMatrix, &(mattr->value())); else if (type == "v3f" && (v3fattr = header->findTypedAttribute<Imf::V3fAttribute> (name))) spec.attribute (oname, TypeDesc::TypeVector, &(v3fattr->value())); else if (type == "v3i" && (v3iattr = header->findTypedAttribute<Imf::V3iAttribute> (name))) { TypeDesc v3 (TypeDesc::INT, TypeDesc::VEC3, TypeDesc::VECTOR); spec.attribute (oname, v3, &(v3iattr->value())); } else if (type == "v2f" && (v2fattr = header->findTypedAttribute<Imf::V2fAttribute> (name))) { TypeDesc v2 (TypeDesc::FLOAT,TypeDesc::VEC2); spec.attribute (oname, v2, &(v2fattr->value())); } else if (type == "v2i" && (v2iattr = header->findTypedAttribute<Imf::V2iAttribute> (name))) { TypeDesc v2 (TypeDesc::INT,TypeDesc::VEC2); spec.attribute (oname, v2, &(v2iattr->value())); } #ifdef USE_OPENEXR_VERSION2 else if (type == "stringvector" && (svattr = header->findTypedAttribute<Imf::StringVectorAttribute> (name))) { std::vector<std::string> strvec = svattr->value(); std::vector<ustring> ustrvec (strvec.size()); for (size_t i = 0, e = strvec.size(); i < e; ++i) ustrvec[i] = strvec[i]; TypeDesc sv (TypeDesc::STRING, ustrvec.size()); spec.attribute(oname, sv, &ustrvec[0]); } #endif else if (type == "box2i" && (b2iattr = header->findTypedAttribute<Imf::Box2iAttribute> (name))) { TypeDesc bx (TypeDesc::INT, TypeDesc::VEC2, 2); spec.attribute (oname, bx, &b2iattr->value()); } else if (type == "box2f" && (b2fattr = header->findTypedAttribute<Imf::Box2fAttribute> (name))) { TypeDesc bx (TypeDesc::FLOAT, TypeDesc::VEC2, 2); spec.attribute (oname, bx, &b2fattr->value()); } else if (type == "timecode" && (tattr = header->findTypedAttribute<Imf::TimeCodeAttribute> (name))) { unsigned int timecode[2]; timecode[0] = tattr->value().timeAndFlags(Imf::TimeCode::TV60_PACKING); //TV60 returns unchanged _time timecode[1] = tattr->value().userData(); // Elevate "timeCode" to smpte:TimeCode if (oname == "timeCode") oname = "smpte:TimeCode"; spec.attribute(oname, TypeDesc::TypeTimeCode, timecode); } else if (type == "keycode" && (kcattr = header->findTypedAttribute<Imf::KeyCodeAttribute> (name))) { const Imf::KeyCode *k = &kcattr->value(); unsigned int keycode[7]; keycode[0] = k->filmMfcCode(); keycode[1] = k->filmType(); keycode[2] = k->prefix(); keycode[3] = k->count(); keycode[4] = k->perfOffset(); keycode[5] = k->perfsPerFrame(); keycode[6] = k->perfsPerCount(); // Elevate "keyCode" to smpte:KeyCode if (oname == "keyCode") oname = "smpte:KeyCode"; spec.attribute(oname, TypeDesc::TypeKeyCode, keycode); } else { #if 0 std::cerr << " unknown attribute " << type << ' ' << name << "\n"; #endif } } #ifdef USE_OPENEXR_VERSION2 // EXR "name" also gets passed along as "oiio:subimagename". if (header->hasName()) spec.attribute ("oiio:subimagename", header->name()); #endif initialized = true; }
/*! Tries to fill the image object with the data read from the given input stream. Returns true on success. */ bool EXRImageFileType::read( Image *image, std::istream &is, const std::string &mimetype) { #ifdef OSG_WITH_IMF if (!is.good()) return false; const char *dummy = ""; StdIStream file(is, dummy); Imf::Int64 pos = file.tellg(); bool check = isOpenExrFile(is); file.seekg(pos); if (!check) { FFATAL(( "Wrong format, no %s image given!\n", mimetype.c_str() )); return false; } // just read the header and get the channel count int channel_count = 0; pos = file.tellg(); try { Imf::RgbaInputFile stream(file); const Imf::Header &header = stream.header(); const Imf::ChannelList &channels = header.channels(); for(Imf::ChannelList::ConstIterator it = channels.begin(); it != channels.end(); ++it) { ++channel_count; } } catch(std::exception &e) { FFATAL(( "Error while trying to read OpenEXR Image from stream: %s\n", e.what() )); return false; } file.seekg(pos); if(channel_count <= 4) { // TODO: check for mipmap levels, // look if line order is s.th. else than INCREASING_Y try { Int32 width, height, numImg = 1; Imf::RgbaInputFile stream(file); Imath::Box2i dw = stream.dataWindow(); Imf::Array2D<Imf::Rgba> pixels; const Imf::Header &header = stream.header(); // const Imf::LineOrder &order = header.lineOrder(); const Imf::EnvmapAttribute *envmap = header.findTypedAttribute<Imf::EnvmapAttribute>("envmap"); width = dw.max.x - dw.min.x + 1; height = dw.max.y - dw.min.y + 1; pixels.resizeErase(height, width); if(envmap && envmap->value() == Imf::ENVMAP_CUBE) { numImg = 6; height /= numImg; if (width != height) { FFATAL(( "Cubemaps must have squared size, " "but w=%d and h=%d!\n", width, height )); return false; } } stream.setFrameBuffer(&pixels[0][0] - dw.min.x - dw.min.y * width, 1, width); stream.readPixels(dw.min.y, dw.max.y); image->set( Image::OSG_RGBA_PF, width, height, 1, 1, 1, 0, 0, Image::OSG_FLOAT16_IMAGEDATA, true, numImg ); image->clearHalf(); // now add custom attributes for(Imf::Header::ConstIterator it = header.begin(); it != header.end(); ++it) { Imf::Attribute *copy = it.attribute().copy(); Imf::StringAttribute *sa = dynamic_cast<Imf::StringAttribute *>(copy); if(sa != NULL) image->setAttachmentField(it.name(), sa->value()); delete copy; } Real16 *data = reinterpret_cast<Real16*>(image->editData()); for (Int32 side=numImg-1; side >=0; side--) { Int32 i, j, size = side * width * height * 4; for (Int32 y=side*height; y<(side+1)*height; y++) { for (Int32 x=0; x<width; x++) { if (numImg == 1 || side == 2 || side == 3) { i = (2 * side + 1) * height - (y + 1); // new y j = x; } else { i = y; j = width - x - 1; // new x } *(data + size++) = Real16(pixels[i][j].r); *(data + size++) = Real16(pixels[i][j].g); *(data + size++) = Real16(pixels[i][j].b); *(data + size++) = Real16(pixels[i][j].a); } } } return true; } catch(std::exception &e) { FFATAL(( "Error while trying to read OpenEXR Image from stream: " "%s\n", e.what() )); return false; } } else { try { if(channel_count % 4 != 0) { FFATAL(( "Error while trying to read OpenEXR Image from " "stream, channel count of %d is not supported!\n", channel_count)); return false; } int num_img = channel_count / 4; Imf::InputFile stream(file); const Imf::Header &header = stream.header(); Imath::Box2i dw = header.dataWindow(); int width = dw.max.x - dw.min.x + 1; int height = dw.max.y - dw.min.y + 1; image->set(Image::OSG_RGBA_PF, width, height, 1, 1, 1, 0, 0, Image::OSG_FLOAT16_IMAGEDATA, true, num_img); image->clearHalf(); // now add custom attributes for(Imf::Header::ConstIterator it = header.begin(); it != header.end(); ++it ) { Imf::Attribute *copy = it.attribute().copy(); Imf::StringAttribute *sa = dynamic_cast<Imf::StringAttribute *>(copy); if(sa != NULL) image->setAttachmentField(it.name(), sa->value()); delete copy; } const Imf::ChannelList &channels = header.channels(); // do some channel name checks bool channel_error = false; for(Imf::ChannelList::ConstIterator it=channels.begin();it!=channels.end();++it) { for(int side=0;side>num_img;++side) { char cn[20]; sprintf(cn, "%d", side); char name[20]; sprintf(name, "R%s", side == 0 ? "" : cn); if(channels.findChannel(name) == NULL) channel_error = true; sprintf(name, "G%s", side == 0 ? "" : cn); if(channels.findChannel(name) == NULL) channel_error = true; sprintf(name, "B%s", side == 0 ? "" : cn); if(channels.findChannel(name) == NULL) channel_error = true; sprintf(name, "A%s", side == 0 ? "" : cn); if(channels.findChannel(name) == NULL) channel_error = true; } } if(channel_error) { FFATAL(( "Error while trying to read OpenEXR Image from " "stream, expected channel names 'R' 'G' 'B' 'A', " "'R1' 'G1', 'B1', 'A1', ...\n")); return false; } Imf::FrameBuffer frame_buffer; // we need to do a vertical flip so we read single scan lines in. int current_scan_line = 0; for(int i=height-1;i>=0;--i) { for(int side=0;side<num_img;++side) { char *data = (reinterpret_cast<char *>(image->editData(0, 0, side))) + i * (sizeof(Real16) * 4 * width); data -= current_scan_line * (sizeof(Real16) * 4 * width); char cn[20]; sprintf(cn, "%d", side); char name[20]; sprintf(name, "R%s", side == 0 ? "" : cn); frame_buffer.insert(name, Imf::Slice(Imf::HALF, data, sizeof(Real16) * 4, sizeof(Real16) * 4 * width)); sprintf(name, "G%s", side == 0 ? "" : cn); frame_buffer.insert(name, Imf::Slice(Imf::HALF, data + 1 * sizeof(Real16), sizeof(Real16) * 4, sizeof(Real16) * 4 * width)); sprintf(name, "B%s", side == 0 ? "" : cn); frame_buffer.insert(name, Imf::Slice(Imf::HALF, data + 2 * sizeof(Real16), sizeof(Real16) * 4, sizeof(Real16) * 4 * width)); sprintf(name, "A%s", side == 0 ? "" : cn); frame_buffer.insert(name, Imf::Slice(Imf::HALF, data + 3 * sizeof(Real16), sizeof(Real16) * 4, sizeof(Real16) * 4 * width)); } stream.setFrameBuffer(frame_buffer); stream.readPixels(current_scan_line, current_scan_line); ++current_scan_line; } return true; } catch(std::exception &e) { FFATAL(( "Error while trying to read OpenEXR Image from stream: %s\n", e.what() )); return false; } } #else SWARNING << getMimeType() << " read is not compiled into the current binary " << std::endl; return false; #endif }
void OpenEXRInput::PartInfo::parse_header (const Imf::Header *header) { if (initialized) return; ASSERT (header); spec = ImageSpec(); top_datawindow = header->dataWindow(); top_displaywindow = header->displayWindow(); spec.x = top_datawindow.min.x; spec.y = top_datawindow.min.y; spec.z = 0; spec.width = top_datawindow.max.x - top_datawindow.min.x + 1; spec.height = top_datawindow.max.y - top_datawindow.min.y + 1; spec.depth = 1; topwidth = spec.width; // Save top-level mipmap dimensions topheight = spec.height; spec.full_x = top_displaywindow.min.x; spec.full_y = top_displaywindow.min.y; spec.full_z = 0; spec.full_width = top_displaywindow.max.x - top_displaywindow.min.x + 1; spec.full_height = top_displaywindow.max.y - top_displaywindow.min.y + 1; spec.full_depth = 1; spec.tile_depth = 1; if (header->hasTileDescription() && Strutil::icontains(header->type(), "tile")) { const Imf::TileDescription &td (header->tileDescription()); spec.tile_width = td.xSize; spec.tile_height = td.ySize; levelmode = td.mode; roundingmode = td.roundingMode; if (levelmode == Imf::MIPMAP_LEVELS) nmiplevels = numlevels (std::max(topwidth,topheight), roundingmode); else if (levelmode == Imf::RIPMAP_LEVELS) nmiplevels = numlevels (std::max(topwidth,topheight), roundingmode); else nmiplevels = 1; } else { spec.tile_width = 0; spec.tile_height = 0; levelmode = Imf::ONE_LEVEL; nmiplevels = 1; } query_channels (header); // also sets format spec.deep = Strutil::istarts_with (header->type(), "deep"); // Unless otherwise specified, exr files are assumed to be linear. spec.attribute ("oiio:ColorSpace", "Linear"); if (levelmode != Imf::ONE_LEVEL) spec.attribute ("openexr:roundingmode", roundingmode); const Imf::EnvmapAttribute *envmap; envmap = header->findTypedAttribute<Imf::EnvmapAttribute>("envmap"); if (envmap) { cubeface = (envmap->value() == Imf::ENVMAP_CUBE); spec.attribute ("textureformat", cubeface ? "CubeFace Environment" : "LatLong Environment"); // OpenEXR conventions for env maps if (! cubeface) spec.attribute ("oiio:updirection", "y"); spec.attribute ("oiio:sampleborder", 1); // FIXME - detect CubeFace Shadow? } else { cubeface = false; if (spec.tile_width && levelmode == Imf::MIPMAP_LEVELS) spec.attribute ("textureformat", "Plain Texture"); // FIXME - detect Shadow } const Imf::CompressionAttribute *compressattr; compressattr = header->findTypedAttribute<Imf::CompressionAttribute>("compression"); if (compressattr) { const char *comp = NULL; switch (compressattr->value()) { case Imf::NO_COMPRESSION : comp = "none"; break; case Imf::RLE_COMPRESSION : comp = "rle"; break; case Imf::ZIPS_COMPRESSION : comp = "zips"; break; case Imf::ZIP_COMPRESSION : comp = "zip"; break; case Imf::PIZ_COMPRESSION : comp = "piz"; break; case Imf::PXR24_COMPRESSION : comp = "pxr24"; break; #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. case Imf::B44_COMPRESSION : comp = "b44"; break; case Imf::B44A_COMPRESSION : comp = "b44a"; break; #endif #if defined(OPENEXR_VERSION_MAJOR) && \ (OPENEXR_VERSION_MAJOR*10000+OPENEXR_VERSION_MINOR*100+OPENEXR_VERSION_PATCH) >= 20200 case Imf::DWAA_COMPRESSION : comp = "dwaa"; break; case Imf::DWAB_COMPRESSION : comp = "dwab"; break; #endif default: break; } if (comp) spec.attribute ("compression", comp); } for (Imf::Header::ConstIterator hit = header->begin(); hit != header->end(); ++hit) { const Imf::IntAttribute *iattr; const Imf::FloatAttribute *fattr; const Imf::StringAttribute *sattr; const Imf::M33fAttribute *m33fattr; const Imf::M44fAttribute *m44fattr; const Imf::V3fAttribute *v3fattr; const Imf::V3iAttribute *v3iattr; const Imf::V2fAttribute *v2fattr; const Imf::V2iAttribute *v2iattr; const Imf::Box2iAttribute *b2iattr; const Imf::Box2fAttribute *b2fattr; const Imf::TimeCodeAttribute *tattr; const Imf::KeyCodeAttribute *kcattr; const Imf::ChromaticitiesAttribute *crattr; const Imf::RationalAttribute *rattr; const Imf::StringVectorAttribute *svattr; const Imf::DoubleAttribute *dattr; const Imf::V2dAttribute *v2dattr; const Imf::V3dAttribute *v3dattr; const Imf::M33dAttribute *m33dattr; const Imf::M44dAttribute *m44dattr; const char *name = hit.name(); std::string oname = exr_tag_to_oiio_std[name]; if (oname.empty()) // Empty string means skip this attrib continue; // if (oname == name) // oname = std::string(format_name()) + "_" + oname; const Imf::Attribute &attrib = hit.attribute(); std::string type = attrib.typeName(); if (type == "string" && (sattr = header->findTypedAttribute<Imf::StringAttribute> (name))) spec.attribute (oname, sattr->value().c_str()); else if (type == "int" && (iattr = header->findTypedAttribute<Imf::IntAttribute> (name))) spec.attribute (oname, iattr->value()); else if (type == "float" && (fattr = header->findTypedAttribute<Imf::FloatAttribute> (name))) spec.attribute (oname, fattr->value()); else if (type == "m33f" && (m33fattr = header->findTypedAttribute<Imf::M33fAttribute> (name))) spec.attribute (oname, TypeMatrix33, &(m33fattr->value())); else if (type == "m44f" && (m44fattr = header->findTypedAttribute<Imf::M44fAttribute> (name))) spec.attribute (oname, TypeMatrix44, &(m44fattr->value())); else if (type == "v3f" && (v3fattr = header->findTypedAttribute<Imf::V3fAttribute> (name))) spec.attribute (oname, TypeVector, &(v3fattr->value())); else if (type == "v3i" && (v3iattr = header->findTypedAttribute<Imf::V3iAttribute> (name))) { TypeDesc v3 (TypeDesc::INT, TypeDesc::VEC3, TypeDesc::VECTOR); spec.attribute (oname, v3, &(v3iattr->value())); } else if (type == "v2f" && (v2fattr = header->findTypedAttribute<Imf::V2fAttribute> (name))) { TypeDesc v2 (TypeDesc::FLOAT,TypeDesc::VEC2); spec.attribute (oname, v2, &(v2fattr->value())); } else if (type == "v2i" && (v2iattr = header->findTypedAttribute<Imf::V2iAttribute> (name))) { TypeDesc v2 (TypeDesc::INT,TypeDesc::VEC2); spec.attribute (oname, v2, &(v2iattr->value())); } else if (type == "stringvector" && (svattr = header->findTypedAttribute<Imf::StringVectorAttribute> (name))) { std::vector<std::string> strvec = svattr->value(); std::vector<ustring> ustrvec (strvec.size()); for (size_t i = 0, e = strvec.size(); i < e; ++i) ustrvec[i] = strvec[i]; TypeDesc sv (TypeDesc::STRING, ustrvec.size()); spec.attribute(oname, sv, &ustrvec[0]); } else if (type == "double" && (dattr = header->findTypedAttribute<Imf::DoubleAttribute> (name))) { TypeDesc d (TypeDesc::DOUBLE); spec.attribute (oname, d, &(dattr->value())); } else if (type == "v2d" && (v2dattr = header->findTypedAttribute<Imf::V2dAttribute> (name))) { TypeDesc v2 (TypeDesc::DOUBLE,TypeDesc::VEC2); spec.attribute (oname, v2, &(v2dattr->value())); } else if (type == "v3d" && (v3dattr = header->findTypedAttribute<Imf::V3dAttribute> (name))) { TypeDesc v3 (TypeDesc::DOUBLE,TypeDesc::VEC3, TypeDesc::VECTOR); spec.attribute (oname, v3, &(v3dattr->value())); } else if (type == "m33d" && (m33dattr = header->findTypedAttribute<Imf::M33dAttribute> (name))) { TypeDesc m33 (TypeDesc::DOUBLE, TypeDesc::MATRIX33); spec.attribute (oname, m33, &(m33dattr->value())); } else if (type == "m44d" && (m44dattr = header->findTypedAttribute<Imf::M44dAttribute> (name))) { TypeDesc m44 (TypeDesc::DOUBLE, TypeDesc::MATRIX44); spec.attribute (oname, m44, &(m44dattr->value())); } else if (type == "box2i" && (b2iattr = header->findTypedAttribute<Imf::Box2iAttribute> (name))) { TypeDesc bx (TypeDesc::INT, TypeDesc::VEC2, 2); spec.attribute (oname, bx, &b2iattr->value()); } else if (type == "box2f" && (b2fattr = header->findTypedAttribute<Imf::Box2fAttribute> (name))) { TypeDesc bx (TypeDesc::FLOAT, TypeDesc::VEC2, 2); spec.attribute (oname, bx, &b2fattr->value()); } else if (type == "timecode" && (tattr = header->findTypedAttribute<Imf::TimeCodeAttribute> (name))) { unsigned int timecode[2]; timecode[0] = tattr->value().timeAndFlags(Imf::TimeCode::TV60_PACKING); //TV60 returns unchanged _time timecode[1] = tattr->value().userData(); // Elevate "timeCode" to smpte:TimeCode if (oname == "timeCode") oname = "smpte:TimeCode"; spec.attribute(oname, TypeTimeCode, timecode); } else if (type == "keycode" && (kcattr = header->findTypedAttribute<Imf::KeyCodeAttribute> (name))) { const Imf::KeyCode *k = &kcattr->value(); unsigned int keycode[7]; keycode[0] = k->filmMfcCode(); keycode[1] = k->filmType(); keycode[2] = k->prefix(); keycode[3] = k->count(); keycode[4] = k->perfOffset(); keycode[5] = k->perfsPerFrame(); keycode[6] = k->perfsPerCount(); // Elevate "keyCode" to smpte:KeyCode if (oname == "keyCode") oname = "smpte:KeyCode"; spec.attribute(oname, TypeKeyCode, keycode); } else if (type == "chromaticities" && (crattr = header->findTypedAttribute<Imf::ChromaticitiesAttribute> (name))) { const Imf::Chromaticities *chroma = &crattr->value(); spec.attribute (oname, TypeDesc(TypeDesc::FLOAT,8), (const float *)chroma); } else if (type == "rational" && (rattr = header->findTypedAttribute<Imf::RationalAttribute> (name))) { const Imf::Rational *rational = &rattr->value(); int n = rational->n; unsigned int d = rational->d; if (d < (1UL << 31)) { int r[2]; r[0] = n; r[1] = static_cast<int>(d); spec.attribute (oname, TypeRational, r); } else if (int f = static_cast<int>(boost::math::gcd<long int>(rational[0], rational[1])) > 1) { int r[2]; r[0] = n / f; r[1] = static_cast<int>(d / f); spec.attribute (oname, TypeRational, r); } else { // TODO: find a way to allow the client to accept "close" rational values OIIO::debug ("Don't know what to do with OpenEXR Rational attribute %s with value %d / %u that we cannot represent exactly", oname, n, d); } } else { #if 0 std::cerr << " unknown attribute " << type << ' ' << name << "\n"; #endif } } float aspect = spec.get_float_attribute ("PixelAspectRatio", 0.0f); float xdensity = spec.get_float_attribute ("XResolution", 0.0f); if (xdensity) { // If XResolution is found, supply the YResolution and unit. spec.attribute ("YResolution", xdensity * (aspect ? aspect : 1.0f)); spec.attribute ("ResolutionUnit", "in"); // EXR is always pixels/inch } // EXR "name" also gets passed along as "oiio:subimagename". if (header->hasName()) spec.attribute ("oiio:subimagename", header->name()); // Squash some problematic texture metadata if we suspect it's wrong pvt::check_texture_metadata_sanity (spec); initialized = true; }
void OpenEXRInput::PartInfo::parse_header (const Imf::Header *header) { if (initialized) return; ASSERT (header); spec = ImageSpec(); top_datawindow = header->dataWindow(); top_displaywindow = header->displayWindow(); spec.x = top_datawindow.min.x; spec.y = top_datawindow.min.y; spec.z = 0; spec.width = top_datawindow.max.x - top_datawindow.min.x + 1; spec.height = top_datawindow.max.y - top_datawindow.min.y + 1; spec.depth = 1; topwidth = spec.width; // Save top-level mipmap dimensions topheight = spec.height; spec.full_x = top_displaywindow.min.x; spec.full_y = top_displaywindow.min.y; spec.full_z = 0; spec.full_width = top_displaywindow.max.x - top_displaywindow.min.x + 1; spec.full_height = top_displaywindow.max.y - top_displaywindow.min.y + 1; spec.full_depth = 1; spec.tile_depth = 1; if (header->hasTileDescription()) { const Imf::TileDescription &td (header->tileDescription()); spec.tile_width = td.xSize; spec.tile_height = td.ySize; levelmode = td.mode; roundingmode = td.roundingMode; if (levelmode == Imf::MIPMAP_LEVELS) nmiplevels = numlevels (std::max(topwidth,topheight), roundingmode); else if (levelmode == Imf::RIPMAP_LEVELS) nmiplevels = numlevels (std::max(topwidth,topheight), roundingmode); else nmiplevels = 1; } else { spec.tile_width = 0; spec.tile_height = 0; levelmode = Imf::ONE_LEVEL; nmiplevels = 1; } query_channels (header); // also sets format #ifdef USE_OPENEXR_VERSION2 spec.deep = Imf::isDeepData (header->type()); #endif // Unless otherwise specified, exr files are assumed to be linear. spec.attribute ("oiio:ColorSpace", "Linear"); if (levelmode != Imf::ONE_LEVEL) spec.attribute ("openexr:roundingmode", roundingmode); const Imf::EnvmapAttribute *envmap; envmap = header->findTypedAttribute<Imf::EnvmapAttribute>("envmap"); if (envmap) { cubeface = (envmap->value() == Imf::ENVMAP_CUBE); spec.attribute ("textureformat", cubeface ? "CubeFace Environment" : "LatLong Environment"); // OpenEXR conventions for env maps if (! cubeface) spec.attribute ("oiio:updirection", "y"); spec.attribute ("oiio:sampleborder", 1); // FIXME - detect CubeFace Shadow? } else { cubeface = false; if (spec.tile_width && levelmode == Imf::MIPMAP_LEVELS) spec.attribute ("textureformat", "Plain Texture"); // FIXME - detect Shadow } const Imf::CompressionAttribute *compressattr; compressattr = header->findTypedAttribute<Imf::CompressionAttribute>("compression"); if (compressattr) { const char *comp = NULL; switch (compressattr->value()) { case Imf::NO_COMPRESSION : comp = "none"; break; case Imf::RLE_COMPRESSION : comp = "rle"; break; case Imf::ZIPS_COMPRESSION : comp = "zips"; break; case Imf::ZIP_COMPRESSION : comp = "zip"; break; case Imf::PIZ_COMPRESSION : comp = "piz"; break; case Imf::PXR24_COMPRESSION : comp = "pxr24"; break; #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. case Imf::B44_COMPRESSION : comp = "b44"; break; case Imf::B44A_COMPRESSION : comp = "b44a"; break; #endif default: break; } if (comp) spec.attribute ("compression", comp); } for (Imf::Header::ConstIterator hit = header->begin(); hit != header->end(); ++hit) { const Imf::IntAttribute *iattr; const Imf::FloatAttribute *fattr; const Imf::StringAttribute *sattr; const Imf::M44fAttribute *mattr; const Imf::V3fAttribute *vattr; const Imf::V2fAttribute *v2attr; const char *name = hit.name(); std::string oname = exr_tag_to_ooio_std[name]; if (oname.empty()) // Empty string means skip this attrib continue; // if (oname == name) // oname = std::string(format_name()) + "_" + oname; const Imf::Attribute &attrib = hit.attribute(); std::string type = attrib.typeName(); if (type == "string" && (sattr = header->findTypedAttribute<Imf::StringAttribute> (name))) spec.attribute (oname, sattr->value().c_str()); else if (type == "int" && (iattr = header->findTypedAttribute<Imf::IntAttribute> (name))) spec.attribute (oname, iattr->value()); else if (type == "float" && (fattr = header->findTypedAttribute<Imf::FloatAttribute> (name))) spec.attribute (oname, fattr->value()); else if (type == "m44f" && (mattr = header->findTypedAttribute<Imf::M44fAttribute> (name))) spec.attribute (oname, TypeDesc::TypeMatrix, &(mattr->value())); else if (type == "v3f" && (vattr = header->findTypedAttribute<Imf::V3fAttribute> (name))) spec.attribute (oname, TypeDesc::TypeVector, &(vattr->value())); else if (type == "v2f" && (v2attr = header->findTypedAttribute<Imf::V2fAttribute> (name))) { TypeDesc v2 (TypeDesc::FLOAT,TypeDesc::VEC2); spec.attribute (oname, v2, &(v2attr->value())); } else { #if 0 std::cerr << " unknown attribute " << type << ' ' << name << "\n"; #endif } } initialized = true; }
bool OpenEXRInput::open (const std::string &name, ImageSpec &newspec) { // Quick check to reject non-exr files bool tiled; if (! Imf::isOpenExrFile (name.c_str(), tiled)) return false; m_spec = ImageSpec(); // Clear everything with default constructor // Unless otherwise specified, exr files are assumed to be linear. m_spec.attribute ("oiio:ColorSpace", "Linear"); try { if (tiled) { m_input_tiled = new Imf::TiledInputFile (name.c_str()); m_header = &(m_input_tiled->header()); } else { m_input_scanline = new Imf::InputFile (name.c_str()); m_header = &(m_input_scanline->header()); } } catch (const std::exception &e) { error ("OpenEXR exception: %s", e.what()); return false; } if (! m_input_scanline && ! m_input_tiled) { error ("Unknown error opening EXR file"); return false; } Imath::Box2i datawindow = m_header->dataWindow(); m_spec.x = datawindow.min.x; m_spec.y = datawindow.min.y; m_spec.z = 0; m_spec.width = datawindow.max.x - datawindow.min.x + 1; m_spec.height = datawindow.max.y - datawindow.min.y + 1; m_spec.depth = 1; m_topwidth = m_spec.width; // Save top-level mipmap dimensions m_topheight = m_spec.height; Imath::Box2i displaywindow = m_header->displayWindow(); m_spec.full_x = displaywindow.min.x; m_spec.full_y = displaywindow.min.y; m_spec.full_z = 0; m_spec.full_width = displaywindow.max.x - displaywindow.min.x + 1; m_spec.full_height = displaywindow.max.y - displaywindow.min.y + 1; m_spec.full_depth = 1; if (tiled) { m_spec.tile_width = m_input_tiled->tileXSize(); m_spec.tile_height = m_input_tiled->tileYSize(); } else { m_spec.tile_width = 0; m_spec.tile_height = 0; } m_spec.tile_depth = 1; query_channels (); // also sets format m_nsubimages = 1; if (tiled) { // FIXME: levelmode m_levelmode = m_input_tiled->levelMode(); m_roundingmode = m_input_tiled->levelRoundingMode(); if (m_levelmode == Imf::MIPMAP_LEVELS) { m_nmiplevels = m_input_tiled->numLevels(); m_spec.attribute ("openexr:roundingmode", m_roundingmode); } else if (m_levelmode == Imf::RIPMAP_LEVELS) { m_nmiplevels = std::max (m_input_tiled->numXLevels(), m_input_tiled->numYLevels()); m_spec.attribute ("openexr:roundingmode", m_roundingmode); } else { m_nmiplevels = 1; } } else { m_levelmode = Imf::ONE_LEVEL; m_nmiplevels = 1; } const Imf::EnvmapAttribute *envmap; envmap = m_header->findTypedAttribute<Imf::EnvmapAttribute>("envmap"); if (envmap) { m_cubeface = (envmap->value() == Imf::ENVMAP_CUBE); m_spec.attribute ("textureformat", m_cubeface ? "CubeFace Environment" : "LatLong Environment"); // OpenEXR conventions for env maps if (! m_cubeface) m_spec.attribute ("oiio:updirection", "y"); m_spec.attribute ("oiio:sampleborder", 1); // FIXME - detect CubeFace Shadow? } else { m_cubeface = false; if (tiled && m_levelmode == Imf::MIPMAP_LEVELS) m_spec.attribute ("textureformat", "Plain Texture"); // FIXME - detect Shadow } const Imf::CompressionAttribute *compressattr; compressattr = m_header->findTypedAttribute<Imf::CompressionAttribute>("compression"); if (compressattr) { const char *comp = NULL; switch (compressattr->value()) { case Imf::NO_COMPRESSION : comp = "none"; break; case Imf::RLE_COMPRESSION : comp = "rle"; break; case Imf::ZIPS_COMPRESSION : comp = "zip"; break; case Imf::ZIP_COMPRESSION : comp = "zip"; break; case Imf::PIZ_COMPRESSION : comp = "piz"; break; case Imf::PXR24_COMPRESSION : comp = "pxr24"; break; #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. case Imf::B44_COMPRESSION : comp = "b44"; break; case Imf::B44A_COMPRESSION : comp = "b44a"; break; #endif default: break; } if (comp) m_spec.attribute ("compression", comp); } for (Imf::Header::ConstIterator hit = m_header->begin(); hit != m_header->end(); ++hit) { const Imf::IntAttribute *iattr; const Imf::FloatAttribute *fattr; const Imf::StringAttribute *sattr; const Imf::M44fAttribute *mattr; const Imf::V3fAttribute *vattr; const char *name = hit.name(); std::string oname = exr_tag_to_ooio_std[name]; if (oname.empty()) // Empty string means skip this attrib continue; // if (oname == name) // oname = std::string(format_name()) + "_" + oname; const Imf::Attribute &attrib = hit.attribute(); std::string type = attrib.typeName(); if (type == "string" && (sattr = m_header->findTypedAttribute<Imf::StringAttribute> (name))) m_spec.attribute (oname, sattr->value().c_str()); else if (type == "int" && (iattr = m_header->findTypedAttribute<Imf::IntAttribute> (name))) m_spec.attribute (oname, iattr->value()); else if (type == "float" && (fattr = m_header->findTypedAttribute<Imf::FloatAttribute> (name))) m_spec.attribute (oname, fattr->value()); else if (type == "m44f" && (mattr = m_header->findTypedAttribute<Imf::M44fAttribute> (name))) m_spec.attribute (oname, TypeDesc::TypeMatrix, &(mattr->value())); else if (type == "v3f" && (vattr = m_header->findTypedAttribute<Imf::V3fAttribute> (name))) m_spec.attribute (oname, TypeDesc::TypeVector, &(vattr->value())); else { #if 0 std::cerr << " unknown attribute " << type << ' ' << name << "\n"; #endif } } m_subimage = 0; m_miplevel = 0; newspec = m_spec; return true; }