Beispiel #1
0
static GwyDataField*
rhk_sm3_page_to_data_field(const RHKPage *page)
{
    GwyDataField *dfield;
    GwySIUnit *siunit;
    const gchar *unit;
    gint xres, yres, i;
    gint32 *pdata;
    gdouble *data;

    xres = page->x_size;
    yres = page->y_size;
    dfield = GWY_DATA_FIELD(gwy_data_field_new(xres, yres,
                                               xres*fabs(page->x_scale),
                                               yres*fabs(page->y_scale),
                                               FALSE));
    data = gwy_data_field_get_data(dfield);
    pdata = (gint32*)page->page_data;
    for (i = 0; i < xres*yres; i++)
        data[i] = GINT32_FROM_LE(pdata[i])*page->z_scale + page->z_offset;

    if (page->strings[RHK_STRING_X_UNITS]
        && page->strings[RHK_STRING_Y_UNITS]) {
        if (strcmp(page->strings[RHK_STRING_X_UNITS],
                   page->strings[RHK_STRING_Y_UNITS]))
            g_warning("X and Y units are different, using X");
        unit = page->strings[RHK_STRING_X_UNITS];
    }
    else if (page->strings[RHK_STRING_X_UNITS])
        unit = page->strings[RHK_STRING_X_UNITS];
    else if (page->strings[RHK_STRING_Y_UNITS])
        unit = page->strings[RHK_STRING_Y_UNITS];
    else
        unit = "";
    siunit = GWY_SI_UNIT(gwy_si_unit_new(unit));
    gwy_data_field_set_si_unit_xy(dfield, siunit);
    g_object_unref(siunit);

    if (page->strings[RHK_STRING_Z_UNITS])
        unit = page->strings[RHK_STRING_Z_UNITS];
    else
        unit = "";
    siunit = GWY_SI_UNIT(gwy_si_unit_new(unit));
    gwy_data_field_set_si_unit_z(dfield, siunit);
    g_object_unref(siunit);

    return dfield;
}
Beispiel #2
0
/* FIXME: this should be the default constructor */
GtkWidget*
gwy_color_axis_new_default(GtkOrientation orientation)
{
    GwyColorAxis *axis;

    gwy_debug(" ");

    axis = (GwyColorAxis*)g_object_new(GWY_TYPE_COLOR_AXIS, NULL);
    axis->orientation = orientation;
    /* TODO: use some font properties, at least */
    if (orientation == GTK_ORIENTATION_VERTICAL)
        axis->par.textarea = 70;
    else
        axis->par.textarea = 20;

    axis->min = 0.0;
    axis->max = 1.0;

    axis->par.font = pango_font_description_from_string("Helvetica 10");
    axis->gradient = gwy_gradients_get_gradient(GWY_GRADIENT_DEFAULT);
    g_object_ref(axis->gradient);
    /* XXX: remove */
    axis->palette = (GwyPalette*)gwy_palette_new(NULL);
    axis->siunit = GWY_SI_UNIT(gwy_si_unit_new("m"));

    return GTK_WIDGET(axis);
}
Beispiel #3
0
static void
gwy_si_unit_clone_real(GObject *source, GObject *copy)
{
    GwySIUnit *si_unit, *clone;

    g_return_if_fail(GWY_IS_SI_UNIT(source));
    g_return_if_fail(GWY_IS_SI_UNIT(copy));

    si_unit = GWY_SI_UNIT(source);
    clone = GWY_SI_UNIT(copy);
    if (gwy_si_unit_equal(si_unit, clone))
        return;

    g_array_set_size(clone->units, 0);
    g_array_append_vals(clone->units,
                        si_unit->units->data, si_unit->units->len);
    clone->power10 = si_unit->power10;
    g_signal_emit(copy, si_unit_signals[VALUE_CHANGED], 0);
}
Beispiel #4
0
static GObject*
gwy_si_unit_duplicate_real(GObject *object)
{
    GwySIUnit *si_unit, *duplicate;

    g_return_val_if_fail(GWY_IS_SI_UNIT(object), NULL);
    si_unit = GWY_SI_UNIT(object);
    duplicate = gwy_si_unit_new_parse("", NULL);
    duplicate->power10 = si_unit->power10;
    g_array_append_vals(duplicate->units,
                        si_unit->units->data, si_unit->units->len);

    return (GObject*)duplicate;
}
Beispiel #5
0
static gsize
gwy_si_unit_get_size(GObject *obj)
{
    GwySIUnit *si_unit;
    gsize size;

    g_return_val_if_fail(GWY_IS_SI_UNIT(obj), 0);

    si_unit = GWY_SI_UNIT(obj);
    size = gwy_serialize_get_struct_size(GWY_SI_UNIT_TYPE_NAME, 0, NULL);
    /* Just estimate */
    size += 20*si_unit->units->len;

    return size;
}
Beispiel #6
0
/**
 * gwy_color_axis_new:
 * @orientation: The orientation of the axis.
 * @min: The minimum.
 * @max: The maximum.
 * @pal: The palette the color axis should use.
 *
 * Creates a new color axis.
 *
 * Returns: The newly created color axis as a #GtkWidget.
 **/
