Пример #1
0
/* Build the test file. */
int
buildfile(size_t num_vars, size_t num_atts, size_t att_len,
          char *file_name)
{
   int ncid, varid;
   int dimids[NDIMS];
   int v;

   if (nc_create(file_name, NC_NETCDF4, &ncid)) ERR;

   if (nc_def_dim(ncid, DIM0, DIMSIZE0, &dimids[0])) ERR;
   if (nc_def_dim(ncid, DIM1, DIMSIZE1, &dimids[1])) ERR;
   for (v = 0; v < num_vars; v++)
   {
      char var_name[NC_MAX_NAME + 1];
      sprintf(var_name, "%s_var_%d", TEST, v);
      if (nc_def_var(ncid, var_name, NC_INT, NDIMS, dimids, &varid)) ERR;
      if (add_attributes(ncid, v, num_atts, att_len)) ERR;
   }
   if (!num_vars)
      if (add_attributes(ncid, NC_GLOBAL, num_atts, att_len)) ERR;
   if (nc_enddef(ncid)) ERR;

   if (nc_close(ncid)) ERR;
   return 0;
}
Пример #2
0
    std::string event::serialize() const {
        FFWD::Protocol0::Message message;
        FFWD::Protocol0::Event *e = message.mutable_event();

        if (has(TIME))
            e->set_time(time_);

        if (has(KEY))
            e->set_key(key_);

        if (has(VALUE))
            e->set_value(value_);

        if (has(HOST))
            e->set_host(host_);

        if (has(STATE))
            e->set_state(state_);

        if (has(DESCRIPTION))
            e->set_description(description_);

        if (has(TTL))
            e->set_ttl(ttl_);

        if (has(TAGS))
            add_tags(e, tags_);

        if (has(ATTRIBUTES))
            add_attributes(e, attributes_);

        std::string string;
        message.SerializeToString(&string);
        return string;
    }
Пример #3
0
    std::string metric::serialize() const {
        FFWD::Protocol0::Message message;
        FFWD::Protocol0::Metric *m = message.mutable_metric();

        if (has(PROC))
            m->set_proc(proc_);

        if (has(TIME))
            m->set_time(time_);

        if (has(KEY))
            m->set_key(key_);

        if (has(VALUE))
            m->set_value(value_);

        if (has(HOST))
            m->set_host(host_);

        if (has(TAGS))
            add_tags(m, tags_);

        if (has(ATTRIBUTES))
            add_attributes(m, attributes_);

        std::string string;
        message.SerializeToString(&string);
        return string;
    }
Пример #4
0
int saveJobToXML(

  job *pjob,      /* I - pointer to job */
  const char *filename) /* I - filename to save to */

  {
  xmlDocPtr doc = NULL;       /* document pointer */
  xmlNodePtr root_node;
  int lenwritten = 0, rc = PBSE_NONE;
  root_node = NULL;
  char  log_buf[LOCAL_LOG_BUF_SIZE];
  if ((doc = xmlNewDoc((const xmlChar*) "1.0")))
    {
    root_node = xmlNewNode(NULL, (const xmlChar*) JOB_TAG);
    xmlDocSetRootElement(doc, root_node);
    add_fix_fields(&root_node, (const job*)pjob);
    add_union_fields(&root_node, (const job*)pjob);
    if (add_attributes(&root_node, pjob))
      return -1;

#ifdef PBS_MOM
    add_mom_fields(&root_node, (const job*)pjob);
#endif /* PBS_MOM */

#ifndef PBS_MOM
    lock_ss();
#endif /* !defined PBS_MOM */

    lenwritten = xmlSaveFormatFileEnc(filename, doc, NULL, 1);

#ifndef PBS_MOM
    unlock_ss();
#endif /* !defined PBS_MOM */

    xmlFreeDoc(doc);
    }
  else
    {
    snprintf(log_buf, sizeof(log_buf), "could not create a new xml document");
    log_event(
    PBSEVENT_JOB,
    PBS_EVENTCLASS_JOB,
    pjob->ji_qs.ji_jobid,
    log_buf);
    rc = -1;     
    }

  if (lenwritten <= 0)
    {
    snprintf(log_buf, sizeof(log_buf), "failed writing job to the xml file %s", filename);
    log_event(
      PBSEVENT_JOB,
      PBS_EVENTCLASS_JOB,
      pjob->ji_qs.ji_jobid,
      log_buf);
    rc = -1;
    }

  return rc;
  } /* saveJobToXML */
