示例#1
0
static GwyContainer*
aist_load(const gchar *filename,
          G_GNUC_UNUSED GwyRunType mode,
          GError **error)
{
    AistContext context;
    guchar *buffer = NULL;
    const guchar *p;
    gsize remaining, size = 0;
    GError *err = NULL;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }

    p = buffer;
    remaining = size;

    context.container = gwy_container_new();
    context.filename = filename;
    context.channel_id = 0;
    context.graph_id = 0;
    read_aist_tree(&p, &remaining, &context);

    gwy_file_abandon_contents(buffer, size, NULL);

    if ((context.channel_id == 0) && (context.graph_id == 0)) {
        g_object_unref(context.container);
        context.container = NULL;
        err_NO_DATA(error);
    }

    return context.container;
}
示例#2
0
static GwyContainer*
x3p_load(const gchar *filename,
         G_GNUC_UNUSED GwyRunType mode,
         GError **error)
{
    GwyContainer *container = NULL;
    X3PFile x3pfile;
    unzFile zipfile;

    zipfile = gwyminizip_unzOpen(filename);
    if (!zipfile) {
        g_set_error(error, GWY_MODULE_FILE_ERROR,
                    GWY_MODULE_FILE_ERROR_SPECIFIC,
                    _("Minizip cannot open the file as a ZIP file."));
        return NULL;
    }

    gwy_clear(&x3pfile, 1);
    if (!x3p_parse_main(zipfile, &x3pfile, error))
        goto fail;

    if (!x3pfile.ndata) {
        err_NO_DATA(error);
        goto fail;
    }

    if (!x3pfile.datapos) {
        if (!read_binary_data(&x3pfile, zipfile, error))
            goto fail;
    }

    container = gwy_container_new();
    if (x3pfile.feature_type == X3P_FEATURE_SUR)
        create_images(&x3pfile, container);
    else if (x3pfile.feature_type == X3P_FEATURE_PRF)
        create_profiles(&x3pfile, container);
    else {
        g_assert_not_reached();
    }

fail:
    gwy_debug("calling unzClose()");
    unzClose(zipfile);
    x3p_file_free(&x3pfile);

    return container;
}
示例#3
0
static void
apedax_get_channels_data(unzFile uFile,
                         guchar *scanXmlContent,
                         gsize contentSize,
                         const gchar *filename,
                         GwyContainer *container,
                         GwyContainer *meta,
                         const APEScanSize *scanSize,
                         GError **error)
{
    xmlDocPtr doc = NULL;
    xmlNodePtr cur = NULL;
    xmlXPathContextPtr context;
    xmlXPathObjectPtr pathObj;
    xmlNodeSetPtr nodeset;
    xmlChar *buffer = NULL;
    gchar key[256];
    gint i;
    gint power10 = 0;
    gdouble scaleFactor = 1.0;
    GwySIUnit *zUnit;
    gchar *zUnitString = NULL;
    gchar *binFileName = NULL;
    GwyDataField *dfield;
    GwyContainer *tmp;

    if (scanXmlContent == NULL || contentSize == 0)
        return;

    gwy_clear(key, sizeof(key));

    doc = xmlReadMemory(scanXmlContent,
                        contentSize,
                        "scan.xml",
                        NULL,
                        0);

    if (doc == NULL)
        goto fail;

    context = xmlXPathNewContext(doc);

    if (context == NULL)
        goto fail;

    pathObj = xmlXPathEvalExpression("/Scan/Channels/Channel", context);

    if (pathObj == NULL) {
        xmlXPathFreeContext(context);
        goto fail;
    }

    /*There must be at least one channel*/
    if (xmlXPathNodeSetIsEmpty(pathObj->nodesetval)) {
        xmlXPathFreeObject(pathObj);
        xmlXPathFreeContext(context);
        err_NO_DATA(error);
        return;
    }

    nodeset = pathObj->nodesetval;

    if (nodeset->nodeNr <= 0)
        goto fail;

    for (i = 0; i < nodeset->nodeNr; i++) {

        cur = nodeset->nodeTab[i]->xmlChildrenNode;

        while (cur) {
            /*Label*/
            if (gwy_strequal((gchar*)cur->name, "Label")) {
                buffer = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
                g_snprintf(key, sizeof(key), "/%d/data/title", i);
                gwy_container_set_string_by_name(container, key, g_strdup(buffer));
                xmlFree(buffer);
            }
            /*Factor*/
            if (gwy_strequal((gchar*)cur->name, "ConversionFactor")) {
                buffer = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
                scaleFactor = g_ascii_strtod((gchar*)buffer, NULL);
                xmlFree(buffer);
            }
            /*Unit*/
            if (gwy_strequal((gchar*)cur->name, "DataUnit")) {
                buffer = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
                zUnitString = g_strdup((gchar*)buffer);
                zUnit = gwy_si_unit_new_parse(zUnitString, &power10);
                xmlFree(buffer);
                g_object_unref(zUnit);
            }
            /*Binary file name*/
            if (gwy_strequal((gchar*)cur->name, "BINFile")) {
                buffer = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
                binFileName = g_strdup((gchar*)buffer);
                xmlFree(buffer);
            }
            cur = cur->next;
        }

        scaleFactor *= pow(10.0, power10);

        dfield = apedax_get_data_field(uFile,
                                       binFileName,
                                       scanSize,
                                       zUnitString,
                                       scaleFactor,
                                       error);
        if (dfield) {
            g_snprintf(key, sizeof(key), "/%d/data", i);
            gwy_container_set_object_by_name(container, key, dfield);
            g_object_unref(dfield);
            gwy_file_channel_import_log_add(container, i, NULL,
                                            filename);

            tmp = gwy_container_duplicate(meta);
            g_snprintf(key, sizeof(key), "/%d/meta", i);
            gwy_container_set_object_by_name(container, key, tmp);
            g_object_unref(tmp);
        }
    }

    xmlXPathFreeObject(pathObj);
    xmlXPathFreeContext(context);
    xmlFreeDoc(doc);

    return;

fail:
    err_FILE_TYPE(error, FILE_TYPE);
    if (doc)
        xmlFreeDoc(doc);
    return;
}
示例#4
0
static GwyDataField*
apedax_get_data_field(unzFile uFile,
                      const gchar *chFileName,
                      const APEScanSize *scanSize,
                      gchar *zUnit,
                      gdouble scale,
                      GError **error)
{
    GwyDataField *dfield = NULL;
    GwySIUnit *xyUnit;
    GwySIUnit *zSIUnit;
    gdouble *data;
    guchar *buffer;
    gsize size, expectedSize;
    unz_file_info uFileInfo;

    /*Checking the dimensions*/
    if (err_DIMENSION(error, scanSize->XRes)) {
        return NULL;
    }

    if (err_DIMENSION(error, scanSize->YRes)) {
        return NULL;
    }

    /*If XReal it's not greater than 0 or XReal is NaN*/
    if (!(fabs(scanSize->XReal) > 0)) {
        err_UNSUPPORTED(error, "X scan size");
        return NULL;
    }

    /*Same for YReal*/
    if (!(fabs(scanSize->YReal) > 0)) {
        err_UNSUPPORTED(error, "Y scan size");
        return NULL;
    }

    expectedSize = scanSize->XRes * scanSize->YRes * sizeof(gdouble);

    unzGoToFirstFile(uFile);

    if (unzLocateFile(uFile, chFileName, 0) != UNZ_OK) {
        gwy_debug("Binary file not found");
        err_NO_DATA(error);
        return NULL;
    }

    if (unzGetCurrentFileInfo(uFile,
                              &uFileInfo,
                              NULL,
                              0L,
                              NULL,
                              0L,
                              NULL,
                              0L) != UNZ_OK) {
        err_NO_DATA(error);
        return NULL;
    }

    buffer = apedax_get_file_content(uFile, &uFileInfo, &size, error);

    if (buffer == NULL) {
        err_NO_DATA(error);
        return NULL;
    }

    if (err_SIZE_MISMATCH(error, expectedSize, size, FALSE)) {
       return NULL;
    }

    dfield = gwy_data_field_new(scanSize->XRes, scanSize->YRes,
                                scanSize->XReal, scanSize->YReal,
                                FALSE);

    data = gwy_data_field_get_data(dfield);

    xyUnit = gwy_data_field_get_si_unit_xy(dfield);
    gwy_si_unit_set_from_string(xyUnit, "m");

    zSIUnit = gwy_data_field_get_si_unit_z(dfield);
    gwy_si_unit_set_from_string(zSIUnit, zUnit);

    gwy_debug("Reading RAW data");

    gwy_convert_raw_data(buffer,
                         scanSize->XRes * scanSize->YRes,
                         1,
                         GWY_RAW_DATA_DOUBLE,
                         GWY_BYTE_ORDER_LITTLE_ENDIAN,
                         data,
                         scale,
                         0.0);

    return dfield;
}
示例#5
0
static GwyContainer*
mif_load(const gchar *filename,
         G_GNUC_UNUSED GwyRunType mode,
         GError **error)
{
    GwyContainer *container = NULL;
    guchar *buffer = NULL;
    gsize size = 0;
    GError *err = NULL;
    MIFFile mfile;
    GwyDataField *dfield;
    guint i;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }

    if (!mif_read_header(buffer, size, &mfile.header, error)) {
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }
    /* TODO: Check file version */
    if (!mif_read_image_items(mfile.images, buffer, size, &mfile.header.info,
                              error)) {
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }

    /* FIXME: Only v1.7! */
    for (i = 0; i < mfile.header.nimages; i++) {
        MIFInfoItem *item = mfile.images + i;
        MIFImageHeader image_header;
        MIFBlock raster, macro_geometry, preview, image, curve, calc;
        guint ncalculations;
        const guchar *p = buffer + item->image.offset;
        GQuark quark;

        if (!item->image.size)
            continue;
        if (item->image.offset > size
            || item->image.size > size
            || item->image.offset + item->image.size > size) {
            continue;
        }

        /* XXX: We cannot use item->image.size because it's bogus, i.e.
         * too short.  Apparently there is some unaccounted-for space until
         * the next block starts, 120 bytes for v1.7 files, after the image
         * header which is in fact still occupied by the image header.
         * MIFBlock says 714 bytes but the true size is 834 = 714 + 120. */
        if (!mif_read_image_header(&image_header, &p, size - (p - buffer),
                                   mfile.header.file_version,
                                   error))
            continue;

        if (p - buffer + 52 > size)
            continue;

        mif_read_block(&raster, "raster", &p);
        mif_read_block(&macro_geometry, "macro_geometry", &p);
        mif_read_block(&preview, "preview", &p);
        mif_read_block(&image, "image", &p);
        mif_read_block(&curve, "curve", &p);
        ncalculations = gwy_get_guint32_le(&p);
        mif_read_block(&calc, "calc", &p);

        gwy_debug("image header true size: %zu",
                  (gsize)(p - (buffer + item->image.offset)));

        dfield = mif_read_data_field(&image_header, &image, buffer, size, NULL);
        if (!dfield)
            continue;

        if (!container)
            container = gwy_container_new();

        quark = gwy_app_get_data_key_for_id(i);
        gwy_container_set_object(container, quark, dfield);
        g_object_unref(dfield);
        gwy_app_channel_title_fall_back(container, i);
    }

    if (!container)
        err_NO_DATA(error);

    gwy_file_abandon_contents(buffer, size, NULL);
    return container;
}
示例#6
0
static GwyContainer*
rhkspm32_load(const gchar *filename,
              G_GNUC_UNUSED GwyRunType mode,
              GError **error)
{
    GArray *rhkfile;
    RHKPage *rhkpage;
    GwyContainer *meta, *container = NULL;
    guchar *buffer = NULL;
    gsize size = 0;
    GError *err = NULL;
    GwyDataField *dfield = NULL;
    gsize totalpos, pagesize;
    GString *key;
    guint i;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }
    if (size < HEADER_SIZE) {
        err_TOO_SHORT(error);
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }

    // niv - rhkfile is an array of rhkpage's, but buffer is where the actual
    // raw file data is stored
    rhkfile = g_array_new(FALSE, TRUE, sizeof(RHKPage));
    totalpos = 0;

    while (totalpos < size) {
        g_array_set_size(rhkfile, rhkfile->len + 1);
        rhkpage = &g_array_index(rhkfile, RHKPage, rhkfile->len - 1);
        rhkpage->buffer = buffer + totalpos;
        // niv - if the header seems illegal, skip all the next ones as well
        // (and cancel the element addition to the g_array)
        if (!rhkspm32_read_header(rhkpage, &err)) {
            g_warning("failed to read rhk header after %u", rhkfile->len);
            g_array_set_size(rhkfile, rhkfile->len - 1);
            break;
        }

        pagesize = rhkpage->data_offset
                   + rhkpage->item_size*rhkpage->xres*rhkpage->yres;
        if (size < totalpos + pagesize) {
            rhkspm32_free(rhkpage);
            g_array_set_size(rhkfile, rhkfile->len - 1);
            break;
        }

        totalpos += pagesize;
    }

    /* Be tolerant and don't fail when we were able to import at least
     * something */
    if (!rhkfile->len) {
        if (err)
            g_propagate_error(error, err);
        else
            err_NO_DATA(error);
        gwy_file_abandon_contents(buffer, size, NULL);
        g_array_free(rhkfile, TRUE);
        return NULL;
    }
    g_clear_error(&err);

    container = gwy_container_new();
    key = g_string_new(NULL);
    for (i = 0; i < rhkfile->len; i++) {
        const gchar *cs;
        gchar *s;

        gwy_debug("rhk-spm32: processing page %d of %d\n", i+1, rhkfile->len);
        rhkpage = &g_array_index(rhkfile, RHKPage, i);
        if (rhkpage->type == RHK_TYPE_IMAGE) { // niv - just leaving this alone
            dfield = rhkspm32_read_data(rhkpage);
            g_string_printf(key, "/%d/data", i);
            gwy_container_set_object_by_name(container, key->str, dfield);
            g_object_unref(dfield);
            g_string_append(key, "/title");
            cs = gwy_enum_to_string(rhkpage->scan,
                                    scan_directions,
                                    G_N_ELEMENTS(scan_directions));
            if (rhkpage->label) {
                if (cs)
                    s = g_strdup_printf("%s [%s]", rhkpage->label, cs);
                else
                    s = g_strdup(rhkpage->label);
                gwy_container_set_string_by_name(container, key->str, s);
            }
            else
                gwy_app_channel_title_fall_back(container, i);

            gwy_file_channel_import_log_add(container, i, NULL,
                                            filename);
        }
        else if (rhkpage->type == RHK_TYPE_LINE) { // niv - after omicron.c

            GwySpectra* spectra;
            GwyGraphModel *gmodel;

            spectra = rhkspm32_read_spectra(rhkpage);
            /* converting to graphs, as there is no point in leaving these as
             * sps - no xy coordinates, so the spectro tool is kinda clueless */
            gwy_debug("processing graph in page %d\n", i);
            if ((gmodel = spectra_to_graph(spectra)) != NULL) {
                gchar *container_key = NULL;
                /* add gmodel to container */
                container_key = g_strdup_printf("%s/%d", GRAPH_PREFIX, i);
                gwy_container_set_object_by_name(container, container_key,
                                                gmodel);
                g_free(container_key);
            }
            g_object_unref(gmodel);
            g_object_unref(spectra);
        }
        gwy_debug("rhk-spm32: finished parsing page %d \n", i);
        meta = rhkspm32_get_metadata(rhkpage);
        if (rhkpage->type == RHK_TYPE_IMAGE) {
            /* this doesn't really work, but at least the meta data stays
               with the graph, even if the metadata viewer won't show it*/
            g_string_printf(key, "/%d/meta", i);
        }
        else if (rhkpage->type == RHK_TYPE_LINE) {
            g_string_printf(key, "%s/%d/meta", GRAPH_PREFIX, i);
        }
        gwy_container_set_object_by_name(container, key->str, meta);
        g_object_unref(meta);
    }
    g_string_free(key, TRUE);

    gwy_file_abandon_contents(buffer, size, NULL);
    for (i = 0; i < rhkfile->len; i++)
        rhkspm32_free(&g_array_index(rhkfile, RHKPage, i));
    g_array_free(rhkfile, TRUE);

    return container;
}
示例#7
0
static GwyContainer*
gxsm_load(const gchar *filename,
          G_GNUC_UNUSED GwyRunType mode,
          GError **error)
{
    static const gchar *dimensions[] = { "time", "value", "dimy", "dimx" };
    GwyContainer *data = NULL;
    GwyDataField *dfield;
    GwySIUnit *siunit;
    NetCDF cdffile;
    const NetCDFDim *dim;
    const NetCDFVar *var;
    const NetCDFAttr *attr;
    gdouble real;
    gint i, power10;

    if (!cdffile_load(&cdffile, filename, error))
        return NULL;

    if (cdffile.nrecs) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("NetCDF records are not supported."));
        goto gxsm_load_fail;
    }

    /* Look for variable "H" or "FloatField".  This seems to be how GXSM calls
     * data. */
    if (!(var = cdffile_get_var(&cdffile, "H"))
        && !(var = cdffile_get_var(&cdffile, "FloatField"))) {
        err_NO_DATA(error);
        goto gxsm_load_fail;
    }

    /* Check the dimensions.  We only know how to handle time=1 and value=1. */
    for (i = 0; i < var->ndims; i++) {
        dim = cdffile.dims + var->dimids[i];
        if (!gwy_strequal(dim->name, dimensions[i])
            || (i < 2 && dim->length != 1)) {
            /* XXX */
            err_NO_DATA(error);
            goto gxsm_load_fail;
        }
    }

    if (err_DIMENSION(error, cdffile.dims[var->dimids[3]].length)
        || err_DIMENSION(error, cdffile.dims[var->dimids[2]].length))
        goto gxsm_load_fail;

    dfield = read_data_field((const guchar*)(cdffile.buffer + var->begin),
                             cdffile.dims[var->dimids[3]].length,
                             cdffile.dims[var->dimids[2]].length,
                             var->type);

    if ((siunit = read_real_size(&cdffile, "rangex", &real, &power10))) {
        /* Use negated positive conditions to catch NaNs */
        if (!((real = fabs(real)) > 0)) {
            g_warning("Real x size is 0.0, fixing to 1.0");
            real = 1.0;
        }
        gwy_data_field_set_xreal(dfield, real*pow10(power10));
        gwy_data_field_set_si_unit_xy(dfield, siunit);
        g_object_unref(siunit);
    }

    if ((siunit = read_real_size(&cdffile, "rangey", &real, &power10))) {
        /* Use negated positive conditions to catch NaNs */
        if (!((real = fabs(real)) > 0)) {
            g_warning("Real y size is 0.0, fixing to 1.0");
            real = 1.0;
        }
        gwy_data_field_set_yreal(dfield, real*pow10(power10));
        /* must be the same gwy_data_field_set_si_unit_xy(dfield, siunit); */
        g_object_unref(siunit);
    }

    if ((siunit = read_real_size(&cdffile, "rangez", &real, &power10))) {
        /* rangez seems to be some bogus value, take only units */
        gwy_data_field_set_si_unit_z(dfield, siunit);
        gwy_data_field_multiply(dfield, pow10(power10));
        g_object_unref(siunit);
    }
    if ((siunit = read_real_size(&cdffile, "dz", &real, &power10))) {
        /* on the other hand the units seem to be bogus here, take the range */
        gwy_data_field_multiply(dfield, real);
        g_object_unref(siunit);
    }

    data = gwy_container_new();
    gwy_container_set_object_by_name(data, "/0/data", dfield);
    g_object_unref(dfield);

    if ((attr = cdffile_get_attr(var->attrs, var->nattrs, "long_name"))
        && attr->type == NC_CHAR
        && attr->nelems) {
        gwy_container_set_string_by_name(data, "/0/data/title",
                                         g_strndup(attr->values, attr->nelems));
    }