GtkWidget*
gwy_color_axis_new(GtkOrientation orientation,
                   gdouble min,
                   gdouble max,
                   GwyPalette *pal)
{
    GwyColorAxis *axis;

    gwy_debug("");
    g_return_val_if_fail(GWY_IS_PALETTE(pal), NULL);

    axis = gtk_type_new(gwy_color_axis_get_type());
    axis->orientation = orientation;
    /* TODO: use some font properties, at least */
    if (orientation == GTK_ORIENTATION_VERTICAL)
        axis->par.textarea = 70;
    else
        axis->par.textarea = 20;
    axis->min = min;
    axis->max = max;

    /* XXX */
    axis->par.font = pango_font_description_new();
    pango_font_description_set_family(axis->par.font, "Helvetica");
    pango_font_description_set_style(axis->par.font, PANGO_STYLE_NORMAL);
    pango_font_description_set_variant(axis->par.font, PANGO_VARIANT_NORMAL);
    pango_font_description_set_weight(axis->par.font, PANGO_WEIGHT_NORMAL);
    pango_font_description_set_size(axis->par.font, 10*PANGO_SCALE);

    axis->gradient = gwy_gradients_get_gradient(GWY_GRADIENT_DEFAULT);
    g_object_ref(axis->gradient);
    /* XXX: remove */
    axis->palette = (GwyPalette*)gwy_palette_new(NULL);
    gwy_color_axis_set_palette(axis, pal);
    axis->siunit = GWY_SI_UNIT(gwy_si_unit_new("m"));

    return GTK_WIDGET(axis);
}
Beispiel #7
0
static GByteArray*
gwy_si_unit_serialize(GObject *obj,
                      GByteArray *buffer)
{
    GwySIUnit *si_unit;
    GByteArray *retval;

    g_return_val_if_fail(GWY_IS_SI_UNIT(obj), NULL);

    si_unit = GWY_SI_UNIT(obj);
    {
        gchar *unitstr = gwy_si_unit_get_string(si_unit,
                                                GWY_SI_UNIT_FORMAT_PLAIN);
        GwySerializeSpec spec[] = {
            { 's', "unitstr", &unitstr, NULL, },
        };
        gwy_debug("unitstr = <%s>", unitstr);
        retval = gwy_serialize_pack_object_struct(buffer,
                                                  GWY_SI_UNIT_TYPE_NAME,
                                                  G_N_ELEMENTS(spec), spec);
        g_free(unitstr);
        return retval;
    }
}
Beispiel #8
0
static GwyContainer*
burleigh_load(const gchar *filename)
{
    GwySIUnit *unit;
    GwyContainer *container = NULL;
    guchar *buffer = NULL;
    const guchar *p;
    gsize size = 0;
    GError *err = NULL;
    IMGFile imgfile;
    GwyDataField *dfield;
    gdouble *data;
    const gint16 *d;
    gdouble scale;
    guint i;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        g_warning("Cannot get file contents");
        g_clear_error(&err);
        return NULL;
    }
    if (size < HEADER_SIZE_MIN + 2) {
        g_warning("File is too short");
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }

    memset(&imgfile, 0, sizeof(imgfile));
    p = buffer;
    imgfile.version = get_FLOAT(&p);
    imgfile.version_int = ROUND(10*imgfile.version);
    if (imgfile.version_int == 21) {
        d = burleigh_load_v21(&imgfile, buffer, size);
        if (!d) {
            gwy_file_abandon_contents(buffer, size, NULL);
            return NULL;
        }
    }
    else {
        g_warning("File format version %.f is not supported", imgfile.version);
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }

    dfield = GWY_DATA_FIELD(gwy_data_field_new(imgfile.xres, imgfile.yres,
                                               Angstrom*imgfile.xrange,
                                               Angstrom*imgfile.yrange,
                                               FALSE));
    data = gwy_data_field_get_data(dfield);
    scale = Angstrom * imgfile.z_gain * imgfile.zrange;
    for (i = 0; i < imgfile.xres*imgfile.yres; i++)
        data[i] = scale * GINT16_FROM_LE(d[i]);

    gwy_file_abandon_contents(buffer, size, NULL);

    unit = GWY_SI_UNIT(gwy_si_unit_new("m"));
    gwy_data_field_set_si_unit_xy(dfield, unit);
    g_object_unref(unit);

    container = GWY_CONTAINER(gwy_container_new());
    switch (imgfile.data_type) {
        case BURLEIGH_CURRENT:
        unit = GWY_SI_UNIT(gwy_si_unit_new("A"));
        gwy_container_set_string_by_name(container, "/filename/title",
                                         g_strdup("Current"));
        break;

        case BURLEIGH_TOPOGRAPHY:
        unit = GWY_SI_UNIT(gwy_si_unit_new("m"));
        gwy_container_set_string_by_name(container, "/filename/title",
                                         g_strdup("Topography"));
        break;

        default:
        unit = GWY_SI_UNIT(gwy_si_unit_new("m"));
        break;
    }
    gwy_data_field_set_si_unit_z(dfield, unit);
    g_object_unref(unit);

    gwy_container_set_object_by_name(container, "/0/data", (GObject*)dfield);
    g_object_unref(dfield);

    return container;
}
Beispiel #9
0
static void
selection_finished_cb(GwyUnitoolState *state)
{
    GwyContainer *data;
    GObject *dfield;
    GwyDataField *mask = NULL;
    GwyDataViewLayer *layer;
    ToolControls *controls;
    GwySIUnit *siunit;
    gint isel[4];

    controls = (ToolControls*)state->user_data;
    layer = GWY_DATA_VIEW_LAYER(state->layer);
    data = gwy_data_view_get_data(GWY_DATA_VIEW(layer->parent));
    dfield = gwy_container_get_object_by_name(data, "/0/data");
    gwy_container_gis_object_by_name(data, "/0/mask", (GObject**)&mask);
    gwy_unitool_rect_info_table_fill(state, &controls->labels, NULL, isel);

    switch (controls->mode) {
        case MASK_EDIT_SET:
        gwy_app_undo_checkpoint(data, "/0/mask", NULL);
        if (!mask) {
            mask = GWY_DATA_FIELD(gwy_serializable_duplicate(dfield));
            siunit = GWY_SI_UNIT(gwy_si_unit_new(""));
            gwy_data_field_set_si_unit_z(mask, siunit);
            g_object_unref(siunit);
            gwy_container_set_object_by_name(data, "/0/mask", (GObject*)mask);
            g_object_unref(mask);
        }
        gwy_data_field_fill(mask, 0.0);
        gwy_data_field_area_fill(mask, isel[0], isel[1], isel[2], isel[3],
                                 1.0);
        break;

        case MASK_EDIT_ADD:
        gwy_app_undo_checkpoint(data, "/0/mask", NULL);
        if (!mask) {
            mask = GWY_DATA_FIELD(gwy_serializable_duplicate(dfield));
            siunit = GWY_SI_UNIT(gwy_si_unit_new(""));
            gwy_data_field_set_si_unit_z(mask, siunit);
            g_object_unref(siunit);
            gwy_container_set_object_by_name(data, "/0/mask", (GObject*)mask);
            g_object_unref(mask);
            gwy_data_field_fill(mask, 0.0);
        }
        gwy_data_field_area_fill(mask, isel[0], isel[1], isel[2], isel[3],
                                 1.0);
        break;

        case MASK_EDIT_REMOVE:
        if (mask) {
            gwy_app_undo_checkpoint(data, "/0/mask", NULL);
            gwy_data_field_area_fill(mask, isel[0], isel[1], isel[2], isel[3],
                                     0.0);
        }
        break;

        case MASK_EDIT_INTERSECT:
        if (mask) {
            gwy_app_undo_checkpoint(data, "/0/mask", NULL);
            gwy_data_field_clamp(mask, 0.0, 1.0);
            gwy_data_field_area_add(mask, isel[0], isel[1], isel[2], isel[3],
                                    1.0);
            gwy_data_field_add(mask, -1.0);
            gwy_data_field_clamp(mask, 0.0, 1.0);
        }
        break;

        default:
        break;
    }
    gwy_vector_layer_unselect(GWY_VECTOR_LAYER(layer));
    gwy_app_data_view_update(layer->parent);
}
Beispiel #10
0
static gboolean
stats(GwyContainer *data, GwyRunType run)
{
    GtkWidget *dialog, *table, *label;
    GwyDataField *dfield;
    GwySIUnit *siunit, *siunit2;
    GwySIValueFormat *vf;
    gint i, xres, yres, ngrains, npix;
    gdouble area, v;
    GString *str;
    gint *grains;
    gint row;

    g_return_val_if_fail(run & DIST_RUN_MODES, FALSE);
    g_return_val_if_fail(gwy_container_contains_by_name(data, "/0/mask"),
                         FALSE);

    dfield = GWY_DATA_FIELD(gwy_container_get_object_by_name(data, "/0/mask"));
    xres = gwy_data_field_get_xres(dfield);
    yres = gwy_data_field_get_yres(dfield);
    area = gwy_data_field_get_xreal(dfield)*gwy_data_field_get_yreal(dfield);
    grains = g_new0(gint, xres*yres);

    ngrains = gwy_data_field_number_grains(dfield, grains);
    npix = 0;
    for (i = 0; i < xres*yres; i++)
        npix += (grains[i] != 0);

    g_free(grains);

    dialog = gtk_dialog_new_with_buttons(_("Grain Statistics"), NULL, 0,
                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
                                         NULL);
    gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE);
    g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_destroy), NULL);

    table = gtk_table_new(4, 2, FALSE);
    gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), table);
    gtk_container_set_border_width(GTK_CONTAINER(table), 4);
    row = 0;
    str = g_string_new("");

    label = gtk_label_new(_("Number of grains:"));
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
                     GTK_FILL, 0, 2, 2);
    g_string_printf(str, "%d", ngrains);
    label = gtk_label_new(str->str);
    gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row+1,
                     GTK_FILL, 0, 2, 2);
    row++;

    /* FIXME: simplify with 2.x unit methods */
    siunit = gwy_data_field_get_si_unit_xy(dfield);
    siunit2 = GWY_SI_UNIT(gwy_si_unit_new(""));
    gwy_si_unit_multiply(siunit, siunit, siunit2);

    label = gtk_label_new(_("Total projected area (abs.):"));
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
                     GTK_FILL, 0, 2, 2);
    v = npix*area/(xres*yres);
    vf = gwy_si_unit_get_format(siunit2, v, NULL);
    g_string_printf(str, "%.*f %s",
                    vf->precision, v/vf->magnitude, vf->units);
    label = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(label), str->str);
    gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row+1,
                     GTK_FILL, 0, 2, 2);
    row++;

    label = gtk_label_new(_("Total projected area (rel.):"));
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
    gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
                     GTK_FILL, 0, 2, 2);
    g_string_printf(str, "%.2f %%", 100.0*npix/(xres*yres));
    label = gtk_label_new(str->str);
    gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row+1,
                     GTK_FILL, 0, 2, 2);
    row++;

    label = gtk_label_new(_("Mean grain area:"));
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
                     GTK_FILL, 0, 2, 2);
    v = npix*area/(ngrains*xres*yres);
    gwy_si_unit_get_format(siunit2, v, vf);
    g_string_printf(str, "%.*f %s",
                    vf->precision, v/vf->magnitude, vf->units);
    label = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(label), str->str);
    gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row+1,
                     GTK_FILL, 0, 2, 2);
    row++;

    label = gtk_label_new(_("Mean grain size:"));
    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 0, 1, row, row+1,
                     GTK_FILL, 0, 2, 2);
    v = sqrt(npix*area/(ngrains*xres*yres));
    gwy_si_unit_get_format(siunit, v, vf);
    g_string_printf(str, "%.*f %s",
                    vf->precision, v/vf->magnitude, vf->units);
    label = gtk_label_new(NULL);
    gtk_label_set_markup(GTK_LABEL(label), str->str);
    gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
    gtk_table_attach(GTK_TABLE(table), label, 1, 2, row, row+1,
                     GTK_FILL, 0, 2, 2);
    row++;

    gwy_si_unit_value_format_free(vf);
    g_string_free(str, TRUE);
    g_object_unref(siunit2);
    gtk_widget_show_all(dialog);

    return FALSE;
}
Beispiel #11
0
static GwyContainer*
text_dump_import(gchar *buffer,
                 gsize size,
                 const gchar *filename,
                 GError **error)
{
    gchar *val, *key, *pos, *line, *title;
    GwyContainer *data;
    GwyDataField *dfield;
    gdouble xreal, yreal;
    gint xres, yres, id;
    GwySIUnit *uxy, *uz;
    const guchar *s;
    gdouble *d;
    gsize n;

    data = gwy_container_new();

    pos = buffer;
    while ((line = gwy_str_next_line(&pos)) && *line) {
        val = strchr(line, '=');
        if (!val || *line != '/') {
            g_warning("Garbage key: %s", line);
            continue;
        }
        if ((gsize)(val - buffer) + 1 > size) {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("End of file reached when value was expected."));
            goto fail;
        }
        *val = '\0';
        val++;
        if (!gwy_strequal(val, "[") || !pos || *pos != '[') {
            gwy_debug("<%s>=<%s>", line, val);
            if (*val)
                gwy_container_set_string_by_name(data, line, g_strdup(val));
            else
                gwy_container_remove_by_name(data, line);
            continue;
        }

        g_assert(pos && *pos == '[');
        pos++;
        dfield = NULL;
        gwy_container_gis_object_by_name(data, line, &dfield);

        id = 0;
        sscanf(line, "/%d", &id);

        /* get datafield parameters from already read values, failing back
         * to values of original data field */
        key = g_strconcat(line, "/xres", NULL);
        if (gwy_container_gis_string_by_name(data, key, &s))
            xres = atoi(s);
        else if (dfield)
            xres = gwy_data_field_get_xres(dfield);
        else {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("Missing data field width."));
            goto fail;
        }
        g_free(key);

        key = g_strconcat(line, "/yres", NULL);
        if (gwy_container_gis_string_by_name(data, key, &s))
            yres = atoi(s);
        else if (dfield)
            yres = gwy_data_field_get_yres(dfield);
        else {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("Missing data field height."));
            goto fail;
        }
        g_free(key);

        key = g_strconcat(line, "/xreal", NULL);
        if (gwy_container_gis_string_by_name(data, key, &s))
            xreal = g_ascii_strtod(s, NULL);
        else if (dfield)
            xreal = gwy_data_field_get_xreal(dfield);
        else {
            g_warning("Missing real data field width.");
            xreal = 1.0;   /* 0 could cause troubles */
        }
        g_free(key);

        key = g_strconcat(line, "/yreal", NULL);
        if (gwy_container_gis_string_by_name(data, key, &s))
            yreal = g_ascii_strtod(s, NULL);
        else if (dfield)
            yreal = gwy_data_field_get_yreal(dfield);
        else {
            g_warning("Missing real data field height.");
            yreal = 1.0;   /* 0 could cause troubles */
        }
        g_free(key);

        if (!(xres > 0 && yres > 0 && xreal > 0 && yreal > 0)) {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("Data field dimensions are not positive numbers."));
            goto fail;
        }

        key = g_strconcat(line, "/unit-xy", NULL);
        if (gwy_container_gis_string_by_name(data, key, &s))
            uxy = gwy_si_unit_new((const gchar*)s);
        else if (dfield) {
            uxy = gwy_data_field_get_si_unit_xy(dfield);
            uxy = gwy_si_unit_duplicate(uxy);
        }
        else {
            g_warning("Missing lateral units.");
            uxy = gwy_si_unit_new("m");
        }
        g_free(key);

        key = g_strconcat(line, "/unit-z", NULL);
        if (gwy_container_gis_string_by_name(data, key, &s))
            uz = gwy_si_unit_new((const gchar*)s);
        else if (dfield) {
            uz = gwy_data_field_get_si_unit_z(dfield);
            uz = gwy_si_unit_duplicate(uz);
        }
        else {
            g_warning("Missing value units.");
            uz = gwy_si_unit_new("m");
        }
        g_free(key);

        key = g_strconcat(line, "/title", NULL);
        title = NULL;
        gwy_container_gis_string_by_name(data, key, (const guchar**)&title);
        /* We got the contained string but that would disappear. */
        title = g_strdup(title);
        g_free(key);

        n = xres*yres*sizeof(gdouble);
        if ((gsize)(pos - buffer) + n + 3 > size) {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("End of file reached inside a data field."));
            goto fail;
        }
        dfield = GWY_DATA_FIELD(gwy_data_field_new(xres, yres, xreal, yreal,
                                                   FALSE));
        gwy_data_field_set_si_unit_xy(dfield, GWY_SI_UNIT(uxy));
        gwy_object_unref(uxy);
        gwy_data_field_set_si_unit_z(dfield, GWY_SI_UNIT(uz));
        gwy_object_unref(uz);
        d = gwy_data_field_get_data(dfield);
#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
        memcpy(d, pos, n);
#else
        gwy_memcpy_byte_swap(pos, (guint8*)d,
                             sizeof(gdouble), xres*yres, sizeof(gdouble)-1);
#endif
        pos += n;
        val = gwy_str_next_line(&pos);
        if (!gwy_strequal(val, "]]")) {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("Missing end of data field marker."));
            gwy_object_unref(dfield);
            goto fail;
        }
        gwy_container_remove_by_prefix(data, line);
        gwy_container_set_object_by_name(data, line, dfield);
        g_object_unref(dfield);

        if (title) {
            key = g_strconcat(line, "/title", NULL);
            gwy_container_set_string_by_name(data, key, title);
            g_free(key);
        }

        gwy_file_channel_import_log_add(data, id, NULL, filename);
    }
    return data;

fail:
    gwy_container_remove_by_prefix(data, NULL);
    g_object_unref(data);
    return NULL;
}