proper metadata support for the Bitmap class (mainly for OpenEXR I/O)

metadata
Wenzel Jakob 2013-01-25 21:12:04 -05:00
parent f6399ad08c
commit 4d75c69d4a
8 changed files with 240 additions and 106 deletions

View File

@ -774,25 +774,23 @@ public:
inline void setGamma(Float gamma) { m_gamma = gamma; } inline void setGamma(Float gamma) { m_gamma = gamma; }
/// Set a string-valued metadata field /// Set a string-valued metadata field
void setString(const std::string &key, const std::string &value); inline void setMetadataString(const std::string &key, const std::string &value) {
m_metadata.setString(key, value);
}
/// Return a string-valued metadata field /// Return a string-valued metadata field
std::string getString(const std::string &key) const; inline std::string getMetadataString(const std::string &key) const {
return m_metadata.getAsString(key);
/// Return a map of all present metadata
inline std::map<std::string, std::string> &getMetadata() {
return m_metadata;
} }
/// Return a map of all present metadata (const version) /// Return a \ref Properties object containing the image metadata
inline const std::map<std::string, std::string> &getMetadata() const { inline Properties &getMetadata() { return m_metadata; }
return m_metadata;
}
/// Set the metadata associated with the bitmap /// Return a \ref Properties object containing the image metadata (const version)
inline void setMetadata(const std::map<std::string, std::string> &metadata) { inline const Properties &getMetadata() const { return m_metadata; }
m_metadata = metadata;
} /// Set the a \ref Properties object containing the image metadata
inline void setMetadata(const Properties &metadata) { m_metadata = metadata; }
//! @} //! @}
// ====================================================================== // ======================================================================
@ -910,9 +908,9 @@ protected:
EComponentFormat m_componentFormat; EComponentFormat m_componentFormat;
Vector2i m_size; Vector2i m_size;
uint8_t *m_data; uint8_t *m_data;
std::map<std::string, std::string> m_metadata;
Float m_gamma; Float m_gamma;
int m_channelCount; int m_channelCount;
Properties m_metadata;
}; };
/** \brief Bitmap format conversion helper class /** \brief Bitmap format conversion helper class

View File

@ -71,6 +71,14 @@ public:
struct Data { struct Data {
uint8_t *ptr; uint8_t *ptr;
size_t size; size_t size;
inline bool operator==(const Data &d) const {
return ptr == d.ptr && size == d.size;
}
inline bool operator!=(const Data &d) const {
return !operator==(d);
}
}; };
/// Construct an empty property container /// Construct an empty property container
@ -172,6 +180,11 @@ public:
/// Get a string (with default) /// Get a string (with default)
std::string getString(const std::string &name, const std::string &defVal) const; std::string getString(const std::string &name, const std::string &defVal) const;
/// Return one of the parameters (converting it to a string if necessary)
std::string getAsString(const std::string &name) const;
/// Return one of the parameters (converting it to a string if necessary, with default value)
std::string getAsString(const std::string &name, const std::string &defVal) const;
/// Store an array containing the names of all stored properties /// Store an array containing the names of all stored properties
void putPropertyNames(std::vector<std::string> &results) const; void putPropertyNames(std::vector<std::string> &results) const;
@ -206,6 +219,14 @@ public:
/// Assignment operator /// Assignment operator
void operator=(const Properties &props); void operator=(const Properties &props);
/// Equality comparison operator
bool operator==(const Properties &props) const;
/// Inequality comparision operator
inline bool operator!=(const Properties &props) const {
return !operator==(props);
}
/// Return a string representation /// Return a string representation
std::string toString() const; std::string toString() const;
private: private:

View File

@ -393,6 +393,16 @@ public:
m_invTransform.serialize(stream); m_invTransform.serialize(stream);
} }
/// Equality comparison operator
inline bool operator==(const Transform &trafo) const {
return m_transform == trafo.m_transform;
}
/// Inequality comparison operator
inline bool operator!=(const Transform &trafo) const {
return m_transform != trafo.m_transform;
}
/// Return a string representation /// Return a string representation
std::string toString() const; std::string toString() const;
private: private:

View File

@ -383,7 +383,7 @@ public:
for (std::map<std::string, std::string>::const_iterator it = m_tags.begin(); for (std::map<std::string, std::string>::const_iterator it = m_tags.begin();
it != m_tags.end(); ++it) it != m_tags.end(); ++it)
bitmap->getMetadata()[it->first] = it->second; bitmap->setMetadataString(it->first, it->second);
fs::path filename = m_destFile; fs::path filename = m_destFile;
std::string extension = boost::to_lower_copy(filename.extension().string()); std::string extension = boost::to_lower_copy(filename.extension().string());
@ -400,7 +400,7 @@ public:
if (m_attachLog && logger->readLog(log)) { if (m_attachLog && logger->readLog(log)) {
log += "\n\n"; log += "\n\n";
log += Statistics::getInstance()->getStats(); log += Statistics::getInstance()->getStats();
bitmap->setString("log", log); bitmap->setMetadataString("log", log);
} }
bitmap->write(m_fileFormat, stream); bitmap->write(m_fileFormat, stream);

View File

@ -353,7 +353,7 @@ public:
for (std::map<std::string, std::string>::const_iterator it = m_tags.begin(); for (std::map<std::string, std::string>::const_iterator it = m_tags.begin();
it != m_tags.end(); ++it) it != m_tags.end(); ++it)
bitmap->getMetadata()[it->first] = it->second; bitmap->setMetadataString(it->first, it->second);
fs::path filename = m_destFile; fs::path filename = m_destFile;
std::string extension = boost::to_lower_copy(filename.extension().string()); std::string extension = boost::to_lower_copy(filename.extension().string());

View File

@ -38,6 +38,11 @@
#include <ImfOutputFile.h> #include <ImfOutputFile.h>
#include <ImfChannelList.h> #include <ImfChannelList.h>
#include <ImfStringAttribute.h> #include <ImfStringAttribute.h>
#include <ImfIntAttribute.h>
#include <ImfFloatAttribute.h>
#include <ImfDoubleAttribute.h>
#include <ImfVecAttribute.h>
#include <ImfMatrixAttribute.h>
#include <ImfVersion.h> #include <ImfVersion.h>
#include <ImfIO.h> #include <ImfIO.h>
#include <ImathBox.h> #include <ImathBox.h>
@ -386,19 +391,6 @@ int Bitmap::getBytesPerComponent() const {
} }
} }
void Bitmap::setString(const std::string &key, const std::string &value) {
m_metadata[key] = value;
}
std::string Bitmap::getString(const std::string &key) const {
std::map<std::string, std::string>::const_iterator it = m_metadata.find(key);
if (it != m_metadata.end())
return it->second;
else
return "";
}
Bitmap::~Bitmap() { Bitmap::~Bitmap() {
if (m_data) if (m_data)
freeAligned(m_data); freeAligned(m_data);
@ -1189,12 +1181,17 @@ std::string Bitmap::toString() const {
<< " type = " << m_pixelFormat << endl << " type = " << m_pixelFormat << endl
<< " componentFormat = " << m_componentFormat << endl << " componentFormat = " << m_componentFormat << endl
<< " size = " << m_size.toString() << endl; << " size = " << m_size.toString() << endl;
if (!m_metadata.empty()) {
std::vector<std::string> keys = m_metadata.getPropertyNames();
if (!keys.empty()) {
oss << " metadata = {" << endl; oss << " metadata = {" << endl;
for (std::map<std::string, std::string>::const_iterator it = m_metadata.begin(); for (std::vector<std::string>::const_iterator it = keys.begin(); it != keys.end(); ) {
it != m_metadata.end();) { std::string value = m_metadata.getAsString(*it);
oss << " \"" << it->first << "\" => \"" << it->second << "\""; if (value.size() > 50)
if (++it != m_metadata.end()) value = value.substr(0, 50) + ".. [truncated]";
oss << " \"" << *it << "\" => \"" << value << "\"";
if (++it != keys.end())
oss << ","; oss << ",";
oss << endl; oss << endl;
} }
@ -1281,7 +1278,7 @@ void Bitmap::readPNG(Stream *stream) {
png_get_text(png_ptr, info_ptr, &text_ptr, &textIdx); png_get_text(png_ptr, info_ptr, &text_ptr, &textIdx);
for (int i=0; i<textIdx; ++i, text_ptr++) for (int i=0; i<textIdx; ++i, text_ptr++)
m_metadata[text_ptr->key] = text_ptr->text; setMetadataString(text_ptr->key, text_ptr->text);
int intent; double gamma; int intent; double gamma;
if (png_get_sRGB(png_ptr, info_ptr, &intent)) { if (png_get_sRGB(png_ptr, info_ptr, &intent)) {
@ -1357,20 +1354,23 @@ void Bitmap::writePNG(Stream *stream, int compression) const {
png_text *text = NULL; png_text *text = NULL;
std::map<std::string, std::string> metadata = m_metadata; Properties metadata(m_metadata);
metadata["generated-by"] = "Mitsuba version " MTS_VERSION; metadata.setString("generated-by", "Mitsuba version " MTS_VERSION);
text = new png_text[metadata.size()]; std::vector<std::string> keys = metadata.getPropertyNames();
memset(text, 0, sizeof(png_text) * metadata.size()); std::vector<std::string> values(keys.size());
int textIndex = 0;
for (std::map<std::string, std::string>::iterator it = metadata.begin(); text = new png_text[keys.size()];
it != metadata.end(); ++it) { memset(text, 0, sizeof(png_text) * keys.size());
text[textIndex].key = const_cast<char *>(it->first.c_str());
text[textIndex].text = const_cast<char *>(it->second.c_str()); for (size_t i = 0; i<keys.size(); ++i) {
text[textIndex++].compression = PNG_TEXT_COMPRESSION_NONE; values[i] = metadata.getAsString(keys[i]);
text[i].key = const_cast<char *>(keys[i].c_str());
text[i].text = const_cast<char *>(values[i].c_str());
text[i].compression = PNG_TEXT_COMPRESSION_NONE;
} }
png_set_text(png_ptr, info_ptr, text, textIndex); png_set_text(png_ptr, info_ptr, text, keys.size());
if (m_gamma == -1) if (m_gamma == -1)
png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE); png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_ABSOLUTE);
@ -1665,11 +1665,37 @@ void Bitmap::readOpenEXR(Stream *stream, const std::string &_prefix) {
/* Load metadata if present */ /* Load metadata if present */
for (Imf::Header::ConstIterator it = header.begin(); it != header.end(); ++it) { for (Imf::Header::ConstIterator it = header.begin(); it != header.end(); ++it) {
std::string name = it.name(), typeName = it.attribute().typeName(); std::string name = it.name(), typeName = it.attribute().typeName();
const Imf::StringAttribute *sattr = NULL; const Imf::StringAttribute *sattr;
const Imf::IntAttribute *iattr;
const Imf::FloatAttribute *fattr;
const Imf::DoubleAttribute *dattr;
const Imf::V3fAttribute *vattr;
const Imf::M44fAttribute *mattr;
if (typeName == "string" && if (typeName == "string" &&
(sattr = header.findTypedAttribute<Imf::StringAttribute>(name.c_str()))) (sattr = header.findTypedAttribute<Imf::StringAttribute>(name.c_str())))
m_metadata[name] = sattr->value(); m_metadata.setString(name, sattr->value());
else if (typeName == "int" &&
(iattr = header.findTypedAttribute<Imf::IntAttribute>(name.c_str())))
m_metadata.setInteger(name, iattr->value());
else if (typeName == "float" &&
(fattr = header.findTypedAttribute<Imf::FloatAttribute>(name.c_str())))
m_metadata.setFloat(name, (Float) fattr->value());
else if (typeName == "double" &&
(dattr = header.findTypedAttribute<Imf::DoubleAttribute>(name.c_str())))
m_metadata.setFloat(name, (Float) dattr->value());
else if (typeName == "v3f" &&
(vattr = header.findTypedAttribute<Imf::V3fAttribute>(name.c_str()))) {
Imath::V3f vec = vattr->value();
m_metadata.setVector(name, Vector(vec.x, vec.y, vec.z));
} else if (typeName == "m44f" &&
(mattr = header.findTypedAttribute<Imf::M44fAttribute>(name.c_str()))) {
Matrix4x4 M;
for (int i=0; i<4; ++i)
for (int j=0; j<4; ++j)
M(i, j) = mattr->value().x[i][j];
m_metadata.setTransform(name, Transform(M));
}
} }
updateChannelCount(); updateChannelCount();
@ -1896,13 +1922,45 @@ void Bitmap::writeOpenEXR(Stream *stream,
pixelFormat = ERGBA; pixelFormat = ERGBA;
#endif #endif
std::map<std::string, std::string> metadata = m_metadata; Properties metadata(m_metadata);
metadata["generated-by"] = "Mitsuba version " MTS_VERSION; metadata.setString("generated-by", "Mitsuba version " MTS_VERSION);
std::vector<std::string> keys = metadata.getPropertyNames();
Imf::Header header(m_size.x, m_size.y); Imf::Header header(m_size.x, m_size.y);
for (std::map<std::string, std::string>::const_iterator it = metadata.begin(); for (std::vector<std::string>::const_iterator it = keys.begin(); it != keys.end(); ++it) {
it != metadata.end(); ++it) Properties::EPropertyType type = metadata.getType(*it);
header.insert(it->first.c_str(), Imf::StringAttribute(it->second.c_str()));
switch (type) {
case Properties::EString:
header.insert(it->c_str(), Imf::StringAttribute(metadata.getString(*it)));
break;
case Properties::EInteger:
header.insert(it->c_str(), Imf::IntAttribute(metadata.getInteger(*it)));
break;
case Properties::EFloat:
header.insert(it->c_str(), Imf::FloatAttribute((float) metadata.getFloat(*it)));
break;
case Properties::EPoint: {
Point val = metadata.getPoint(*it);
header.insert(it->c_str(), Imf::V3fAttribute(
Imath::V3f((float) val.x, (float) val.y, (float) val.z)));
}
break;
case Properties::ETransform: {
Matrix4x4 val = metadata.getTransform(*it).getMatrix();
header.insert(it->c_str(), Imf::M44fAttribute(Imath::M44f(
(float) val(0, 0), (float) val(0, 1), (float) val(0, 2), (float) val(0, 3),
(float) val(1, 0), (float) val(1, 1), (float) val(1, 2), (float) val(1, 3),
(float) val(2, 0), (float) val(2, 1), (float) val(2, 2), (float) val(2, 3),
(float) val(3, 0), (float) val(3, 1), (float) val(3, 2), (float) val(3, 3))));
}
break;
default:
header.insert(it->c_str(), Imf::StringAttribute(metadata.getAsString(*it)));
break;
}
}
if (pixelFormat == EXYZ || pixelFormat == EXYZA) { if (pixelFormat == EXYZ || pixelFormat == EXYZA) {
Imf::addChromaticities(header, Imf::Chromaticities( Imf::addChromaticities(header, Imf::Chromaticities(
@ -2363,14 +2421,16 @@ void Bitmap::writeRGBE(Stream *stream) const {
Log(EError, "writeRGBE(): pixel format must be ERGB or ERGBA!"); Log(EError, "writeRGBE(): pixel format must be ERGB or ERGBA!");
stream->writeLine("#?RGBE"); stream->writeLine("#?RGBE");
for (std::map<std::string, std::string>::const_iterator it = m_metadata.begin();
it != m_metadata.end(); ++it) { std::vector<std::string> keys = m_metadata.getPropertyNames();
stream->writeLine(formatString("# Metadata [%s]:", it->first.c_str())); for (std::vector<std::string>::const_iterator it = keys.begin(); it != keys.end(); ) {
std::istringstream iss(it->second); stream->writeLine(formatString("# Metadata [%s]:", it->c_str()));
std::istringstream iss(m_metadata.getAsString(*it));
std::string buf; std::string buf;
while (std::getline(iss, buf)) while (std::getline(iss, buf))
stream->writeLine(formatString("# %s", buf.c_str())); stream->writeLine(formatString("# %s", buf.c_str()));
} }
stream->writeLine("FORMAT=32-bit_rle_rgbe\n"); stream->writeLine("FORMAT=32-bit_rle_rgbe\n");
stream->writeLine(formatString("-Y %i +X %i", m_size.y, m_size.x)); stream->writeLine(formatString("-Y %i +X %i", m_size.y, m_size.x));

View File

@ -45,7 +45,7 @@ struct PropertyElement {
Type Properties::get##TypeName(const std::string &name) const { \ Type Properties::get##TypeName(const std::string &name) const { \
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name); \ std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name); \
if (it == m_elements->end()) \ if (it == m_elements->end()) \
SLog(EError, "Property \"%s\" missing", name.c_str()); \ SLog(EError, "Property \"%s\" has not been specified!", name.c_str()); \
const BaseType *result = boost::get<BaseType>(&it->second.data); \ const BaseType *result = boost::get<BaseType>(&it->second.data); \
if (!result) \ if (!result) \
SLog(EError, "The property \"%s\" has the wrong type (expected <" #ReadableName ">). The " \ SLog(EError, "The property \"%s\" has the wrong type (expected <" #ReadableName ">). The " \
@ -78,18 +78,55 @@ DEFINE_PROPERTY_ACCESSOR(Spectrum, Spectrum, Spectrum, spectrum)
DEFINE_PROPERTY_ACCESSOR(std::string, std::string, String, string) DEFINE_PROPERTY_ACCESSOR(std::string, std::string, String, string)
DEFINE_PROPERTY_ACCESSOR(Properties::Data, Properties::Data, Data, data) DEFINE_PROPERTY_ACCESSOR(Properties::Data, Properties::Data, Data, data)
class type_visitor : public boost::static_visitor<Properties::EPropertyType> { namespace {
public: class TypeVisitor : public boost::static_visitor<Properties::EPropertyType> {
Properties::EPropertyType operator()(const bool &) const { return Properties::EBoolean; } public:
Properties::EPropertyType operator()(const int64_t &) const { return Properties::EInteger; } Properties::EPropertyType operator()(const bool &) const { return Properties::EBoolean; }
Properties::EPropertyType operator()(const Float &) const { return Properties::EFloat; } Properties::EPropertyType operator()(const int64_t &) const { return Properties::EInteger; }
Properties::EPropertyType operator()(const Point &) const { return Properties::EPoint; } Properties::EPropertyType operator()(const Float &) const { return Properties::EFloat; }
Properties::EPropertyType operator()(const Vector &) const { return Properties::EVector; } Properties::EPropertyType operator()(const Point &) const { return Properties::EPoint; }
Properties::EPropertyType operator()(const Transform &) const { return Properties::ETransform; } Properties::EPropertyType operator()(const Vector &) const { return Properties::EVector; }
Properties::EPropertyType operator()(const Spectrum &) const { return Properties::ESpectrum; } Properties::EPropertyType operator()(const Transform &) const { return Properties::ETransform; }
Properties::EPropertyType operator()(const std::string &) const { return Properties::EString; } Properties::EPropertyType operator()(const Spectrum &) const { return Properties::ESpectrum; }
Properties::EPropertyType operator()(const Properties::Data &) const { return Properties::EData; } Properties::EPropertyType operator()(const std::string &) const { return Properties::EString; }
}; Properties::EPropertyType operator()(const Properties::Data &) const { return Properties::EData; }
};
class EqualityVisitor : public boost::static_visitor<bool> {
public:
EqualityVisitor(const ElementData *ref) : ref(ref) { }
bool operator()(const bool &v) const { const bool *v2 = boost::get<bool>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const int64_t &v) const { const int64_t *v2 = boost::get<int64_t>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const Float &v) const { const Float *v2 = boost::get<Float>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const Point &v) const { const Point *v2 = boost::get<Point>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const Vector &v) const { const Vector *v2 = boost::get<Vector>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const Transform &v) const { const Transform *v2 = boost::get<Transform>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const Spectrum &v) const { const Spectrum *v2 = boost::get<Spectrum>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const std::string &v) const { const std::string *v2 = boost::get<std::string>(ref); return v2 ? (v == *v2) : false; }
bool operator()(const Properties::Data &v) const { const Properties::Data *v2 = boost::get<Properties::Data>(ref); return v2 ? (v == *v2) : false; }
private:
const ElementData *ref;
};
class StringVisitor : public boost::static_visitor<void> {
public:
StringVisitor(std::ostringstream &oss, bool quote) : oss(oss), quote(quote) { }
void operator()(const bool &v) const { oss << (v ? "true" : "false"); }
void operator()(const int64_t &v) const { oss << v; }
void operator()(const Float &v) const { oss << v; }
void operator()(const Point &v) const { oss << v.toString(); }
void operator()(const Vector &v) const { oss << v.toString(); }
void operator()(const Transform &v) const { oss << v.toString(); }
void operator()(const Spectrum &v) const { oss << v.toString(); }
void operator()(const std::string &v) const { oss << (quote ? "\"" : "") << v << (quote ? "\"" : ""); }
void operator()(const Properties::Data &v) const { oss << v.ptr << " (size=" << v.size << ")"; }
private:
std::ostringstream &oss;
bool quote;
};
}
Properties::Properties() Properties::Properties()
: m_id("unnamed") { : m_id("unnamed") {
@ -145,13 +182,32 @@ Properties::EPropertyType Properties::getType(const std::string &name) const {
if (it == m_elements->end()) if (it == m_elements->end())
SLog(EError, "Property \"%s\" has not been specified!", name.c_str()); SLog(EError, "Property \"%s\" has not been specified!", name.c_str());
type_visitor myVisitor; return boost::apply_visitor(TypeVisitor(), it->second.data);
return boost::apply_visitor(myVisitor, it->second.data); }
std::string Properties::getAsString(const std::string &name, const std::string &defVal) const {
if (m_elements->find(name) == m_elements->end())
return defVal;
return getAsString(name);
}
std::string Properties::getAsString(const std::string &name) const {
std::map<std::string, PropertyElement>::const_iterator it = m_elements->find(name);
if (it == m_elements->end())
SLog(EError, "Property \"%s\" has not been specified!", name.c_str());
std::ostringstream oss;
StringVisitor strVisitor(oss, false);
boost::apply_visitor(strVisitor, it->second.data);
it->second.queried = true;
return oss.str();
} }
std::string Properties::toString() const { std::string Properties::toString() const {
std::map<std::string, PropertyElement>::const_iterator it = m_elements->begin(); std::map<std::string, PropertyElement>::const_iterator it = m_elements->begin();
std::ostringstream oss; std::ostringstream oss;
StringVisitor strVisitor(oss, true);
oss << "Properties[" << endl oss << "Properties[" << endl
<< " pluginName = \"" << m_pluginName << "\"," << endl << " pluginName = \"" << m_pluginName << "\"," << endl
@ -160,36 +216,7 @@ std::string Properties::toString() const {
while (it != m_elements->end()) { while (it != m_elements->end()) {
oss << " \"" << (*it).first << "\" -> "; oss << " \"" << (*it).first << "\" -> ";
const ElementData &data = (*it).second.data; const ElementData &data = (*it).second.data;
EPropertyType type = boost::apply_visitor(type_visitor(), data); boost::apply_visitor(strVisitor, data);
switch (type) {
case EBoolean:
oss << (boost::get<bool>(data) ? "true" : "false");
break;
case EInteger:
oss << boost::get<int64_t>(data);
break;
case EFloat:
oss << boost::get<Float>(data);
break;
case EPoint:
oss << boost::get<Point>(data).toString();
break;
case ETransform:
oss << indent(boost::get<Transform>(data).toString());
break;
case ESpectrum:
oss << boost::get<Spectrum>(data).toString();
break;
case EString:
oss << "\"" << boost::get<std::string>(data) << "\"";
break;
case EData:
oss << boost::get<Data>(data).ptr << " (size="
<< boost::get<Data>(data).size << ")";
break;
default:
oss << "<unknown>";
}
if (++it != m_elements->end()) if (++it != m_elements->end())
oss << ","; oss << ",";
oss << endl; oss << endl;
@ -219,6 +246,21 @@ void Properties::putPropertyNames(std::vector<std::string> &results) const {
results.push_back((*it).first); results.push_back((*it).first);
} }
bool Properties::operator==(const Properties &p) const {
if (m_pluginName != p.m_pluginName || m_id != p.m_id || m_elements->size() != p.m_elements->size())
return false;
std::map<std::string, PropertyElement>::const_iterator it = m_elements->begin();
for (; it != m_elements->end(); ++it) {
const PropertyElement &first = it->second;
const PropertyElement &second = (*p.m_elements)[it->first];
if (!boost::apply_visitor(EqualityVisitor(&first.data), second.data))
return false;
}
return true;
}
ConfigurableObject::ConfigurableObject(Stream *stream, InstanceManager *manager) ConfigurableObject::ConfigurableObject(Stream *stream, InstanceManager *manager)
: SerializableObject(stream, manager) { : SerializableObject(stream, manager) {

View File

@ -754,6 +754,7 @@ void export_core() {
void (Bitmap::*accumulate_1)(const Bitmap *bitmap, Point2i sourceOffset, Point2i targetOffset, Vector2i size) = &Bitmap::accumulate; void (Bitmap::*accumulate_1)(const Bitmap *bitmap, Point2i sourceOffset, Point2i targetOffset, Vector2i size) = &Bitmap::accumulate;
void (Bitmap::*accumulate_2)(const Bitmap *bitmap, Point2i targetOffset) = &Bitmap::accumulate; void (Bitmap::*accumulate_2)(const Bitmap *bitmap, Point2i targetOffset) = &Bitmap::accumulate;
const Properties &(Bitmap::*get_metadata)() const = &Bitmap::getMetadata;
BP_CLASS(Bitmap, Object, (bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &>())) BP_CLASS(Bitmap, Object, (bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &>()))
.def(bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &, int>()) .def(bp::init<Bitmap::EPixelFormat, Bitmap::EComponentFormat, const Vector2i &, int>())
@ -769,8 +770,10 @@ void export_core() {
.def("accumulate", accumulate_1) .def("accumulate", accumulate_1)
.def("accumulate", accumulate_2) .def("accumulate", accumulate_2)
.def("write", &bitmap_write) .def("write", &bitmap_write)
.def("setString", &Bitmap::setString) .def("setMetadataString", &Bitmap::setMetadataString)
.def("getString", &Bitmap::getString, BP_RETURN_VALUE) .def("getMetadataString", &Bitmap::getMetadataString, BP_RETURN_VALUE)
.def("setMetadata", &Bitmap::setMetadata)
.def("getMetadata", get_metadata, BP_RETURN_VALUE)
.def("setGamma", &Bitmap::setGamma) .def("setGamma", &Bitmap::setGamma)
.def("getGamma", &Bitmap::getGamma) .def("getGamma", &Bitmap::getGamma)
.def("getWidth", &Bitmap::getWidth) .def("getWidth", &Bitmap::getWidth)