gxsm_load_fail:
    gwy_file_abandon_contents(cdffile.buffer, cdffile.size, NULL);
    cdffile_free(&cdffile);

    return data;
}
static GwyContainer*
rhk_sm4_load(const gchar *filename,
             G_GNUC_UNUSED GwyRunType mode,
             GError **error)
{
    RHKFile rhkfile;
    RHKObject *obj, o;
    GwyContainer *meta, *container = NULL;
    guchar *buffer = NULL;
    gsize size = 0;
    GError *err = NULL;
    const guchar *p;
    GString *key = NULL;
    guint i, imageid = 0, graphid = 0;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }

    gwy_clear(&rhkfile, 1);
    if (size < HEADER_SIZE) {
        err_TOO_SHORT(error);
        goto fail;
    }

    /* File header */
    p = buffer + MAGIC_OFFSET + MAGIC_TOTAL_SIZE;
    rhkfile.page_count = gwy_get_guint32_le(&p);
    rhkfile.object_count = gwy_get_guint32_le(&p);
    rhkfile.object_field_size = gwy_get_guint32_le(&p);
    gwy_debug("page_count: %u, object_count: %u, object_field_size: %u",
              rhkfile.page_count, rhkfile.object_count,
              rhkfile.object_field_size);
    if (rhkfile.object_field_size != OBJECT_SIZE)
        g_warning("Object field size %u differs from %u",
                  rhkfile.object_field_size, OBJECT_SIZE);
    rhkfile.reserved1 = gwy_get_guint32_le(&p);
    rhkfile.reserved2 = gwy_get_guint32_le(&p);

    /* Header objects */
    if (!(rhkfile.objects = rhk_sm4_read_objects(buffer, p, size,
                                                 rhkfile.object_count,
                                                 RHK_OBJECT_FILE_HEADER,
                                                 error)))
        goto fail;

    /* Find page index header */
    if (!(obj = rhk_sm4_find_object(rhkfile.objects, rhkfile.object_count,
                                    RHK_OBJECT_PAGE_INDEX_HEADER,
                                    RHK_OBJECT_FILE_HEADER, error))
        || !rhk_sm4_read_page_index_header(&rhkfile.page_index_header,
                                           obj, buffer, size, error))
        goto fail;

    /* There, find the page index array.  That's a single object in the object
     * list but it contains a page_count-long sequence of page indices. */
    rhkfile.page_indices = g_new0(RHKPageIndex,
                                  rhkfile.page_index_header.page_count);
    if (!(obj = rhk_sm4_find_object(rhkfile.page_index_header.objects,
                                    rhkfile.page_index_header.object_count,
                                    RHK_OBJECT_PAGE_INDEX_ARRAY,
                                    RHK_OBJECT_PAGE_INDEX_HEADER, error)))
        goto fail;

    o = *obj;
    for (i = 0; i < rhkfile.page_index_header.page_count; i++) {
        if (!rhk_sm4_read_page_index(rhkfile.page_indices + i, &o,
                                     buffer, size, error))
            goto fail;

        /* Carefully move to the next page index */
        o.offset += o.size + OBJECT_SIZE*rhkfile.page_indices[i].object_count;
    }

    container = gwy_container_new();
    key = g_string_new(NULL);

    /* Read pages */
    for (i = 0; i < rhkfile.page_index_header.page_count; i++) {
        RHKPageIndex *pi = rhkfile.page_indices + i;
        RHKPage *page = &pi->page;

        /* Page must contain header */
        if (!(obj = rhk_sm4_find_object(pi->objects, pi->object_count,
                                        RHK_OBJECT_PAGE_HEADER,
                                        RHK_OBJECT_PAGE_INDEX, error))
            || !rhk_sm4_read_page_header(page, obj, buffer, size, error))
            goto fail;

        /* Page must contain data */
        if (!(obj = rhk_sm4_find_object(pi->objects, pi->object_count,
                                        RHK_OBJECT_PAGE_DATA,
                                        RHK_OBJECT_PAGE_INDEX, error))
            || !rhk_sm4_read_page_data(page, obj, buffer, error))
            goto fail;

        /* Page may contain strings */
        if (!(obj = rhk_sm4_find_object(page->objects, page->object_count,
                                        RHK_OBJECT_STRING_DATA,
                                        RHK_OBJECT_PAGE_HEADER, NULL))
            || !rhk_sm4_read_string_data(page, obj, pi->page.string_count,
                                         buffer)) {
            g_warning("Failed to read string data in page %u", i);
        }

        /* Read the data */
        if (pi->data_type == RHK_DATA_IMAGE) {
            GwyDataField *dfield = rhk_sm4_page_to_data_field(page);
            GQuark quark = gwy_app_get_data_key_for_id(imageid);
            const gchar *scandir, *name;
            gchar *title;

            gwy_container_set_object(container, quark, dfield);
            g_object_unref(dfield);

            if ((name = page->strings[RHK_STRING_LABEL])) {
                scandir = gwy_enum_to_string(page->scan_dir, scan_directions,
                                             G_N_ELEMENTS(scan_directions));
                g_string_assign(key, g_quark_to_string(quark));
                g_string_append(key, "/title");
                if (scandir && *scandir)
                    title = g_strdup_printf("%s [%s]", name, scandir);
                else
                    title = g_strdup(name);
                gwy_container_set_string_by_name(container, key->str, title);
            }

            meta = rhk_sm4_get_metadata(pi, page);
            g_string_printf(key, "/%u/meta", imageid);
            gwy_container_set_object_by_name(container, key->str, meta);
            g_object_unref(meta);

            imageid++;
        }
        else if (pi->data_type == RHK_DATA_LINE) {
            GwyGraphModel *gmodel;
            RHKSpecDriftHeader drift_header;
            RHKSpecInfo spec_info;
            G_GNUC_UNUSED gboolean have_header = FALSE, have_info = FALSE;

            gwy_debug("page_type %u", page->page_type);
            gwy_debug("line_type %u", page->line_type);
            gwy_debug("page_sizes %u %u", page->x_size, page->y_size);
            /* Page may contain drift header */
            if ((obj = rhk_sm4_find_object(page->objects, page->object_count,
                                           RHK_OBJECT_SPEC_DRIFT_HEADER,
                                           RHK_OBJECT_PAGE_HEADER, NULL))
                && rhk_sm4_read_drift_header(&drift_header, obj, buffer)) {
                gwy_debug("drift_header OK");
                have_header = TRUE;
            }
            if ((obj = rhk_sm4_find_object(page->objects, page->object_count,
                                           RHK_OBJECT_SPEC_DRIFT_DATA,
                                           RHK_OBJECT_PAGE_HEADER, NULL))
                && rhk_sm4_read_spec_info(&spec_info, obj, buffer)) {
                gwy_debug("spec_info OK");
                have_info = TRUE;
            }
            /* FIXME: RHK_STRING_PLL_PRO_STATUS may contain interesting
             * metadata.  But we have not place where to put it. */

            if ((gmodel = rhk_sm4_page_to_graph_model(page))) {
                graphid++;
                gwy_container_set_object(container,
                                         gwy_app_get_graph_key_for_id(graphid),
                                         gmodel);
                g_object_unref(gmodel);
            }
        }
    }

    if (!imageid && !graphid)
        err_NO_DATA(error);

