/// Given data types a and b, return a type that is a best guess for one /// that can handle both without any loss of range or precision. TypeDesc::BASETYPE ImageBufAlgo::type_merge (TypeDesc::BASETYPE a, TypeDesc::BASETYPE b) { // Same type already? done. if (a == b) return a; if (a == TypeDesc::UNKNOWN) return b; if (b == TypeDesc::UNKNOWN) return a; // Canonicalize so a's size (in bytes) is >= b's size in bytes. This // unclutters remaining cases. if (TypeDesc(a).size() < TypeDesc(b).size()) std::swap (a, b); // Double or float trump anything else if (a == TypeDesc::DOUBLE || a == TypeDesc::FLOAT) return a; if (a == TypeDesc::UINT32 && (b == TypeDesc::UINT16 || b == TypeDesc::UINT8)) return a; if (a == TypeDesc::INT32 && (b == TypeDesc::INT16 || b == TypeDesc::UINT16 || b == TypeDesc::INT8 || b == TypeDesc::UINT8)) return a; if ((a == TypeDesc::UINT16 || a == TypeDesc::HALF) && b == TypeDesc::UINT8) return a; if ((a == TypeDesc::INT16 || a == TypeDesc::HALF) && (b == TypeDesc::INT8 || b == TypeDesc::UINT8)) return a; // Out of common cases. For all remaining edge cases, punt and say that // we prefer float. return TypeDesc::FLOAT; }
TypeSpec OSLCompilerImpl::type_from_code (const char *code, int *advance) { TypeSpec t; int i = 0; switch (code[i]) { case 'i' : t = TypeDesc::TypeInt; break; case 'f' : t = TypeDesc::TypeFloat; break; case 'c' : t = TypeDesc::TypeColor; break; case 'p' : t = TypeDesc::TypePoint; break; case 'v' : t = TypeDesc::TypeVector; break; case 'n' : t = TypeDesc::TypeNormal; break; case 'm' : t = TypeDesc::TypeMatrix; break; case 's' : t = TypeDesc::TypeString; break; case 'x' : t = TypeDesc (TypeDesc::NONE); break; case 'X' : t = TypeDesc (TypeDesc::PTR); break; case 'L' : t = TypeDesc (TypeDesc::LONGLONG); break; case 'C' : // color closure t = TypeSpec (TypeDesc::TypeColor, true); break; case 'S' : // structure // Following the 'S' is the numeric structure ID t = TypeSpec ("struct", atoi (code+i+1)); // Skip to the last digit while (isdigit(code[i+1])) ++i; break; case '?' : break; // anything will match, so keep 'UNKNOWN' case '*' : break; // anything will match, so keep 'UNKNOWN' case '.' : break; // anything will match, so keep 'UNKNOWN' default: std::cerr << "Don't know how to decode type code '" << code << "' " << (int)code[0] << "\n"; ASSERT (0); // FIXME if (advance) *advance = 1; return TypeSpec(); } ++i; if (code[i] == '[') { ++i; t.make_array (-1); // signal arrayness, unknown length if (isdigit(code[i]) || code[i] == ']') { if (isdigit(code[i])) t.make_array (atoi (code+i)); while (isdigit(code[i])) ++i; if (code[i] == ']') ++i; } } if (advance) *advance = i; return t; }
void benchmark_convert_type () { const size_t size = 10000000; const S testval(1.0); std::vector<S> svec (size, testval); std::vector<D> dvec (size); std::cout << Strutil::format("Benchmark conversion of %6s -> %6s : ", TypeDesc(BaseTypeFromC<S>::value), TypeDesc(BaseTypeFromC<D>::value)); float time = time_trial (bind (do_convert_type<S,D>, OIIO::cref(svec), OIIO::ref(dvec)), ntrials, iterations) / iterations; std::cout << Strutil::format ("%7.1f Mvals/sec", (size/1.0e6)/time) << std::endl; D r = convert_type<S,D>(testval); OIIO_CHECK_EQUAL (dvec[size-1], r); }
bool JpgInput::read_icc_profile(j_decompress_ptr cinfo, ImageSpec& spec) { int num_markers = 0; std::vector<unsigned char> icc_buf; unsigned int total_length = 0; const int MAX_SEQ_NO = 255; unsigned char marker_present [MAX_SEQ_NO + 1]; // one extra is used to store the flag if marker is found, set to one if marker is found unsigned int data_length[MAX_SEQ_NO + 1]; // store the size of each marker unsigned int data_offset[MAX_SEQ_NO + 1]; // store the offset of each marker memset(marker_present, 0, (MAX_SEQ_NO + 1)); for (jpeg_saved_marker_ptr m = cinfo->marker_list; m; m = m->next) { if (m->marker == (JPEG_APP0 + 2) && !strcmp((const char*)m->data, "ICC_PROFILE")) { if (num_markers == 0) num_markers = GETJOCTET(m->data[13]); else if (num_markers != GETJOCTET(m->data[13])) return false; int seq_no = GETJOCTET(m->data[12]); if (seq_no <= 0 || seq_no > num_markers) return false; if (marker_present[seq_no]) // duplicate marker return false; marker_present[seq_no] = 1; // flag found marker data_length[seq_no] = m->data_length - ICC_HEADER_SIZE; } } if (num_markers == 0) return false; // checking for missing markers for (int seq_no = 1; seq_no <= num_markers; seq_no++) { if (marker_present[seq_no] == 0) return false; // missing sequence number data_offset[seq_no] = total_length; total_length += data_length[seq_no]; } if (total_length == 0) return false; // found only empty markers icc_buf.resize(total_length * sizeof(JOCTET)); // and fill it in for (jpeg_saved_marker_ptr m = cinfo->marker_list; m; m = m->next) { if (m->marker == (JPEG_APP0 + 2) && !strcmp((const char*)m->data, "ICC_PROFILE")) { int seq_no = GETJOCTET(m->data[12]); memcpy(&icc_buf[0] + data_offset[seq_no], m->data + ICC_HEADER_SIZE, data_length[seq_no]); } } spec.attribute(ICC_PROFILE_ATTR, TypeDesc(TypeDesc::UINT8, total_length), &icc_buf[0]); return true; }
static void test_gettextureinfo (ustring filename) { bool ok; int res[2] = {0}; ok = texsys->get_texture_info (filename, 0, ustring("resolution"), TypeDesc(TypeDesc::INT,2), res); std::cerr << "Result of get_texture_info resolution = " << ok << ' ' << res[0] << 'x' << res[1] << "\n"; int chan = 0; ok = texsys->get_texture_info (filename, 0, ustring("channels"), TypeDesc::INT, &chan); std::cerr << "Result of get_texture_info channels = " << ok << ' ' << chan << "\n"; float fchan = 0; ok = texsys->get_texture_info (filename, 0, ustring("channels"), TypeDesc::FLOAT, &fchan); std::cerr << "Result of get_texture_info channels = " << ok << ' ' << fchan << "\n"; int dataformat = 0; ok = texsys->get_texture_info (filename, 0, ustring("format"), TypeDesc::INT, &dataformat); std::cerr << "Result of get_texture_info data format = " << ok << ' ' << TypeDesc((TypeDesc::BASETYPE)dataformat).c_str() << "\n"; const char *datetime = NULL; ok = texsys->get_texture_info (filename, 0, ustring("DateTime"), TypeDesc::STRING, &datetime); std::cerr << "Result of get_texture_info datetime = " << ok << ' ' << (datetime ? datetime : "") << "\n"; const char *texturetype = NULL; ok = texsys->get_texture_info (filename, 0, ustring("textureformat"), TypeDesc::STRING, &texturetype); std::cerr << "Texture type is " << ok << ' ' << (texturetype ? texturetype : "") << "\n"; std::cerr << "\n"; }
void ImageBuf::set_full (int xbegin, int xend, int ybegin, int yend, int zbegin, int zend, const float *bordercolor) { m_spec.full_x = xbegin; m_spec.full_y = ybegin; m_spec.full_z = zbegin; m_spec.full_width = xend - xbegin; m_spec.full_height = yend - ybegin; m_spec.full_depth = zend - zbegin; if (bordercolor) m_spec.attribute ("oiio:bordercolor", TypeDesc(TypeDesc::FLOAT,m_spec.nchannels), bordercolor); }
TypeSpec ASTconditional_statement::typecheck (TypeSpec expected) { typecheck_list (cond ()); oslcompiler->push_nesting (false); typecheck_list (truestmt ()); typecheck_list (falsestmt ()); oslcompiler->pop_nesting (false); TypeSpec c = cond()->typespec(); if (c.is_closure()) error ("Cannot use a closure as an 'if' condition"); if (c.is_structure()) error ("Cannot use a struct as an 'if' condition"); if (c.is_array()) error ("Cannot use an array as an 'if' condition"); return m_typespec = TypeDesc (TypeDesc::NONE); }
TypeSpec ASTloop_statement::typecheck (TypeSpec expected) { typecheck_list (init ()); oslcompiler->push_nesting (true); typecheck_list (cond ()); typecheck_list (iter ()); typecheck_list (stmt ()); oslcompiler->pop_nesting (true); TypeSpec c = cond()->typespec(); if (c.is_closure()) error ("Cannot use a closure as an '%s' condition", opname()); if (c.is_structure()) error ("Cannot use a struct as an '%s' condition", opname()); if (c.is_array()) error ("Cannot use an array as an '%s' condition", opname()); return m_typespec = TypeDesc (TypeDesc::NONE); }
void OpenEXRInput::PartInfo::query_channels (const Imf::Header *header) { ASSERT (! initialized); spec.nchannels = 0; const Imf::ChannelList &channels (header->channels()); std::vector<std::string> channelnames; // Order of channels in file std::vector<ChanNameHolder> cnh; int c = 0; for (Imf::ChannelList::ConstIterator ci = channels.begin(); ci != channels.end(); ++c, ++ci) { cnh.emplace_back (ci.name(), c, ci.channel().type); ++spec.nchannels; } std::sort (cnh.begin(), cnh.end(), ChanNameHolder::compare_cnh); // Now we should have cnh sorted into the order that we want to present // to the OIIO client. spec.format = TypeDesc::UNKNOWN; bool all_one_format = true; for (int c = 0; c < spec.nchannels; ++c) { spec.channelnames.push_back (cnh[c].fullname); spec.channelformats.push_back (cnh[c].datatype); spec.format = TypeDesc(ImageBufAlgo::type_merge (TypeDesc::BASETYPE(spec.format.basetype), TypeDesc::BASETYPE(cnh[c].datatype.basetype))); pixeltype.push_back (cnh[c].exr_data_type); chanbytes.push_back (cnh[c].datatype.size()); all_one_format &= (cnh[c].datatype == cnh[0].datatype); if (spec.alpha_channel < 0 && (Strutil::iequals (cnh[c].suffix, "A") || Strutil::iequals (cnh[c].suffix, "Alpha"))) spec.alpha_channel = c; if (spec.z_channel < 0 && (Strutil::iequals (cnh[c].suffix, "Z") || Strutil::iequals (cnh[c].suffix, "Depth"))) spec.z_channel = c; } ASSERT ((int)spec.channelnames.size() == spec.nchannels); ASSERT (spec.format != TypeDesc::UNKNOWN); if (all_one_format) spec.channelformats.clear(); }
static void print_component (std::ostream &out, const ClosureComponent *comp, ShadingSystemImpl *ss, const Color3 &weight) { out << "(" << weight[0]*comp->w[0] << ", " << weight[1]*comp->w[1] << ", " << weight[2]*comp->w[2] << ") * "; const ClosureRegistry::ClosureEntry *clentry = ss->find_closure(comp->id); ASSERT(clentry); out << clentry->name.c_str() << " ("; int i; for (i = 0; i < clentry->nformal; ++i) { if (i) out << ", "; if (clentry->params[i].type.numelements() > 1) out << "["; for (size_t j = 0; j < clentry->params[i].type.numelements(); ++j) { if (j) out << ", "; print_component_value(out, ss, clentry->params[i].type.elementtype(), (const char *)comp->data() + clentry->params[i].offset + clentry->params[i].type.elementsize() * j); } if (clentry->params[i].type.numelements() > 1) out << "]"; } if (comp->nattrs) { const ClosureComponent::Attr * attrs = comp->attrs(); for (int j = 0; j < comp->nattrs; ++j) { if (i || j) out << ", "; // find the type TypeDesc td; for (int p = 0; p < clentry->nkeyword; ++p) if (!strcmp(clentry->params[clentry->nformal + p].key, attrs[j].key.c_str())) td = clentry->params[clentry->nformal + p].type; if (td != TypeDesc()) { out << "\"" << attrs[j].key.c_str() << "\", "; print_component_value(out, ss, td, &attrs[j].value); } } } out << ")"; }
bool NullInput::open(const std::string& name, ImageSpec& newspec, const ImageSpec& config) { m_filename = name; m_subimage = -1; m_miplevel = -1; m_mip = false; m_topspec = config; // std::vector<std::pair<string_view,string_view> > args; // string_view filename = deconstruct_uri (name, &args); std::map<std::string, std::string> args; std::string filename; if (!Strutil::get_rest_arguments(name, filename, args)) return false; if (filename.empty()) return false; // To keep the "null" input reader from reading from ANY name, only // succeed if it ends in ".null" or ".nul" --OR-- if the config has a // special override "null:force" set to nonzero (that lets the caller // guarantee a null input even if the name has no extension, say). if (!Strutil::ends_with(filename, ".null") && !Strutil::ends_with(filename, ".nul") && config.get_int_attribute("null:force") == 0) return false; // Override the config with default resolution if it was not set if (m_topspec.width <= 0) m_topspec.width = 1024; if (m_topspec.height <= 0) m_topspec.height = 1024; if (m_topspec.depth <= 0) m_topspec.depth = 1; if (m_topspec.full_width <= 0) m_topspec.full_width = m_topspec.width; if (m_topspec.full_height <= 0) m_topspec.full_height = m_topspec.height; if (m_topspec.full_depth <= 0) m_topspec.full_depth = m_topspec.depth; if (m_topspec.nchannels <= 0) m_topspec.nchannels = 4; if (m_topspec.format == TypeUnknown) m_topspec.format = TypeFloat; m_filename = filename; std::vector<float> fvalue; for (const auto& a : args) { if (a.first == "RES") { parse_res(a.second, m_topspec.width, m_topspec.height, m_topspec.depth); m_topspec.full_x = m_topspec.x; m_topspec.full_y = m_topspec.y; m_topspec.full_z = m_topspec.z; m_topspec.full_width = m_topspec.width; m_topspec.full_height = m_topspec.height; m_topspec.full_depth = m_topspec.depth; } else if (a.first == "TILE" || a.first == "TILES") { parse_res(a.second, m_topspec.tile_width, m_topspec.tile_height, m_topspec.tile_depth); } else if (a.first == "CHANNELS") { m_topspec.nchannels = Strutil::from_string<int>(a.second); m_topspec.default_channel_names(); } else if (a.first == "MIP") { m_mip = Strutil::from_string<int>(a.second); } else if (a.first == "TEX") { if (Strutil::from_string<int>(a.second)) { if (!m_spec.tile_width) { m_topspec.tile_width = 64; m_topspec.tile_height = 64; m_topspec.tile_depth = 1; } m_topspec.attribute("wrapmodes", "black,black"); m_topspec.attribute("textureformat", "Plain Texture"); m_mip = true; } } else if (a.first == "TYPE") { m_topspec.set_format(TypeDesc(a.second)); } else if (a.first == "PIXEL") { Strutil::extract_from_list_string(fvalue, a.second); fvalue.resize(m_topspec.nchannels); } else if (a.first.size() && a.second.size()) { parse_param(a.first, a.second, m_topspec); } } if (fvalue.size()) { // Convert float to the native type fvalue.resize(m_topspec.nchannels, 0.0f); m_value.resize(m_topspec.pixel_bytes()); convert_types(TypeFloat, fvalue.data(), m_topspec.format, m_value.data(), m_topspec.nchannels); } bool ok = seek_subimage(0, 0); newspec = spec(); return ok; }
bool DPXInput::seek_subimage (int subimage, int miplevel, ImageSpec &newspec) { if (miplevel != 0) return false; if (subimage < 0 || subimage >= m_dpx.header.ImageElementCount ()) return false; m_subimage = subimage; // check if the client asked us for raw data m_wantRaw = newspec.get_int_attribute ("dpx:RawData", 0) != 0; // create imagespec TypeDesc typedesc; switch (m_dpx.header.ComponentDataSize(subimage)) { case dpx::kByte: typedesc = m_dpx.header.DataSign (subimage) ? TypeDesc::INT8 : TypeDesc::UINT8; break; case dpx::kWord: typedesc = m_dpx.header.DataSign (subimage) ? TypeDesc::INT16 : TypeDesc::UINT16; break; case dpx::kInt: typedesc = m_dpx.header.DataSign (subimage) ? TypeDesc::INT32 : TypeDesc::UINT32; break; case dpx::kFloat: typedesc = TypeDesc::FLOAT; break; case dpx::kDouble: typedesc = TypeDesc::DOUBLE; break; default: error ("Invalid component data size"); return false; } m_spec = ImageSpec (m_dpx.header.Width(), m_dpx.header.Height(), m_dpx.header.ImageElementComponentCount(subimage), typedesc); // fill channel names m_spec.channelnames.clear (); switch (m_dpx.header.ImageDescriptor(subimage)) { /*case dpx::kUserDefinedDescriptor: break;*/ case dpx::kRed: m_spec.channelnames.push_back("R"); break; case dpx::kGreen: m_spec.channelnames.push_back("G"); break; case dpx::kBlue: m_spec.channelnames.push_back("B"); break; case dpx::kAlpha: m_spec.channelnames.push_back("A"); m_spec.alpha_channel = 0; break; case dpx::kLuma: // FIXME: do we treat this as intensity or do we use Y' as per // convention to differentiate it from linear luminance? m_spec.channelnames.push_back("Y'"); break; case dpx::kDepth: m_spec.channelnames.push_back("Z"); m_spec.z_channel = 0; break; /*case dpx::kCompositeVideo: break;*/ case dpx::kRGB: case dpx::kRGBA: case dpx::kABGR: // colour converter will swap the bytes for us m_spec.default_channel_names (); break; case dpx::kCbYCrY: if (m_wantRaw) { m_spec.channelnames.push_back("CbCr"); m_spec.channelnames.push_back("Y"); } else { m_spec.nchannels = 3; m_spec.default_channel_names (); } break; case dpx::kCbYACrYA: if (m_wantRaw) { m_spec.channelnames.push_back("CbCr"); m_spec.channelnames.push_back("Y"); m_spec.channelnames.push_back("A"); m_spec.alpha_channel = 2; } else { m_spec.nchannels = 4; m_spec.default_channel_names (); } break; case dpx::kCbYCr: if (m_wantRaw) { m_spec.channelnames.push_back("Cb"); m_spec.channelnames.push_back("Y"); m_spec.channelnames.push_back("Cr"); } else m_spec.default_channel_names (); break; case dpx::kCbYCrA: if (m_wantRaw) { m_spec.channelnames.push_back("Cb"); m_spec.channelnames.push_back("Y"); m_spec.channelnames.push_back("Cr"); m_spec.channelnames.push_back("A"); m_spec.alpha_channel = 3; } else { m_spec.default_channel_names (); } break; default: { for (int i = 0; i < m_dpx.header.ImageElementComponentCount(subimage); i++) { std::string ch = "channel" + i; m_spec.channelnames.push_back(ch); } } } // bits per pixel m_spec.attribute ("oiio:BitsPerSample", m_dpx.header.BitDepth(subimage)); // image orientation - see appendix B.2 of the OIIO documentation int orientation; switch (m_dpx.header.ImageOrientation ()) { case dpx::kLeftToRightTopToBottom: orientation = 1; break; case dpx::kRightToLeftTopToBottom: orientation = 2; break; case dpx::kLeftToRightBottomToTop: orientation = 4; break; case dpx::kRightToLeftBottomToTop: orientation = 3; break; case dpx::kTopToBottomLeftToRight: orientation = 5; break; case dpx::kTopToBottomRightToLeft: orientation = 6; break; case dpx::kBottomToTopLeftToRight: orientation = 8; break; case dpx::kBottomToTopRightToLeft: orientation = 7; break; default: orientation = 0; break; } m_spec.attribute ("Orientation", orientation); // image linearity switch (m_dpx.header.Transfer (subimage)) { case dpx::kLinear: m_spec.attribute ("oiio:ColorSpace", "Linear"); break; case dpx::kLogarithmic: m_spec.attribute ("oiio:ColorSpace", "KodakLog"); break; case dpx::kITUR709: m_spec.attribute ("oiio:ColorSpace", "Rec709"); break; case dpx::kUserDefined: if (! isnan (m_dpx.header.Gamma ()) && m_dpx.header.Gamma () != 0) { m_spec.attribute ("oiio:ColorSpace", "GammaCorrected"); m_spec.attribute ("oiio:Gamma", (float) m_dpx.header.Gamma ()); break; } // intentional fall-through /*case dpx::kPrintingDensity: case dpx::kUnspecifiedVideo: case dpx::kSMPTE274M: case dpx::kITUR601: case dpx::kITUR602: case dpx::kNTSCCompositeVideo: case dpx::kPALCompositeVideo: case dpx::kZLinear: case dpx::kZHomogeneous: case dpx::kUndefinedCharacteristic:*/ default: break; } m_spec.attribute ("dpx:Transfer", get_characteristic_string (m_dpx.header.Transfer (subimage))); // colorimetric characteristic m_spec.attribute ("dpx:Colorimetric", get_characteristic_string (m_dpx.header.Colorimetric (subimage))); // general metadata // some non-compliant writers will dump a field filled with 0xFF rather // than a NULL string termination on the first character, so take that // into account, too if (m_dpx.header.copyright[0] && m_dpx.header.copyright[0] != (char)0xFF) m_spec.attribute ("Copyright", m_dpx.header.copyright); if (m_dpx.header.creator[0] && m_dpx.header.creator[0] != (char)0xFF) m_spec.attribute ("Software", m_dpx.header.creator); if (m_dpx.header.project[0] && m_dpx.header.project[0] != (char)0xFF) m_spec.attribute ("DocumentName", m_dpx.header.project); if (m_dpx.header.creationTimeDate[0]) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) char date[24]; strcpy(date, m_dpx.header.creationTimeDate); date[10] = ' '; date[19] = 0; m_spec.attribute ("DateTime", date); } if (m_dpx.header.ImageEncoding (subimage) == dpx::kRLE) m_spec.attribute ("compression", "rle"); char buf[32 + 1]; m_dpx.header.Description (subimage, buf); if (buf[0] && buf[0] != -1) m_spec.attribute ("ImageDescription", buf); m_spec.attribute ("PixelAspectRatio", m_dpx.header.AspectRatio(0) / (float)m_dpx.header.AspectRatio(1)); // DPX-specific metadata m_spec.attribute ("dpx:ImageDescriptor", get_descriptor_string (m_dpx.header.ImageDescriptor (subimage))); // save some typing by using macros // "internal" macros #define DPX_SET_ATTRIB_S(x, n, s) m_spec.attribute (s, \ m_dpx.header.x (n)) #define DPX_SET_ATTRIB(x, n) DPX_SET_ATTRIB_S(x, n, "dpx:" #x) // set without checking for bogus attributes #define DPX_SET_ATTRIB_N(x) DPX_SET_ATTRIB(x, subimage) // set with checking for bogus attributes #define DPX_SET_ATTRIB_BYTE(x) if (m_dpx.header.x () != 0xFF) \ DPX_SET_ATTRIB(x, ) #define DPX_SET_ATTRIB_INT_N(x) if (m_dpx.header.x (subimage) != 0xFFFFFFFF) \ DPX_SET_ATTRIB(x, subimage) #define DPX_SET_ATTRIB_INT(x) if (m_dpx.header.x () != 0xFFFFFFFF) \ DPX_SET_ATTRIB(x, ) #define DPX_SET_ATTRIB_FLOAT_N(x) if (! isnan(m_dpx.header.x (subimage))) \ DPX_SET_ATTRIB(x, subimage) #define DPX_SET_ATTRIB_FLOAT(x) if (! isnan(m_dpx.header.x ())) \ DPX_SET_ATTRIB(x, ) // see comment above Copyright, Software and DocumentName #define DPX_SET_ATTRIB_STR(X, x) if (m_dpx.header.x[0] \ && m_dpx.header.x[0] != -1) \ m_spec.attribute ("dpx:" #X, \ m_dpx.header.x) DPX_SET_ATTRIB_INT(EncryptKey); DPX_SET_ATTRIB_INT(DittoKey); DPX_SET_ATTRIB_INT_N(LowData); DPX_SET_ATTRIB_FLOAT_N(LowQuantity); DPX_SET_ATTRIB_INT_N(HighData); DPX_SET_ATTRIB_FLOAT_N(HighQuantity); DPX_SET_ATTRIB_FLOAT(XScannedSize); DPX_SET_ATTRIB_FLOAT(YScannedSize); DPX_SET_ATTRIB_INT(FramePosition); DPX_SET_ATTRIB_INT(SequenceLength); DPX_SET_ATTRIB_INT(HeldCount); DPX_SET_ATTRIB_FLOAT(FrameRate); DPX_SET_ATTRIB_FLOAT(ShutterAngle); DPX_SET_ATTRIB_STR(Version, version); DPX_SET_ATTRIB_STR(Format, format); DPX_SET_ATTRIB_STR(FrameId, frameId); DPX_SET_ATTRIB_STR(SlateInfo, slateInfo); DPX_SET_ATTRIB_STR(SourceImageFileName, sourceImageFileName); DPX_SET_ATTRIB_STR(InputDevice, inputDevice); DPX_SET_ATTRIB_STR(InputDeviceSerialNumber, inputDeviceSerialNumber); DPX_SET_ATTRIB_BYTE(Interlace); DPX_SET_ATTRIB_BYTE(FieldNumber); DPX_SET_ATTRIB_FLOAT(HorizontalSampleRate); DPX_SET_ATTRIB_FLOAT(VerticalSampleRate); DPX_SET_ATTRIB_FLOAT(TemporalFrameRate); DPX_SET_ATTRIB_FLOAT(TimeOffset); DPX_SET_ATTRIB_FLOAT(BlackLevel); DPX_SET_ATTRIB_FLOAT(BlackGain); DPX_SET_ATTRIB_FLOAT(BreakPoint); DPX_SET_ATTRIB_FLOAT(WhiteLevel); DPX_SET_ATTRIB_FLOAT(IntegrationTimes); #undef DPX_SET_ATTRIB_STR #undef DPX_SET_ATTRIB_FLOAT #undef DPX_SET_ATTRIB_FLOAT_N #undef DPX_SET_ATTRIB_INT #undef DPX_SET_ATTRIB_INT_N #undef DPX_SET_ATTRIB_N #undef DPX_SET_ATTRIB #undef DPX_SET_ATTRIB_S std::string tmpstr; switch (m_dpx.header.ImagePacking (subimage)) { case dpx::kPacked: tmpstr = "Packed"; break; case dpx::kFilledMethodA: tmpstr = "Filled, method A"; break; case dpx::kFilledMethodB: tmpstr = "Filled, method B"; break; } if (!tmpstr.empty ()) m_spec.attribute ("dpx:Packing", tmpstr); if (m_dpx.header.timeCode != 0xFFFFFFFF) m_spec.attribute ("dpx:TimeCode", m_dpx.header.timeCode); if (m_dpx.header.userBits != 0xFFFFFFFF) m_spec.attribute ("dpx:UserBits", m_dpx.header.userBits); if (m_dpx.header.sourceTimeDate[0]) { // libdpx's date/time format is pretty close to OIIO's (libdpx uses // %Y:%m:%d:%H:%M:%S%Z) char date[24]; strcpy(date, m_dpx.header.sourceTimeDate); date[10] = ' '; date[19] = 0; m_spec.attribute ("dpx:SourceDateTime", date); } m_dpx.header.FilmEdgeCode(buf); if (buf[0]) m_spec.attribute ("dpx:FilmEdgeCode", buf); tmpstr.clear (); switch (m_dpx.header.Signal ()) { case dpx::kUndefined: tmpstr = "Undefined"; break; case dpx::kNTSC: tmpstr = "NTSC"; break; case dpx::kPAL: tmpstr = "PAL"; break; case dpx::kPAL_M: tmpstr = "PAL-M"; break; case dpx::kSECAM: tmpstr = "SECAM"; break; case dpx::k525LineInterlace43AR: tmpstr = "YCbCr ITU-R 601-5 525i, 4:3"; break; case dpx::k625LineInterlace43AR: tmpstr = "YCbCr ITU-R 601-5 625i, 4:3"; break; case dpx::k525LineInterlace169AR: tmpstr = "YCbCr ITU-R 601-5 525i, 16:9"; break; case dpx::k625LineInterlace169AR: tmpstr = "YCbCr ITU-R 601-5 625i, 16:9"; break; case dpx::k1050LineInterlace169AR: tmpstr = "YCbCr 1050i, 16:9"; break; case dpx::k1125LineInterlace169AR_274: tmpstr = "YCbCr 1125i, 16:9 (SMPTE 274M)"; break; case dpx::k1250LineInterlace169AR: tmpstr = "YCbCr 1250i, 16:9"; break; case dpx::k1125LineInterlace169AR_240: tmpstr = "YCbCr 1125i, 16:9 (SMPTE 240M)"; break; case dpx::k525LineProgressive169AR: tmpstr = "YCbCr 525p, 16:9"; break; case dpx::k625LineProgressive169AR: tmpstr = "YCbCr 625p, 16:9"; break; case dpx::k750LineProgressive169AR: tmpstr = "YCbCr 750p, 16:9 (SMPTE 296M)"; break; case dpx::k1125LineProgressive169AR: tmpstr = "YCbCr 1125p, 16:9 (SMPTE 274M)"; break; case 0xFF: // don't set the attribute at all break; default: tmpstr = Strutil::format ("Undefined %d", (int)m_dpx.header.Signal ()); break; } if (!tmpstr.empty ()) m_spec.attribute ("dpx:Signal", tmpstr); // read in user data; don't bother if the buffer is already filled (user // data is per-file, not per-element) if (m_userBuf.empty () && m_dpx.header.UserSize () != 0 && m_dpx.header.UserSize () != 0xFFFFFFFF) { m_userBuf.resize (m_dpx.header.UserSize ()); m_dpx.ReadUserData (&m_userBuf[0]); } if (!m_userBuf.empty ()) m_spec.attribute ("dpx:UserData", TypeDesc (TypeDesc::UCHAR, m_dpx.header.UserSize ()), &m_userBuf[0]); dpx::Block block(0, 0, m_dpx.header.Width () - 1, 0); int bufsize = dpx::QueryRGBBufferSize (m_dpx.header, subimage, block); if (bufsize == 0 && !m_wantRaw) { error ("Unable to deliver RGB data from source data"); return false; } else if (!m_wantRaw && bufsize > 0) m_dataPtr = new unsigned char[bufsize]; else // no need to allocate another buffer m_dataPtr = NULL; newspec = m_spec; return 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() && 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; }
IplImage * ImageBufAlgo::to_IplImage (const ImageBuf &src) { #ifdef USE_OPENCV ImageBuf tmp = src; ImageSpec spec = tmp.spec(); // Make sure the image buffer is initialized. if (!tmp.initialized() && !tmp.read(tmp.subimage(), tmp.miplevel(), true)) { DASSERT (0 && "Could not initialize ImageBuf."); return NULL; } int dstFormat; TypeDesc dstSpecFormat; if (spec.format == TypeDesc(TypeDesc::UINT8)) { dstFormat = IPL_DEPTH_8U; dstSpecFormat = spec.format; } else if (spec.format == TypeDesc(TypeDesc::INT8)) { dstFormat = IPL_DEPTH_8S; dstSpecFormat = spec.format; } else if (spec.format == TypeDesc(TypeDesc::UINT16)) { dstFormat = IPL_DEPTH_16U; dstSpecFormat = spec.format; } else if (spec.format == TypeDesc(TypeDesc::INT16)) { dstFormat = IPL_DEPTH_16S; dstSpecFormat = spec.format; } else if (spec.format == TypeDesc(TypeDesc::HALF)) { dstFormat = IPL_DEPTH_32F; // OpenCV does not support half types. Switch to float instead. dstSpecFormat = TypeDesc(TypeDesc::FLOAT); } else if (spec.format == TypeDesc(TypeDesc::FLOAT)) { dstFormat = IPL_DEPTH_32F; dstSpecFormat = spec.format; } else if (spec.format == TypeDesc(TypeDesc::DOUBLE)) { dstFormat = IPL_DEPTH_64F; dstSpecFormat = spec.format; } else { DASSERT (0 && "Unknown data format in ImageBuf."); return NULL; } IplImage *ipl = cvCreateImage(cvSize(spec.width, spec.height), dstFormat, spec.nchannels); if (!ipl) { DASSERT (0 && "Unable to create IplImage."); return NULL; } size_t pixelsize = dstSpecFormat.size() * spec.nchannels; // Account for the origin in the line step size, to end up with the // standard OIIO origin-at-upper-left: size_t linestep = ipl->origin ? -ipl->widthStep : ipl->widthStep; bool converted = convert_image(spec.nchannels, spec.width, spec.height, 1, tmp.localpixels(), spec.format, spec.pixel_bytes(), spec.scanline_bytes(), 0, ipl->imageData, dstSpecFormat, pixelsize, linestep, 0); if (!converted) { DASSERT (0 && "convert_image failed."); cvReleaseImage(&ipl); return NULL; } // OpenCV uses BGR ordering if (spec.nchannels == 3) { cvCvtColor(ipl, ipl, CV_RGB2BGR); } else if (spec.nchannels == 4) { cvCvtColor(ipl, ipl, CV_RGBA2BGRA); } return ipl; #else return NULL; #endif }
bool ImageBuf::read (int subimage, int miplevel, bool force, TypeDesc convert, ProgressCallback progress_callback, void *progress_callback_data) { if (pixels_valid() && !force && subimage == this->subimage() && miplevel == this->miplevel()) return true; if (! init_spec (m_name.string(), subimage, miplevel)) { m_badfile = true; m_spec_valid = false; return false; } // Set our current spec to the requested subimage if (! m_imagecache->get_imagespec (m_name, m_spec, subimage, miplevel) || ! m_imagecache->get_imagespec (m_name, m_nativespec, subimage, miplevel, true)) { m_err = m_imagecache->geterror (); return false; } m_current_subimage = subimage; m_current_miplevel = miplevel; #if 1 // If we don't already have "local" pixels, and we aren't asking to // convert the pixels to a specific (and different) type, then take an // early out by relying on the cache. int peltype = TypeDesc::UNKNOWN; m_imagecache->get_image_info (m_name, subimage, miplevel, ustring("cachedpixeltype"), TypeDesc::TypeInt, &peltype); m_cachedpixeltype = TypeDesc ((TypeDesc::BASETYPE)peltype); if (! m_localpixels && ! force && (convert == m_cachedpixeltype || convert == TypeDesc::UNKNOWN)) { m_spec.format = m_cachedpixeltype; #ifdef DEBUG std::cerr << "read was not necessary -- using cache\n"; #endif return true; } else { #ifdef DEBUG std::cerr << "going to have to read " << m_name << ": " << m_spec.format.c_str() << " vs " << convert.c_str() << "\n"; #endif } #endif if (convert != TypeDesc::UNKNOWN) m_spec.format = convert; m_orientation = m_spec.get_int_attribute ("orientation", 1); m_pixelaspect = m_spec.get_float_attribute ("pixelaspectratio", 1.0f); realloc (); if (m_imagecache->get_pixels (m_name, subimage, miplevel, m_spec.x, m_spec.x+m_spec.width, m_spec.y, m_spec.y+m_spec.height, m_spec.z, m_spec.z+m_spec.depth, m_spec.format, &m_pixels[0])) { m_pixels_valid = true; m_localpixels = true; } else { m_pixels_valid = false; m_err = m_imagecache->geterror (); } return m_pixels_valid; }
void OSOReaderQuery::hint (string_view hintstring) { if (! Strutil::parse_char (hintstring, '%')) return; if (Strutil::parse_prefix(hintstring, "meta{")) { // std::cerr << " Metadata '" << hintstring << "'\n"; Strutil::skip_whitespace (hintstring); std::string type = Strutil::parse_until (hintstring, ",}"); Strutil::parse_char (hintstring, ','); std::string name = Strutil::parse_until (hintstring, ",}"); Strutil::parse_char (hintstring, ','); // std::cerr << " " << name << " : " << type << "\n"; OSLQuery::Parameter p; p.name = name; p.type = TypeDesc (type.c_str()); if (p.type.basetype == TypeDesc::STRING) { string_view val; while (Strutil::parse_string (hintstring, val)) { p.sdefault.push_back (ustring(val)); if (Strutil::parse_char (hintstring, '}')) break; Strutil::parse_char (hintstring, ','); } } else if (p.type.basetype == TypeDesc::INT) { int val; while (Strutil::parse_int (hintstring, val)) { p.idefault.push_back (val); Strutil::parse_char (hintstring, ','); } } else if (p.type.basetype == TypeDesc::FLOAT) { float val; while (Strutil::parse_float (hintstring, val)) { p.fdefault.push_back (val); Strutil::parse_char (hintstring, ','); } } Strutil::parse_char (hintstring, '}'); if (m_reading_param) // Parameter metadata m_query.m_params[m_query.nparams()-1].metadata.push_back (p); else // global shader metadata m_query.m_meta.push_back (p); return; } if (m_reading_param && Strutil::parse_prefix(hintstring, "structfields{")) { OSLQuery::Parameter ¶m (m_query.m_params[m_query.nparams()-1]); string_view ident; while (1) { string_view ident = Strutil::parse_identifier (hintstring); if (ident.length()) { param.fields.push_back (ustring(ident)); Strutil::parse_char (hintstring, ','); } else { break; } } Strutil::parse_char (hintstring, '}'); return; } if (m_reading_param && Strutil::parse_prefix(hintstring, "struct{")) { string_view str; Strutil::parse_string (hintstring, str); m_query.m_params[m_query.nparams()-1].structname = str; Strutil::parse_char (hintstring, '}'); return; } if (m_reading_param && Strutil::parse_prefix(hintstring, "initexpr")) { m_query.m_params[m_query.nparams()-1].validdefault = false; return; } // std::cerr << "Hint '" << hintstring << "'\n"; }