Пример #5
0
static hubbub_error create_element(void *parser, const hubbub_tag *tag,
		void **result)
{
	dom_hubbub_parser *dom_parser = (dom_hubbub_parser *) parser;
	dom_exception err;
	dom_string *name;
	struct dom_element *element = NULL;
	hubbub_error herr;

	*result = NULL;

	err = dom_string_create_interned(tag->name.ptr, tag->name.len, &name);
	if (err != DOM_NO_ERR) {
		dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
				"Can't create element name");
		goto fail;
	}

	if (tag->ns == HUBBUB_NS_NULL) {
		err = dom_document_create_element(dom_parser->doc, name,
				&element);
		if (err != DOM_NO_ERR) {
			dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
					"Can't create the DOM element");
			goto clean1;
		}
	} else {
		err = dom_document_create_element_ns(dom_parser->doc,
				dom_namespaces[tag->ns], name, &element);
		if (err != DOM_NO_ERR) {
			dom_parser->msg(DOM_MSG_CRITICAL, dom_parser->mctx,
					"Can't create the DOM element");
			goto clean1;
		}
	}

	if (element != NULL && tag->n_attributes > 0) {
		herr = add_attributes(parser, element, tag->attributes,
				tag->n_attributes);
		if (herr != HUBBUB_OK)
			goto clean1;
	}

	*result = element;

clean1:
	dom_string_unref(name);

fail:
	if (*result == NULL)
		return HUBBUB_UNKNOWN;
	else
		return HUBBUB_OK;
}
Пример #6
0
Entry<TypeOfEntry>::Entry(
    const Entry<TypeOfEntry>& from)
: BasicEntry(from), 
  value( from.value ),
  increment(from.increment),
  min(from.min),
  max(from.max)
{
    add_attributes( TypeOfEntry(), additional_attributes );
    range_checker = create_bounds_watcher( min, value, max );
}
Пример #7
0
Entry<TypeOfEntry>::Entry(
    string name, const TypeOfEntry& startVal)