fail:
    gwy_file_abandon_contents(buffer, size, NULL);
    rhk_sm4_free(&rhkfile);
    if (!imageid && !graphid) {
        gwy_object_unref(container);
    }
    if (key)
        g_string_free(key, TRUE);

    return container;
}
示例#9
0
static GwyContainer*
mprofile_load(const gchar *filename,
              G_GNUC_UNUSED GwyRunType mode,
              GError **error)
{
    MProFile mprofile;
    GwyContainer *meta, *container = NULL;
    GwyDataField *dfield = NULL, *vpmask = NULL;
    guchar *buffer = NULL;
    gsize size = 0;
    GError *err = NULL;
    gsize expected;
    GString *key;
    const gchar *title;
    guint n, i;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }

    if (!mprofile_read_header(buffer, size, &mprofile, error))
        return NULL;

    expected = mprofile.header_size
               + 2*mprofile.nbuckets*mprofile.intens_xres*mprofile.intens_yres
               + 4*mprofile.phase_xres*mprofile.phase_yres;
    if (err_SIZE_MISMATCH(error, expected, size, TRUE)) {
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }

    n = fill_data_fields(&mprofile, buffer);
    gwy_file_abandon_contents(buffer, size, NULL);
    if (!n) {
        err_NO_DATA(error);
        return NULL;
    }

    key = g_string_new(NULL);
    container = gwy_container_new();
    for (i = 0; i < n; i++) {
        if (i > 0) {
            dfield = mprofile.intensity_data[i-1];
            vpmask = mprofile.intensity_mask[i-1];
            title = "Intensity";
        }
        else {
            dfield = mprofile.phase_data;
            vpmask = mprofile.phase_mask;
            title = "Phase";
        }
        g_string_printf(key, "/%d/data", i);
        gwy_container_set_object_by_name(container, key->str, dfield);
        g_string_printf(key, "/%d/data/title", i);
        gwy_container_set_string_by_name(container, key->str, g_strdup(title));
        if (vpmask) {
            g_string_printf(key, "/%d/mask", i);
            gwy_container_set_object_by_name(container, key->str, vpmask);
        }

        meta = mprofile_get_metadata(&mprofile);
        g_string_printf(key, "/%d/meta", i);
        gwy_container_set_object_by_name(container, key->str, meta);
        g_object_unref(meta);

    }
    g_string_free(key, TRUE);

    for (n = 0; n < mprofile.nbuckets; n++) {
        gwy_object_unref(mprofile.intensity_data[n]);
        gwy_object_unref(mprofile.intensity_mask[n]);
    }
    gwy_object_unref(mprofile.phase_data);
    gwy_object_unref(mprofile.phase_mask);

    return container;
}
示例#10
0
static GwyContainer*
rawxyz_load(const gchar *filename,
            GwyRunType mode,
            GError **error)
{
    GwyContainer *settings, *container = NULL;
    GwySurface *surface = NULL;
    RawXYZArgs args;
    GwySIUnit *unit;
    gint power10;
    gdouble q;
    gchar *buffer = NULL;
    gsize size;
    GError *err = NULL;
    gboolean ok;
    guint k;

    if (!g_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        goto fail;
    }

    surface = read_xyz_points(buffer);
    g_free(buffer);
    if (!surface->n) {
        err_NO_DATA(error);
        goto fail;
    }

    settings = gwy_app_settings_get();
    rawxyz_load_args(settings, &args);
    if (mode == GWY_RUN_INTERACTIVE) {
        ok = rawxyz_dialog(&args, surface);
        rawxyz_save_args(settings, &args);
        if (!ok) {
            err_CANCELLED(error);
            goto fail;
        }
    }

    unit = gwy_si_unit_new_parse(args.xy_units, &power10);
    if (power10) {
        q = pow10(power10);
        for (k = 0; k < surface->n; k++) {
            surface->data[k].x *= q;
            surface->data[k].y *= q;
        }
        gwy_surface_invalidate(surface);
    }
    gwy_serializable_clone(G_OBJECT(unit),
                           G_OBJECT(gwy_surface_get_si_unit_xy(surface)));

    unit = gwy_si_unit_new_parse(args.z_units, &power10);
    if (power10) {
        q = pow10(power10);
        for (k = 0; k < surface->n; k++)
            surface->data[k].z *= q;
        gwy_surface_invalidate(surface);
    }
    gwy_serializable_clone(G_OBJECT(unit),
                           G_OBJECT(gwy_surface_get_si_unit_z(surface)));

    container = gwy_container_new();
    gwy_container_set_object(container, gwy_app_get_surface_key_for_id(0),
                             surface);
    gwy_app_xyz_title_fall_back(container, 0);
    gwy_file_xyz_import_log_add(container, 0, NULL, filename);

fail:
    g_free(args.xy_units);
    g_free(args.z_units);
    GWY_OBJECT_UNREF(surface);

    return container;
}
示例#11
0
static GwyContainer*
omicron_load(const gchar *filename,
             G_GNUC_UNUSED GwyRunType mode,
             GError **error)
{
    OmicronFile ofile;
    GwyContainer *container = NULL, *meta;
    gchar *text = NULL;
    GError *err = NULL;
    GwyDataField *dfield = NULL;
    GwySpectra *spectra = NULL;
    gchar key[32];
    guint i;

    /* @text must not be destroyed while @ofile is still in used because
     * all strings are only references there */
    if (!g_file_get_contents(filename, &text, NULL, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }

    gwy_clear(&ofile, 1);
    ofile.filename = filename;
    if (!omicron_read_header(text, &ofile, error))
        goto fail;

    if (!ofile.topo_channels || !ofile.topo_channels->len) {
        err_NO_DATA(error);
        goto fail;
    }

    container = gwy_container_new();

    /* First Load the Topographic Data */
    for (i = 0; i < ofile.topo_channels->len; i++) {
        OmicronTopoChannel *channel;

        channel = g_ptr_array_index(ofile.topo_channels, i);
        dfield = omicron_read_data(&ofile, channel, error);
        if (!dfield) {
            gwy_object_unref(container);
            goto fail;
        }

        g_snprintf(key, sizeof(key), "/%u/data", i);
        gwy_container_set_object_by_name(container, key, dfield);
        g_object_unref(dfield);

        if (channel->name) {
            gchar *s;

            g_snprintf(key, sizeof(key), "/%u/data/title", i);
            if (channel->scandir == SCAN_FORWARD)
                s = g_strdup_printf("%s (Forward)", channel->name);
            else if (channel->scandir == SCAN_BACKWARD)
                s = g_strdup_printf("%s (Backward)", channel->name);
            else
                s = g_strdup(channel->name);
            gwy_container_set_string_by_name(container, key, s);
        }

        if ((meta = omicron_make_meta(&ofile))) {
            g_snprintf(key, sizeof(key), "/%u/meta", i);
            gwy_container_set_object_by_name(container, key, meta);
            g_object_unref(meta);
        }
    }

    /* Then load the spectroscopy data. */
    /*
     * There are two types of spectroscopy file:
     *
     * a) Single Point Spectroscopy Files
     * Single point which is stored by SCALA as an ascii file.  Any number of
     * single point spectrums may be aquired, but the number is normally
     * quite small. These files are identified by their filename *.cs[0..3]
     *
     * b) Binary Spectroscopy Files
     * When large numbers of spectra are aquired on a regular grid they are
     * stored in BE binary. These data are aquired during the scan, and so
     * can be aquired during the forward scan or the backward scan.
     *
     * Forwards scan files can be indentified from their filename *.sf[0..3]
     * Backward scan files can be indentified from their filename *.sb[0..3]
     */
    if (ofile.spectro_channels) {
        for (i = 0; i < ofile.spectro_channels->len; i++) {
            OmicronSpectroChannel *channel;

            channel = g_ptr_array_index(ofile.spectro_channels, i);
            if (omicron_has_extension(channel->filename, "cs")) {
                gchar *t;
                GQuark quark;

                spectra = omicron_read_cs_data(&ofile, channel, error);
                if (!spectra) {
                    gwy_object_unref(container);
                    goto fail;
                }

                if (!gwy_spectra_get_n_spectra(spectra)) {
                    gwy_debug("Spectra %u is empty, ignoring", i);
                    g_object_unref(spectra);
                    continue;
                }

                /* FIXME */
                t = g_strconcat(channel->chan, "-", channel->param, NULL);
                gwy_spectra_set_title(spectra, t);
                g_free(t);
                quark = gwy_app_get_spectra_key_for_id(i);
                gwy_container_set_object(container, quark, spectra);
                g_object_unref(spectra);
            }
            else if (omicron_has_extension(channel->filename, "sf")
                     || omicron_has_extension(channel->filename, "sb")) {
                /* FIXME */
            }
            else {
                g_warning("Cannot determine spectra type of %s",
                          channel->filename);
            }
        }
    }

fail:
    omicron_file_free(&ofile);
    g_free(text);

    return container;
}
示例#12
0
static GwyGraphModel*
sensofar_read_profile(SensofarDataDesc *data_desc,
                      const guchar **p,
                      gsize size,
                      GError **error)
{
    GwyGraphModel *gmodel;
    GwyGraphCurveModel *gcmodel;
    guint xres, yres, j, n;
    GwySIUnit *units = NULL;
    gdouble *xdata, *ydata;
    gdouble dx;

    yres = gwy_get_guint32_le(p);
    if (yres != 1)
        g_warning("ysize is not 1 for profile");
    xres = gwy_get_guint32_le(p);
    gwy_debug("Data size: %dx%d", xres, yres);
    if (err_SIZE_MISMATCH(error, xres*yres*sizeof(gfloat),
                          size - 2*sizeof(guint32), FALSE))
        return NULL;
    if (err_DIMENSION(error, xres) || err_DIMENSION(error, yres))
        return NULL;
    if (!((data_desc->axes_config.mppx
           = fabs(data_desc->axes_config.mppx)) > 0)) {
        g_warning("Real x size is 0.0, fixing to 1.0");
        data_desc->axes_config.mppx = 1.0;
    }

    xdata = g_new(gdouble, xres);
    ydata = g_new(gdouble, xres);
    dx = data_desc->axes_config.mppx * Micrometer;

    for (j = n = 0; j < xres; j++) {
        gdouble v = gwy_get_gfloat_le(p);
        if (v != 1000001.0) {
            xdata[n] = dx*j;
            ydata[n] = v*Micrometer;
            n++;
        }
    }

    if (!n) {
        g_free(xdata);
        g_free(ydata);
        err_NO_DATA(error);
        return NULL;
    }

    gmodel = gwy_graph_model_new();
    g_object_set(gmodel, "title", _("Profile"), NULL);

    units = gwy_si_unit_new("m"); // values are in um only
    g_object_set(gmodel, "si-unit-x", units, NULL);
    g_object_unref(units);

    units = gwy_si_unit_new("m"); // values are in um only
    g_object_set(gmodel, "si-unit-y", units, NULL);
    g_object_unref(units);

    gcmodel = gwy_graph_curve_model_new();
    gwy_graph_curve_model_set_data(gcmodel, xdata, ydata, n);
    g_object_set(gcmodel,
                 "mode", GWY_GRAPH_CURVE_LINE,
                 "description", _("Profile"),
                 NULL);
    gwy_graph_model_add_curve(gmodel, gcmodel);
    g_object_unref(gcmodel);

    return gmodel;
}
示例#13
0
static GwyContainer*
apefile_load(const gchar *filename,
             G_GNUC_UNUSED GwyRunType mode,
             GError **error)
{
    APEFile apefile;
    GwyContainer *meta, *container = NULL;
    guchar *buffer = NULL;
    const guchar *p;
    gsize size = 0;
    GError *err = NULL;
    GwyDataField *dfield = NULL;
    guint b, i, n;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }
    p = buffer;
    apefile.version = *(p++);
    if (size < 1294) {
        err_TOO_SHORT(error);
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }

    apefile.spm_mode = *(p++);
    p += 2;   /* Skip VisualBasic VARIANT type type */
    apefile.scan_date = gwy_get_gdouble_le(&p);
    apefile.maxr_x = gwy_get_gfloat_le(&p);
    apefile.maxr_y = gwy_get_gfloat_le(&p);
    apefile.x_offset = gwy_get_guint32_le(&p);
    apefile.y_offset = gwy_get_guint32_le(&p);
    apefile.size_flag = gwy_get_guint16_le(&p);
    apefile.res = 16 << apefile.size_flag;
    if (err_DIMENSION(error, apefile.res)) {
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }
    apefile.acquire_delay = gwy_get_gfloat_le(&p);
    apefile.raster_delay = gwy_get_gfloat_le(&p);
    apefile.tip_dist = gwy_get_gfloat_le(&p);
    apefile.v_ref = gwy_get_gfloat_le(&p);
    if (apefile.version == 1) {
        apefile.vpmt1 = gwy_get_guint16_le(&p);
        apefile.vpmt2 = gwy_get_guint16_le(&p);
    }
    else {
        apefile.vpmt1 = gwy_get_gfloat_le(&p);
        apefile.vpmt2 = gwy_get_gfloat_le(&p);
    }
    apefile.remark = g_strndup(p, 120);
    p += 120;
    apefile.x_piezo_factor = gwy_get_guint32_le(&p);
    apefile.y_piezo_factor = gwy_get_guint32_le(&p);
    apefile.z_piezo_factor = gwy_get_guint32_le(&p);
    apefile.hv_gain = gwy_get_gfloat_le(&p);
    apefile.freq_osc_tip = gwy_get_gdouble_le(&p);
    apefile.rotate = gwy_get_gfloat_le(&p);
    apefile.slope_x = gwy_get_gfloat_le(&p);
    apefile.slope_y = gwy_get_gfloat_le(&p);
    apefile.topo_means = gwy_get_guint16_le(&p);
    apefile.optical_means = gwy_get_guint16_le(&p);
    apefile.error_means = gwy_get_guint16_le(&p);
    /*
    g_printerr("%04x %04x %04x\n",
               apefile.topo_means, apefile.optical_means, apefile.error_means);
               */
    apefile.channels = gwy_get_guint32_le(&p);
    apefile.ndata = 0;
    for (b = apefile.channels; b; b = b >> 1)
        apefile.ndata += (b & 1);
    apefile.range_x = gwy_get_gfloat_le(&p);
    apefile.range_y = gwy_get_gfloat_le(&p);
    apefile.subversion = gwy_get_guint16_le(&p);
    /* Read everything since the header is long enough, check the version
     * later when we decide whether to use these values or not. */
    /* Since 2.1 */
    apefile.hv_gain_z = gwy_get_gfloat_le(&p);
    /* Since 2.2 */
    apefile.fast2_0 = gwy_get_gdouble_le(&p);
    apefile.fast2_1 = gwy_get_gdouble_le(&p);
    apefile.fast2_2 = gwy_get_gdouble_le(&p);
    apefile.fast2_3 = gwy_get_gdouble_le(&p);
    /* Since 2.3 */
    apefile.pg850_image = !!gwy_get_guint16_le(&p);
    /* Since 2.4 */
    apefile.xy_hv_status = gwy_get_gint16_le(&p);
    apefile.z_hv_status = gwy_get_gint16_le(&p);
    /* reserved */
    p += 2;

    apefile.xreal = apefile.maxr_x * apefile.x_piezo_factor * apefile.range_x
                    * apefile.hv_gain/65535.0 * 1e-9;
    apefile.yreal = apefile.maxr_y * apefile.y_piezo_factor * apefile.range_y
                    * apefile.hv_gain/65535.0 * 1e-9;
    /* Use negated positive conditions to catch NaNs */
    if (!((apefile.xreal = fabs(apefile.xreal)) > 0)) {
        g_warning("Real x size is 0.0, fixing to 1.0");
        apefile.xreal = 1.0;
    }
    if (!((apefile.yreal = fabs(apefile.yreal)) > 0)) {
        g_warning("Real y size is 0.0, fixing to 1.0");
        apefile.yreal = 1.0;
    }

    gwy_debug("version = %u.%u, spm_mode = %u",
              apefile.version, apefile.subversion, apefile.spm_mode);
    gwy_debug("scan_date = %f", apefile.scan_date);
    gwy_debug("maxr_x = %g, maxr_y = %g", apefile.maxr_x, apefile.maxr_y);
    gwy_debug("x_offset = %u, y_offset = %u",
              apefile.x_offset, apefile.y_offset);
    gwy_debug("size_flag = %u", apefile.size_flag);
    gwy_debug("acquire_delay = %g, raster_delay = %g, tip_dist = %g",
              apefile.acquire_delay, apefile.raster_delay, apefile.tip_dist);
    gwy_debug("v_ref = %g, vpmt1 = %g, vpmt2 = %g",
              apefile.v_ref, apefile.vpmt1, apefile.vpmt2);
    gwy_debug("x_piezo_factor = %u, y_piezo_factor = %u, z_piezo_factor = %u",
              apefile.x_piezo_factor, apefile.y_piezo_factor,
              apefile.z_piezo_factor);
    gwy_debug("hv_gain = %g, freq_osc_tip = %g, rotate = %g",
              apefile.hv_gain, apefile.freq_osc_tip, apefile.rotate);
    gwy_debug("slope_x = %g, slope_y = %g",
              apefile.slope_x, apefile.slope_y);
    gwy_debug("topo_means = %u, optical_means = %u, error_means = %u",
              apefile.topo_means, apefile.optical_means, apefile.error_means);
    gwy_debug("channel bitmask = %03x, ndata = %u",
              apefile.channels, apefile.ndata);
    gwy_debug("range_x = %g, range_y = %g",
              apefile.range_x, apefile.range_y);

    n = (apefile.res + 1)*(apefile.res + 1)*sizeof(float);
    if (size - (p - buffer) != n*apefile.ndata) {
        g_warning("Expected data size %u, but it's %u.",
                  n*apefile.ndata, (guint)(size - (p - buffer)));
        apefile.ndata = MIN(apefile.ndata, (size - (p - buffer))/n);
    }
    if (!apefile.ndata) {
        err_NO_DATA(error);
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }
    fill_data_fields(&apefile, p);
    gwy_file_abandon_contents(buffer, size, NULL);

    container = gwy_container_new();
    /* All metadata seems to be per-file (global) */
    meta = apefile_get_metadata(&apefile);
    for (b = apefile.channels, n = 0, i = 0; b; b = b >> 1, i++) {
        GwyContainer *tmp;
        gchar *title;
        gchar key[32];

        if (!(b & 1))
            continue;

        g_snprintf(key, sizeof(key), "/%d/data", n);
        dfield = apefile.data[n];
        gwy_container_set_object_by_name(container, key, dfield);
        g_object_unref(apefile.data[n]);

        g_snprintf(key, sizeof(key), "/%d/data/title", n);

        /*
         * Channel labelling based on SPM Mode
         */
        switch (apefile.spm_mode) {
            case SPM_MODE_SNOM:
            title = gwy_enuml_to_string(i,
                                        "Height",   APE_HEIGHT,
                                        "Height-R", APE_HEIGHT_R,
                                        "NSOM",     APE_NSOM,
                                        "NSOM-R",   APE_NSOM_R,
                                        "Error",    APE_ERROR,
                                        "Error-R",  APE_ERROR_R,
                                        "NSOM2",    APE_NSOM2,
                                        "NSOM2-R",  APE_NSOM2_R,
                                        "Lateral",     APE_AUX1,
                                        "Z-Z0",     APE_AUX2,
                                        "Lateral-R",   APE_AUX1_R,
                                        "Z-Z0-R",   APE_AUX2_R,
                                        NULL);
            break;

            case SPM_MODE_AFM_NONCONTACT:
            case SPM_MODE_AFM_CONTACT:
            case SPM_MODE_PHASE_DETECT_AFM:
            title = gwy_enuml_to_string(i,
                                        "Height",   APE_HEIGHT,
                                        "Height-R", APE_HEIGHT_R,
                                        "IN1",     APE_NSOM,
                                        "IN1-R",   APE_NSOM_R,
                                        "Error",    APE_ERROR,
                                        "Error-R",  APE_ERROR_R,
                                        "IN2",    APE_NSOM2,
                                        "IN2-R",  APE_NSOM2_R,
                                        "Lateral",     APE_AUX1,
                                        "Z-Z0",     APE_AUX2,
                                        "Lateral-R",   APE_AUX1_R,
                                        "Z-Z0-R",   APE_AUX2_R,
                                        NULL);
            break;

            default:
            title = gwy_enuml_to_string(i,
                                        "Height",   APE_HEIGHT,
                                        "Height-R", APE_HEIGHT_R,
                                        "IN1",     APE_NSOM,
                                        "IN1-R",   APE_NSOM_R,
                                        "Error",    APE_ERROR,
                                        "Error-R",  APE_ERROR_R,
                                        "IN2",    APE_NSOM2,
                                        "IN2-R",  APE_NSOM2_R,
                                        "Aux1",     APE_AUX1,
                                        "Z-Z0",     APE_AUX2,
                                        "Aux1-R",   APE_AUX1_R,
                                        "Z-Z0-R",   APE_AUX2_R,
                                        NULL);
            break;
        }
        if (title && *title)
            gwy_container_set_string_by_name(container, key, g_strdup(title));

        tmp = gwy_container_duplicate(meta);
        g_snprintf(key, sizeof(key), "/%d/meta", n);
        gwy_container_set_object_by_name(container, key, tmp);
        g_object_unref(tmp);

        gwy_file_channel_import_log_add(container, n, NULL, filename);

        n++;
    }

    g_object_unref(meta);
    g_free(apefile.remark);

    return container;
}
示例#14
0
static GwyContainer*
jeol_load(const gchar *filename,
          G_GNUC_UNUSED GwyRunType mode,
          GError **error)
{
    JEOLImageHeader image_header;
    GwyContainer *meta, *container = NULL;
    guchar *buffer = NULL;
    gsize expected_size, size = 0;
    GError *err = NULL;
    GwyDataField *dfield = NULL;
    const gchar *title;
    gchar *s;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }
    if (size < JEOL_DATA_START) {
        err_TOO_SHORT(error);
        goto fail;
    }
    if (memcmp(buffer, MAGIC, MAGIC_SIZE) != 0) {
        err_FILE_TYPE(error, "JEOL");
        goto fail;
    }

    jeol_read_image_header(buffer, &image_header);
    /* Elementrary sanity */
    if (image_header.bpp != 16) {
        err_BPP(error, image_header.bpp);
        goto fail;
    }

    if (err_DIMENSION(error, image_header.xres)
        || err_DIMENSION(error, image_header.yres))
        goto fail;

    expected_size = image_header.bpp/8 * image_header.xres*image_header.yres;
    if (err_SIZE_MISMATCH(error, JEOL_DATA_START + expected_size, size, FALSE))
        goto fail;

    if (image_header.image_type != JEOL_IMAGE || image_header.compressed) {
        err_NO_DATA(error);
        goto fail;
    }

    /* Use negated positive conditions to catch NaNs */
    if (!((image_header.xreal = fabs(image_header.xreal)) > 0)) {
        g_warning("Real x size is 0.0, fixing to 1.0");
        image_header.xreal = 1.0;
    }
    if (!((image_header.yreal = fabs(image_header.yreal)) > 0)) {
        g_warning("Real y size is 0.0, fixing to 1.0");
        image_header.yreal = 1.0;
    }

    dfield = jeol_read_data_field(buffer + JEOL_DATA_START, &image_header);
    if (!dfield) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("The type of data is unknown.  "
                      "Please report it to the developers."));
        goto fail;
    }

    container = gwy_container_new();
    gwy_container_set_object_by_name(container, "/0/data", dfield);
    g_object_unref(dfield);

    /* Title */
    s = g_convert(image_header.internal_filename, -1,
                  "iso-8859-1", "utf-8", NULL, NULL, NULL);
    if (s)
        g_strstrip(s);
    if (s && *s)
        gwy_container_set_string_by_name(container, "/0/data/title", s);
    else {
        title = gwy_flat_enum_to_string(image_header.data_source,
                                        G_N_ELEMENTS(data_sources),
                                        data_sources, data_sources_name);
        if (title)
            gwy_container_set_string_by_name(container, "/0/data/title",
                                             g_strdup(title));
    }

    /* Meta */
    meta = jeol_get_metadata(&image_header);
    gwy_container_set_object_by_name(container, "/0/meta", meta);
    g_object_unref(meta);

    gwy_file_channel_import_log_add(container, 0, NULL, filename);