: BasicEntry(name), 
  value( "value", startVal ),
  increment("increment", startVal ),
  min("min", bound_type() ),
  max("max", bound_type() )
{
    add_attributes( TypeOfEntry(), additional_attributes );
    range_checker = create_bounds_watcher( min, value, max );
}
Пример #8
0
static void push_node(lua_State *L, const GumboNode *node) {
    luaL_checkstack(L, 10, "element nesting too deep");
    switch (node->type) {
    case GUMBO_NODE_DOCUMENT: {
        const GumboDocument *document = &node->v.document;
        lua_createtable(L, document->children.length, 4);
        add_literal(L, "type", "document");
        add_string(L, "quirks_mode", quirksmap[document->doc_type_quirks_mode]);
        if (document->has_doctype) {
            lua_createtable(L, 0, 3);
            add_string(L, "name", document->name);
            add_string(L, "publicId", document->public_identifier);
            add_string(L, "systemId", document->system_identifier);
            lua_setfield(L, -2, "doctype");
        }
        add_children(L, &document->children);
        return;
    }
    case GUMBO_NODE_ELEMENT: {
        const GumboElement *element = &node->v.element;
        lua_createtable(L, element->children.length, 7);
        lua_getfield(L, LUA_REGISTRYINDEX, "gumbo.element");
        lua_setmetatable(L, -2);
        add_tag(L, element);
        add_string(L, "tag_namespace", tagnsmap[element->tag_namespace]);
        add_integer(L, "line", element->start_pos.line);
        add_integer(L, "column", element->start_pos.column);
        add_integer(L, "offset", element->start_pos.offset);
        add_parseflags(L, node->parse_flags);
        add_attributes(L, &element->attributes);
        add_children(L, &element->children);
        return;
    }
    case GUMBO_NODE_TEXT:
        create_text_node(L, &node->v.text);
        add_literal(L, "type", "text");
        return;
    case GUMBO_NODE_COMMENT:
        create_text_node(L, &node->v.text);
        add_literal(L, "type", "comment");
        return;
    case GUMBO_NODE_CDATA:
        create_text_node(L, &node->v.text);
        add_literal(L, "type", "cdata");
        return;
    case GUMBO_NODE_WHITESPACE:
        create_text_node(L, &node->v.text);
        add_literal(L, "type", "whitespace");
        return;
    }
}
Пример #9
0
void ExportFormatJSON::finish_feature(const osmium::OSMObject& object) {
    m_writer.Key("properties");
    m_writer.StartObject(); // start properties

    add_attributes(object);

    const bool has_tags = add_tags(object, [&](const osmium::Tag& tag) {
        m_writer.String(tag.key());
        m_writer.String(tag.value());
    });

    if (has_tags || options().keep_untagged) {
        m_writer.EndObject(); // end properties
        m_writer.EndObject(); // end feature

        m_committed_size = m_stream.GetSize();
        ++m_count;

        if (m_stream.GetSize() > flush_buffer_size) {
            flush_to_output();
        }
    }
}
Пример #10
0
void EXRImageFileWriter::write(
    const char*             filename,
    const ICanvas&          image,
    const ImageAttributes&  image_attributes)
{
    try
    {
        // Retrieve canvas properties.
        const CanvasProperties& props = image.properties();

        // todo: lift this limitation.
        assert(props.m_channel_count <= 4);

        // Figure out the pixel type, based on the pixel format of the image.
        PixelType pixel_type = FLOAT;
        switch (props.m_pixel_format)
        {
        case PixelFormatUInt32:
            pixel_type = UINT;
            break;
        case PixelFormatHalf:
            pixel_type = HALF;
            break;
        case PixelFormatFloat:
            pixel_type = FLOAT;
            break;
        default:
            throw ExceptionUnsupportedImageFormat();
        }

        // Construct TileDescription object.
        const TileDescription tile_desc(
            static_cast<unsigned int>(props.m_tile_width),
            static_cast<unsigned int>(props.m_tile_height),
            ONE_LEVEL);

        // Construct ChannelList object.
        ChannelList channels;
        for (size_t c = 0; c < props.m_channel_count; ++c)
            channels.insert(ChannelName[c], Channel(pixel_type));

        // Construct Header object.
        Header header(
            static_cast<int>(props.m_canvas_width),
            static_cast<int>(props.m_canvas_height));
        header.setTileDescription(tile_desc);
        header.channels() = channels;

        // Add image attributes to the Header object.
        add_attributes(image_attributes, header);

        // Create the output file.
        TiledOutputFile file(filename, header, m_thread_count);

        // Write tiles.
        for (size_t y = 0; y < props.m_tile_count_y; ++y)
        {
            for (size_t x = 0; x < props.m_tile_count_x; ++x)
            {
                const int ix              = static_cast<int>(x);
                const int iy              = static_cast<int>(y);
                const Box2i range         = file.dataWindowForTile(ix, iy);
                const Tile& tile          = image.tile(x, y);
                const size_t channel_size = Pixel::size(tile.get_pixel_format());
                const size_t stride_x     = channel_size * props.m_channel_count;
                const size_t stride_y     = stride_x * tile.get_width();
                const size_t tile_origin  = range.min.x * stride_x + range.min.y * stride_y;
                const char* tile_base     = reinterpret_cast<const char*>(tile.pixel(0, 0)) - tile_origin;

                // Construct FrameBuffer object.
                FrameBuffer framebuffer;
                for (size_t c = 0; c < props.m_channel_count; ++c)
                {
                    const char* base = tile_base + c * channel_size;
                    framebuffer.insert(
                        ChannelName[c],
                        Slice(
                            pixel_type,
                            const_cast<char*>(base),
                            stride_x,
                            stride_y));
                }

                // Write tile.
                file.setFrameBuffer(framebuffer);
                file.writeTile(ix, iy);
            }
        }
    }
    catch (const BaseExc& e)
    {
        // I/O error.
        throw ExceptionIOError(e.what());
    }
}
Пример #11
0
void PNGImageFileWriter::write(
    const char*             filename,
    const ICanvas&          image,
    const ImageAttributes&  image_attributes)
{
    // Retrieve canvas properties.
    const CanvasProperties& props = image.properties();

    // todo: lift these limitations.
    assert(props.m_channel_count == 3 || props.m_channel_count == 4);

    // Open the file in write mode.
    FILE* fp = fopen(filename, "wb");
    if (fp == 0)
        throw ExceptionIOError();

    // Allocate and initialize the png_struct structure.
    png_structp png_ptr =
        png_create_write_struct(
            PNG_LIBPNG_VER_STRING,
            fp,
            error_callback,
            warning_callback);
    if (png_ptr == 0)
    {
        fclose(fp);
        throw ExceptionMemoryError();
    }

    // Allocate the png_info structure.
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (info_ptr == 0)
    {
        png_destroy_write_struct(&png_ptr, 0);
        fclose(fp);
        throw ExceptionMemoryError();
    }

    // Set up the output control.
    png_init_io(png_ptr, fp);

    // Set image information.
    png_set_IHDR(
        png_ptr,
        info_ptr,
        static_cast<png_uint_32>(props.m_canvas_width),
        static_cast<png_uint_32>(props.m_canvas_height),
        8,                                  // bit depth -- todo: allow higher bit depths
        props.m_channel_count == 4
            ? PNG_COLOR_TYPE_RGB_ALPHA
            : PNG_COLOR_TYPE_RGB,
        PNG_INTERLACE_NONE,
        PNG_COMPRESSION_TYPE_DEFAULT,
        PNG_FILTER_TYPE_DEFAULT);

    // Mark the image as being sRGB (implying specific gamma and color matching functions).
    // See http://www.vias.org/pngguide/chapter10_07.html for details about intents.
    png_set_sRGB_gAMA_and_cHRM(
        png_ptr,
        info_ptr,
        PNG_sRGB_INTENT_PERCEPTUAL);        // todo: allow the user to select different intents

    // Set the number of significant bits for each of the R, G, B and A channels.
    // todo: are we required to provide these information?
    png_color_8 sig_bit;
    sig_bit.red = 8;
    sig_bit.green = 8;
    sig_bit.blue = 8;
    sig_bit.alpha = 8;
    sig_bit.gray = 8;                       // for completeness
    png_set_sBIT(png_ptr, info_ptr, &sig_bit);

    // Add image attributes.
    vector<png_text_struct> text_chunks;
    add_attributes(
        png_ptr,
        info_ptr,
        text_chunks,
        image_attributes);
    if (!text_chunks.empty())
    {
        png_set_text(
            png_ptr,
            info_ptr,
            &text_chunks[0],
            static_cast<int>(text_chunks.size()));
    }

    // Write the file header information.
    png_write_info(png_ptr, info_ptr);

    // Create the temporary buffer holding one row of tiles in target format.
    vector<uint8> buffer(
          props.m_canvas_width
        * props.m_tile_height
        * props.m_channel_count);

    // Construct pointers to each row of the temporary buffer.
    vector<uint8*> buffer_rows(props.m_tile_height);
    for (size_t y = 0; y < props.m_tile_height; ++y)
        buffer_rows[y] = &buffer[y * props.m_canvas_width * props.m_channel_count];

    // Loop over the rows of tiles.
    for (size_t tile_y = 0; tile_y < props.m_tile_count_y; ++tile_y)
    {
        // Convert this row of tiles to target format.
        for (size_t tile_x = 0; tile_x < props.m_tile_count_x; ++tile_x)
        {
            const Tile& tile = image.tile(tile_x, tile_y);
            assert(tile.get_height() <= props.m_tile_height);
            for (size_t y = 0; y < tile.get_height(); ++y)
            {
                for (size_t x = 0; x < tile.get_width(); ++x)
                {
                    // Horizontal coordinate of the pixel in the temporary buffer.
                    const size_t buffer_x = tile_x * props.m_tile_width + x;

                    // Index of the pixel in the temporary buffer.
                    const size_t buffer_index =
                        (y * props.m_canvas_width + buffer_x) * props.m_channel_count;

                    // Fetch the pixel at coordinates (x, y) in the tile,
                    // perform format conversion if necessary, and store
                    // the converted pixel into the temporary buffer.
                    if (tile.get_channel_count() == 3)
                    {
                        Color3i pixel;
                        tile.get_pixel(x, y, pixel);
                        buffer[buffer_index + 0] = pixel[0];
                        buffer[buffer_index + 1] = pixel[1];
                        buffer[buffer_index + 2] = pixel[2];
                    }
                    else
                    {
                        assert(tile.get_channel_count() == 4);
                        Color4i pixel;
                        tile.get_pixel(x, y, pixel);
                        buffer[buffer_index + 0] = pixel[0];
                        buffer[buffer_index + 1] = pixel[1];
                        buffer[buffer_index + 2] = pixel[2];
                        buffer[buffer_index + 3] = pixel[3];
                    }
                }
            }
        }

        // Write this row of tiles to the file.
        const size_t row_count = image.tile(0, tile_y).get_height();
        png_write_rows(
            png_ptr,
            &buffer_rows[0],
            static_cast<png_uint_32>(row_count));
    }

    // Finish writing the file.
    png_write_end(png_ptr, 0);

    // Deallocate the png_struct and png_info structures.
    png_destroy_write_struct(&png_ptr, &info_ptr);

    // Deallocate text chunks.
    destroy_text_chunks(text_chunks);

    // Close the file.
    fclose(fp);
}
Пример #12
0
void traverse_node(rapidxml::xml_node<> *xmlnode, rapidjson::Value &jsvalue, rapidjson::Document::AllocatorType& allocator)
{
    //cout << "this: " << xmlnode->type() << " name: " << xmlnode->name() << " value: " << xmlnode->value() << endl;
    rapidjson::Value jsvalue_chd;

    jsvalue.SetObject();
    jsvalue_chd.SetObject();
    rapidxml::xml_node<> *xmlnode_chd;

    // classified discussion:
    if ((xmlnode->type() == rapidxml::node_data || xmlnode->type() == rapidxml::node_cdata) && xmlnode->value())
    {
        // case: pure_text
        jsvalue.SetString(xmlnode->value(), allocator); // then addmember("#text" , jsvalue, allocator)
    }
    else if (xmlnode->type() == rapidxml::node_element)
    {
        if (xmlnode->first_attribute())
        {
            if (xmlnode->first_node() && xmlnode->first_node()->type() == rapidxml::node_data && count_children(xmlnode) == 1)
            {
                // case: <e attr="xxx">text</e>
                rapidjson::Value jn, jv;
                jn.SetString("#text", allocator);
                jv.SetString(xmlnode->first_node()->value(), allocator);
                jsvalue.AddMember(jn, jv, allocator);
                add_attributes(xmlnode, jsvalue, allocator);
                return;
            }
            else
            {
                // case: <e attr="xxx">...</e>
                add_attributes(xmlnode, jsvalue, allocator);
            }
        }
        else
        {
            if (!xmlnode->first_node())
            {
                // case: <e />
                jsvalue.SetNull();
                return;
            }
            else if (xmlnode->first_node()->type() == rapidxml::node_data && count_children(xmlnode) == 1)
            {
                // case: <e>text</e>
                jsvalue.SetString(rapidjson::StringRef(xmlnode->first_node()->value()), allocator);
                return;
            }
        }
        if (xmlnode->first_node())
        {
            // case: complex else...
            std::map<std::string, int> name_count;
            for (xmlnode_chd = xmlnode->first_node(); xmlnode_chd; xmlnode_chd = xmlnode_chd->next_sibling())
            {
                std::string current_name;
                const char *name_ptr = NULL;
                rapidjson::Value jn, jv;
                if (xmlnode_chd->type() == rapidxml::node_data || xmlnode_chd->type() == rapidxml::node_cdata)
                {
                    current_name = "#text";
                    name_count[current_name]++;
                    jv.SetString("#text", allocator);
                    name_ptr = jv.GetString();
                }
                else if (xmlnode_chd->type() == rapidxml::node_element)
                {
                    current_name = xmlnode_chd->name();
                    name_count[current_name]++;
                    name_ptr = xmlnode_chd->name();
                }
                traverse_node(xmlnode_chd, jsvalue_chd, allocator);
                if (name_count[current_name] > 1 && name_ptr)
                    to_array_form(name_ptr, jsvalue, jsvalue_chd, allocator);
                else
                {
                    jn.SetString(name_ptr, allocator);
                    jsvalue.AddMember(jn, jsvalue_chd, allocator);
                }
            }
        }
    }
    else
    {
        std::cerr << "err data!!" << std::endl;
    }
}
Пример #13
0
inline void add_attributes( boost::units::quantity<Unit,Value>, boost::ptr_vector< BaseAttribute >& t )
{
    add_attributes( Value(), t );
    t.push_back( new Attribute<std::string>("unit_name", boost::units::name_string(Unit()) ) );
    t.push_back( new Attribute<std::string>("unit_symbol", boost::units::symbol_string(Unit()) ) );
}
Пример #14
0
void add_attributes( boost::optional<Inner>, boost::ptr_vector< BaseAttribute >& t ) {
    add_attributes( Inner(), t );
    t.push_back( new Attribute<bool>("is_optional", true) );
}
Пример #15
0
void add_attributes( Eigen::MatrixBase<Derived> d, boost::ptr_vector< BaseAttribute >& t ) {
    add_attributes( typename Derived::Scalar(), t );
    t.push_back( new Attribute<int>("rows", Derived().rows()) );
    t.push_back( new Attribute<int>("columns", Derived().cols()) );
}
int
main(int argc, char** argv)
{
	if (argc > 1 && !strcmp(argv[1], "-v"))
		gVerbose = true;

	BFile file;
	status_t status = file.SetTo(kTempFile, B_CREATE_FILE | B_READ_WRITE);
	if (status != B_OK) {
		fprintf(stderr, "Could not create temporary file: %s\n",
			strerror(status));
		return 1;
	}

	puts("--------- Remove Tests ----------");

	// remove test, many attributes

	puts("Test 1...");

	for (int32 count = 5; count <= 100; count += 5) {
		add_attributes(file, 1, count);
		add_marker_attribute(file, count);
		add_attributes(file, count + 1, count);

		test_remove_attributes(file, 1, count,
			count & 1 ? count - 1 : count + 1, count, -1);

		remove_attributes(file, 1, count * 2);
	}

	// remove test, all positions

	puts("Test 2...");

	for (int32 i = 1; i < 100; i++) {
		add_attributes(file, 1, 50);
		add_marker_attribute(file, 51);
		add_attributes(file, 51, 50);

		test_remove_attributes(file, 1, 100, i, 51, -1);

		remove_attributes(file, 1, 100);
	}

	// remove test, all positions, remove many

	puts("Test 3...");

	for (int32 i = 1; i < 100; i++) {
		add_attributes(file, 1, 33);
		add_marker_attribute(file, 33);
		add_attributes(file, 34, 34);
		add_marker_attribute(file, 67);
		add_attributes(file, 68, 33);

		test_remove_attributes(file, 1, 100, i, 33, 67);

		remove_attributes(file, 1, 100);
	}

	puts("--------- Add Tests ----------");

	// add test, many attributes

	puts("Test 4...");

	for (int32 count = 10; count <= 200; count += 10) {
		add_attributes(file, 1, count);

		int32 half = count / 2;

		test_add_attributes(file, 1, count,
			half & 1 ? half - 1 : half + 1, half - 2, half + 2);

		remove_attributes(file, 1, count);
	}

	// add test, all iterator positions

	puts("Test 5...");

	for (int32 i = 1; i < 100; i++) {
		add_attributes(file, 1, 100);

		test_add_attributes(file, 1, 100, i, 50, -1);

		remove_attributes(file, 1, 100);
	}

	// add test, all attribute positions

	puts("Test 6...");

	for (int32 i = 1; i < 100; i++) {
		add_attributes(file, 1, 100);

		test_add_attributes(file, 1, 100, 50, i, -1);

		remove_attributes(file, 1, 100);
	}

	// add test, many attributes

	puts("Test 7...");

	for (int32 i = 1; i < 100; i++) {
		add_attributes(file, 1, 100);

		test_add_attributes(file, 1, 100, i, 33, 67);

		remove_attributes(file, 1, 100);
	}

	// add test, many attributes

	puts("Test 8...");

	for (int32 i = 1; i < 100; i++) {
		add_attributes(file, 1, 100);

		test_add_attributes(file, 1, 100, 50, i - 1, i + 1);

		remove_attributes(file, 1, 100);
	}

	BEntry entry;
	if (entry.SetTo(kTempFile) == B_OK)
		entry.Remove();

	return 0;
}
// Open an image file for writing.
void ProgressiveEXRImageFileWriter::open(
    const char*             filename,
    const CanvasProperties& props,
    const ImageAttributes&  attrs)
{
    assert(filename);
    assert(!is_open());

    try
    {
        // todo: lift this limitation.
        assert(props.m_channel_count <= 4);

        // Figure out the pixel type, based on the pixel format of the image.
        impl->m_pixel_type = FLOAT;
        switch (props.m_pixel_format)
        {
          case PixelFormatUInt32: impl->m_pixel_type = UINT; break;
          case PixelFormatHalf: impl->m_pixel_type = HALF; break;
          case PixelFormatFloat: impl->m_pixel_type = FLOAT; break;
          default: throw ExceptionUnsupportedImageFormat();
        }

        // Construct TileDescription object.
        const TileDescription tile_desc(
            static_cast<unsigned int>(props.m_tile_width),
            static_cast<unsigned int>(props.m_tile_height),
            ONE_LEVEL);

        // Construct ChannelList object.
        ChannelList channels;
        for (size_t c = 0; c < props.m_channel_count; ++c)
            channels.insert(ChannelName[c], Channel(impl->m_pixel_type));

        // Construct Header object.
        Header header(
            static_cast<int>(props.m_canvas_width),
            static_cast<int>(props.m_canvas_height),
            static_cast<float>(props.m_canvas_width) / props.m_canvas_height);
        header.setTileDescription(tile_desc);
        header.channels() = channels;

        // Add image attributes to the Header object.
        add_attributes(attrs, header);

        // Create the output file.
        impl->m_file.reset(
            new TiledOutputFile(
                filename,
                header,
                impl->m_thread_count));

        // Store the canvas properties.
        impl->m_props = props;
    }
    catch (const BaseExc& e)
    {
        // I/O error.
        throw ExceptionIOError(e.what());
    }
}