fail:
    gwy_file_abandon_contents(buffer, size, NULL);
    return container;
}
示例#15
0
static GwyContainer*
nanoscope_load(const gchar *filename,
               G_GNUC_UNUSED GwyRunType mode,
               GError **error)
{
    GwyContainer *meta, *container = NULL;
    GError *err = NULL;
    gchar *buffer = NULL;
    gchar *p;
    const gchar *self;
    gsize size = 0;
    NanoscopeFileType file_type;
    NanoscopeData *ndata;
    NanoscopeValue *val;
    GHashTable *hash, *scannerlist = NULL, *scanlist = NULL;
    GList *l, *list = NULL;
    gint i, xres = 0, yres = 0;
    gboolean ok, has_version = FALSE;

    if (!g_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }
    file_type = NANOSCOPE_FILE_TYPE_NONE;
    if (size > MAGIC_SIZE) {
        if (!memcmp(buffer, MAGIC_TXT, MAGIC_SIZE))
            file_type = NANOSCOPE_FILE_TYPE_TXT;
        else if (!memcmp(buffer, MAGIC_BIN, MAGIC_SIZE))
            file_type = NANOSCOPE_FILE_TYPE_BIN;
    }
    if (!file_type) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("File is not a Nanoscope file, "
                      "or it is a unknown subtype."));
        g_free(buffer);
        return NULL;
    }
    gwy_debug("File type: %d", file_type);
    /* as already know file_type, fix the first char for hash reading */
    *buffer = '\\';

    p = buffer;
    while ((hash = read_hash(&p, &err))) {
        ndata = g_new0(NanoscopeData, 1);
        ndata->hash = hash;
        list = g_list_append(list, ndata);
    }
    if (err) {
        g_propagate_error(error, err);
        ok = FALSE;
    }
    else
        ok = TRUE;

    for (l = list; ok && l; l = g_list_next(l)) {
        ndata = (NanoscopeData*)l->data;
        hash = ndata->hash;
        self = g_hash_table_lookup(hash, "#self");
        /* The alternate names were found in files written by some beast
         * called Nanoscope E software */
        if (gwy_strequal(self, "Scanner list")
            || gwy_strequal(self, "Microscope list")) {
            scannerlist = hash;
            continue;
        }
        if (gwy_strequal(self, "File list")) {
            has_version = !!g_hash_table_lookup(hash, "Version");
            gwy_debug("has Version: %d", has_version);
            continue;
        }
        if (gwy_strequal(self, "Ciao scan list")
            || gwy_strequal(self, "Afm list")
            || gwy_strequal(self, "NC Afm list")) {
            get_scan_list_res(hash, &xres, &yres);
            scanlist = hash;
        }
        if (!gwy_strequal(self, "Ciao image list")
            && !gwy_strequal(self, "AFM image list")
            && !gwy_strequal(self, "NCAFM image list"))
            continue;

        ndata->data_field = hash_to_data_field(hash, scannerlist, scanlist,
                                               file_type, has_version,
                                               size, buffer,
                                               xres, yres,
                                               &p, error);
        ok = ok && ndata->data_field;
    }

    if (ok) {
        gchar key[40];

        i = 0;
        container = gwy_container_new();
        for (l = list; l; l = g_list_next(l)) {
            ndata = (NanoscopeData*)l->data;
            if (ndata->data_field) {
                g_snprintf(key, sizeof(key), "/%d/data", i);
                gwy_container_set_object_by_name(container, key,
                                                 ndata->data_field);
                if ((val = g_hash_table_lookup(ndata->hash, "@2:Image Data"))
                    && val->soft_scale) {
                    g_snprintf(key, sizeof(key), "/%d/data/title", i);
                    gwy_container_set_string_by_name(container, key,
                                                     g_strdup(val->soft_scale));
                }

                meta = nanoscope_get_metadata(ndata->hash, list);
                g_snprintf(key, sizeof(key), "/%d/meta", i);
                gwy_container_set_object_by_name(container, key, meta);
                g_object_unref(meta);

                gwy_app_channel_check_nonsquare(container, i);
                i++;
            }
        }
        if (!i)
            gwy_object_unref(container);
    }

    for (l = list; l; l = g_list_next(l)) {
        ndata = (NanoscopeData*)l->data;
        gwy_object_unref(ndata->data_field);
        if (ndata->hash)
            g_hash_table_destroy(ndata->hash);
        g_free(ndata);
    }
    g_free(buffer);
    g_list_free(list);

    if (!container && ok)
        err_NO_DATA(error);

    return container;
}
示例#16
0
static GwyContainer*
rhk_sm3_load(const gchar *filename,
             G_GNUC_UNUSED GwyRunType mode,
             GError **error)
{
    GPtrArray *rhkfile;
    RHKPage *rhkpage;
    GwyContainer *meta, *container = NULL;
    guchar *buffer = NULL;
    gsize size = 0;
    GError *err = NULL;
    GwyDataField *dfield = NULL;
    const guchar *p;
    GString *key;
    guint i, count;

    if (!gwy_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }
    if (size < HEADER_SIZE) {
        err_TOO_SHORT(error);
        gwy_file_abandon_contents(buffer, size, NULL);
        return NULL;
    }

    rhkfile = g_ptr_array_new();

    p = buffer;
    count = 0;
    gwy_debug("position %04x", p - buffer);
    while ((rhkpage = rhk_sm3_read_page(&p, &size, &err))) {
        gwy_debug("Page #%u read OK", count);
        count++;
        rhkpage->pageno = count;
        gwy_debug("position %04x", p - buffer);
        if (rhkpage->type != RHK_TYPE_IMAGE) {
            gwy_debug("Page is not IMAGE, skipping");
            rhk_sm3_page_free(rhkpage);
            continue;
        }
        g_ptr_array_add(rhkfile, rhkpage);
    }

    /* Be tolerant and don't fail when we were able to import at least
     * something */
    if (!rhkfile->len) {
        if (err)
            g_propagate_error(error, err);
        else
            err_NO_DATA(error);
        gwy_file_abandon_contents(buffer, size, NULL);
        g_ptr_array_free(rhkfile, TRUE);
        return NULL;
    }
    g_clear_error(&err);

    container = gwy_container_new();
    key = g_string_new("");
    for (i = 0; i < rhkfile->len; i++) {
        const gchar *cs;
        gchar *s;

        rhkpage = g_ptr_array_index(rhkfile, i);
        dfield = rhk_sm3_page_to_data_field(rhkpage);
        g_string_printf(key, "/%d/data", i);
        gwy_container_set_object_by_name(container, key->str, dfield);
        g_object_unref(dfield);
        p = rhkpage->strings[RHK_STRING_LABEL];
        cs = gwy_enum_to_string(rhkpage->scan_dir,
                                scan_directions, G_N_ELEMENTS(scan_directions));
        if (p && *p) {
            g_string_append(key, "/title");
            if (cs)
                s = g_strdup_printf("%s [%s]", p, cs);
            else
                s = g_strdup(p);
            gwy_container_set_string_by_name(container, key->str, s);
        }

        meta = rhk_sm3_get_metadata(rhkpage);
        g_string_printf(key, "/%d/meta", i);
        gwy_container_set_object_by_name(container, key->str, meta);
        g_object_unref(meta);

        gwy_app_channel_check_nonsquare(container, i);
    }
    g_string_free(key, TRUE);

    gwy_file_abandon_contents(buffer, size, NULL);
    for (i = 0; i < rhkfile->len; i++)
        rhk_sm3_page_free(g_ptr_array_index(rhkfile, i));
    g_ptr_array_free(rhkfile, TRUE);

    return container;
}
示例#17
0
static GwyContainer*
sly_load(const gchar *filename,
         G_GNUC_UNUSED GwyRunType mode,
         GError **error)
{
    GwyContainer *container = NULL, *meta = NULL;
    gchar *buffer = NULL;
    GError *err = NULL;
    GHashTable *hash = NULL;
    gchar *p, *line, *value;
    guint expecting_data = 0;
    SensolyticsChannel *channels = NULL;
    Dimensions dimensions;
    gint ndata = 0, i;

    if (!g_file_get_contents(filename, &buffer, NULL, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }

    p = buffer;
    line = gwy_str_next_line(&p);
    g_strstrip(line);
    if (!gwy_strequal(line, MAGIC)) {
        err_FILE_TYPE(error, "Sensolytics");
        goto fail;
    }

    hash = g_hash_table_new(g_str_hash, g_str_equal);
    for (line = gwy_str_next_line(&p); line; line = gwy_str_next_line(&p)) {
        if (!line[0])
            continue;

        if (expecting_data) {
            expecting_data--;

            /* The columns are comma-separated and numbers use decimal points.
             * Do not tempt the number parsing functions more than necessary
             * and fix commas to tab characters. */
            g_strdelimit(line, ",", '\t');

            /* Ignore X, Y and Z, each is two values */
            for (i = 0; i < 6; i++)
                g_ascii_strtod(line, &line);

            for (i = 0; i < ndata; i++)
                channels[i].data[expecting_data]
                    = channels[i].q * g_ascii_strtod(line, &line);
        }
        else {
            g_strstrip(line);
            if (line[0] != '#') {
                g_warning("Comment line does not start with #.");
                continue;
            }

            do {
                line++;
            } while (g_ascii_isspace(*line));

            if (g_str_has_prefix(line, "X [")) {
                if (channels) {
                    g_warning("Multiple data headers!?");
                    continue;
                }

                if (!read_dimensions(hash, &ndata, &dimensions, error)
                    || !(channels = create_fields(hash, line,
                                                  ndata, &dimensions)))
                    goto fail;
                expecting_data = dimensions.xres * dimensions.yres;
                continue;
            }

            value = strchr(line, ':');
            if (!value) {
                if (!gwy_strequal(line, "ArrayScan"))
                    g_warning("Non-parameter-like line %s", line);
                continue;
            }
            *value = '\0';
            g_strchomp(line);
            do {
                value++;
            } while (g_ascii_isspace(*value));

            if (gwy_strequal(line, "Warning"))
                continue;

            gwy_debug("<%s>=<%s>", line, value);
            g_hash_table_insert(hash, line, value);
        }
    }

    if (!channels) {
        err_NO_DATA(error);
        goto fail;
    }

    container = gwy_container_new();
    for (i = 0; i < ndata; i++) {
        GQuark key = gwy_app_get_data_key_for_id(i);

        gwy_data_field_invert(channels[i].dfield, FALSE, TRUE, FALSE);
        gwy_container_set_object(container, key, channels[i].dfield);
        gwy_app_channel_check_nonsquare(container, i);
        if (channels[i].name) {
            gchar *s = g_strconcat(g_quark_to_string(key), "/title", NULL);
            gwy_container_set_string_by_name(container, s,
                                             g_strdup(channels[i].name));
            g_free(s);
        }
        else
            gwy_app_channel_title_fall_back(container, i);

        gwy_file_channel_import_log_add(container, i, NULL, filename);
    }

    meta = get_meta(hash);
    clone_meta(container, meta, ndata);
    g_object_unref(meta);

fail:
    g_free(buffer);
    if (hash)
        g_hash_table_destroy(hash);
    if (channels) {
        for (i = 0; i < ndata; i++)
            g_object_unref(channels[i].dfield);
        g_free(channels);
    }

    return container;
}
示例#18
0
static gboolean
read_binary_data(X3PFile *x3pfile, unzFile *zipfile, GError **error)
{
    GwyRawDataType rawtype;
    gsize size;
    guchar *bindata;
    gchar *s;
    guint i;

    s = g_hash_table_lookup(x3pfile->hash, DATA_LINK_PREFIX "/PointDataLink");
    if (!s) {
        err_NO_DATA(error);
        return FALSE;
    }
    gwy_debug("binary data file %s", s);

    if (unzLocateFile(zipfile, s, 1) != UNZ_OK) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_IO,
                    _("File %s is missing in the zip file."), s);
        return FALSE;
    }

    s = g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CZ/DataType");
    if (!s) {
        err_MISSING_FIELD(error, AXES_PREFIX "CZ/DataType");
        return FALSE;
    }

    if (!x3p_file_get_data_type(s, &rawtype, error))
        return FALSE;

    if (!(bindata = x3p_get_file_content(zipfile, &size, error)))
        return FALSE;

    if (err_SIZE_MISMATCH(error, x3pfile->ndata * gwy_raw_data_size(rawtype),
                          size, TRUE)) {
        g_free(bindata);
        return FALSE;
    }

    gwy_convert_raw_data(bindata, x3pfile->ndata, 1,
                         rawtype, GWY_BYTE_ORDER_LITTLE_ENDIAN,
                         x3pfile->values, x3pfile->dz, x3pfile->zoff);
    g_free(bindata);

    for (i = 0; i < x3pfile->ndata; i++)
        x3pfile->valid[i] = TRUE;

    s = g_hash_table_lookup(x3pfile->hash, DATA_LINK_PREFIX "/ValidPointsLink");
    if (!s)
        return TRUE;

    if (unzLocateFile(zipfile, s, 1) != UNZ_OK) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_IO,
                    _("File %s is missing in the zip file."), s);
        return FALSE;
    }

    if (!(bindata = x3p_get_file_content(zipfile, &size, error)))
        return FALSE;

    if (err_SIZE_MISMATCH(error, (x3pfile->ndata + 7)/8, size, TRUE)) {
        g_free(bindata);
        return FALSE;
    }

    for (i = 0; i < x3pfile->ndata; i++)
        x3pfile->valid[i] = bindata[i/8] & (1 << (i % 8));

    g_free(bindata);

    return TRUE;
}
示例#19
0
static guint
find_data_offsets(const gchar *buffer,
                  gsize size,
                  GPtrArray *ezdfile,
                  GError **error)
{
    EZDSection *dataset, *section;
    GString *grkey;
    guint required_size = 0;
    gint ngroups, nchannels, i, j, k;
    guint ndata = 0;
    gchar *p;

    /* Sanity check */
    if (!ezdfile->len) {
        err_NO_DATA(error);
        return 0;
    }
    dataset = (EZDSection*)g_ptr_array_index(ezdfile, 0);
    if (strcmp(dataset->name, "DataSet")) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("First section isn't DataSet"));
        return 0;
    }

    if (!(p = g_hash_table_lookup(dataset->meta, "GroupCount"))
        || (ngroups = atol(p)) <= 0) {
        err_INVALID(error, _("GroupCount in [DataSet]"));
        return 0;
    }

    /* Scan groups */
    grkey = g_string_new("");
    for (i = 0; i < ngroups; i++) {
        g_string_printf(grkey, "Gr%d-Count", i);
        if (!(p = g_hash_table_lookup(dataset->meta, grkey->str))) {
            g_warning("No count for group %u", i);
            continue;
        }

        if ((nchannels = atol(p)) <= 0)
            continue;

        /* Scan channels inside a group, note it's OK there's less channels
         * than specified */
        for (j = 0; j < nchannels; j++) {
            g_string_printf(grkey, "Gr%d-Ch%d", i, j);
            if (!(p = g_hash_table_lookup(dataset->meta, grkey->str)))
                continue;

            section = NULL;
            for (k = 1; k < ezdfile->len; k++) {
                section = (EZDSection*)g_ptr_array_index(ezdfile, k);
                if (gwy_strequal(section->name, p))
                    break;
            }
            if (!section) {
                g_warning("Cannot find section for %s", p);
                continue;
            }

            /* Compute data position */
            gwy_debug("Data %s at offset %u from data start",
                      grkey->str, required_size);
            gwy_debug("xres = %d, yres = %d, bpp = %d, z-name = %s",
                      section->xres, section->yres, section->bitdepth,
                      section->zrange.name);
            if (section->yres < 2) {
                gwy_debug("Skipping 1D data Gr%d-Ch%d. FIXME.", i, j);
                continue;
            }
            ndata++;
            section->data = buffer + required_size;
            required_size += section->xres * section->yres
                             * (section->bitdepth/8);
            if (required_size > size) {
                g_warning("Truncated file, %s doesn't fit", grkey->str);
                g_string_free(grkey, TRUE);
                section->data = NULL;

                return 0;
            }
            section->group = i;
            section->channel = j;
        }
    }
    g_string_free(grkey, TRUE);

    if (!ndata)
        err_NO_DATA(error);

    return ndata;
}
示例#20
0
static GwyContainer*
ols_load_tiff(const GwyTIFF *tiff, const gchar *filename, GError **error)
{
    const gchar *colour_channels[] = { "Red", "Green", "Blue" };
    const gchar *colour_channel_gradients[] = {
        "RGB-Red", "RGB-Green", "RGB-Blue"
    };

    GwyContainer *container = NULL;
    GwyDataField *dfield;
    GwySIUnit *siunit;
    GwyTIFFImageReader *reader = NULL;
    GwyTextHeaderParser parser;
    GHashTable *hash;
    gint i, power10;
    gchar *comment = NULL;
    const gchar *s1;
    GError *err = NULL;
    guint spp, ch, id = 0, dir_num = 0;
    gdouble *data;
    gdouble z_axis = 1.0, xy_axis, factor;
    GQuark quark;
    GString *key;

    /* Comment with parameters is common for all data fields */
    if (!gwy_tiff_get_string0(tiff, GWY_TIFFTAG_IMAGE_DESCRIPTION, &comment)
        || !strstr(comment, MAGIC_COMMENT)) {
        g_free(comment);
        err_FILE_TYPE(error, "OLS");
        return NULL;
    }

    /* Read the comment header. */
    gwy_clear(&parser, 1);
    parser.key_value_separator = "=";
    parser.section_template = "[\x1a]";
    parser.endsection_template = "[\x1a End]";
    parser.section_accessor = "::";
    hash = gwy_text_header_parse(comment, &parser, NULL, NULL);

    key = g_string_new(NULL);
    for (dir_num = 0; dir_num < gwy_tiff_get_n_dirs(tiff); dir_num++) {
        reader = gwy_tiff_image_reader_free(reader);
        /* Request a reader, this ensures dimensions and stuff are defined. */
        reader = gwy_tiff_get_image_reader(tiff, dir_num, 3, &err);
        if (!reader) {
            g_warning("Ignoring directory %u: %s", dir_num, err->message);
            g_clear_error(&err);
            continue;
        }
        spp = reader->samples_per_pixel;
        g_string_printf(key, "Data %u Info::XY Convert Value", dir_num+1);
        if (!(s1 = g_hash_table_lookup(hash, key->str))) {
            g_warning("Cannot find 'XY Convert Value' for data %u.", dir_num+1);
            continue;
        }
        xy_axis = g_ascii_strtod(s1, NULL);
        if (!((xy_axis = fabs(xy_axis)) > 0)) {
            g_warning("Real size step is 0.0, fixing to 1.0");
            xy_axis = 1.0;
        }
        g_string_printf(key, "Data %u Info::Z Convert Value", dir_num+1);
        if (!(s1 = g_hash_table_lookup(hash, key->str))) {
            g_warning("Cannot find 'Z Convert Value' for data %u.", dir_num+1);
            continue;
        }
        z_axis = g_ascii_strtod(s1, NULL);

        for (ch = 0; ch < spp; ch++) {
            siunit = gwy_si_unit_new_parse("nm", &power10);
            factor = pow10(power10);
            dfield = gwy_data_field_new(reader->width, reader->height,
                                        reader->width * xy_axis * factor,
                                        reader->height * xy_axis * factor,
                                        FALSE);
            // units
            gwy_data_field_set_si_unit_xy(dfield, siunit);
            g_object_unref(siunit);

            if (spp == 1) {
                if (dir_num == 1)
                    siunit = gwy_si_unit_new_parse("nm", &power10);
                else
                    siunit = gwy_si_unit_new_parse("1e-6", &power10);
            }
            else {
                siunit = gwy_si_unit_new(NULL);
                power10 = 0;
            }
            gwy_data_field_set_si_unit_z(dfield, siunit);
            g_object_unref(siunit);

            factor = z_axis * pow10(power10);
            data = gwy_data_field_get_data(dfield);

            for (i = 0; i < reader->height; i++)
                gwy_tiff_read_image_row(tiff, reader, ch, i, factor, 0.0,
                                        data + i*reader->width);

            /* add read datafield to container */
            if (!container)
                container = gwy_container_new();

            quark = gwy_app_get_data_key_for_id(id);
            gwy_container_set_object(container, quark, dfield);
            g_object_unref(dfield);

            g_string_printf(key, "%s/title", g_quark_to_string(quark));
            if (spp == 1) {
                /* Channel 0 is texture */
                if (dir_num == 0) {
                    gwy_container_set_string_by_name(container, key->str,
                                                     g_strdup("Texture"));
                }
                /* Channel 1 is topography */
                else if (dir_num == 1) {
                    g_string_printf(key, "%s/title", g_quark_to_string(quark));
                    gwy_container_set_string_by_name(container, key->str,
                                                     g_strdup("Height"));
                }
            }
            else {
                gwy_container_set_string_by_name(container, key->str,
                                                 g_strdup(colour_channels[ch]));
                g_string_printf(key, "/%d/base/palette", id);
                gwy_container_set_string_by_name
                                    (container, key->str,
                                     g_strdup(colour_channel_gradients[ch]));
            }

            gwy_file_channel_import_log_add(container, id, NULL, filename);

            id++;
        }
    }

    g_hash_table_destroy(hash);
    g_string_free(key, TRUE);
    g_free(comment);
    if (reader) {
        gwy_tiff_image_reader_free(reader);
        reader = NULL;
    }

    if (!container)
        err_NO_DATA(error);

    return container;
}