Ejemplo n.º 1
0
/* This is the main verification function that checks we have everything we
 * need and the data are of a supported type. */
static gboolean
data_start(X3PFile *x3pfile, GError **error)
{
    static const GwyEnum features[] = {
        { "SUR", X3P_FEATURE_SUR, },
        { "PRF", X3P_FEATURE_PRF, },
        { "PCL", X3P_FEATURE_PCL, },
    };

    gchar *s;

    if (x3pfile->values) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("File main.xml contains multiple data elements."));
        return FALSE;
    }

    /* First check axes to get meaningful error messages if their types are
     * not as expected. */
    if (!require_keys(x3pfile->hash, error,
                      "/ISO5436_2/Record1/FeatureType",
                      AXES_PREFIX "/CX/AxisType",
                      AXES_PREFIX "/CY/AxisType",
                      AXES_PREFIX "/CZ/AxisType",
                      NULL))
        return FALSE;

    s = (gchar*)g_hash_table_lookup(x3pfile->hash,
                                    "/ISO5436_2/Record1/FeatureType");
    if ((x3pfile->feature_type
         = gwy_string_to_enum(s, features, G_N_ELEMENTS(features))) == -1) {
        err_UNSUPPORTED(error, "/ISO5436_2/Record1/FeatureType");
        return FALSE;
    }

    if (x3pfile->feature_type != X3P_FEATURE_SUR
        && x3pfile->feature_type != X3P_FEATURE_PRF) {
        err_UNSUPPORTED(error, "/ISO5436_2/Record1/FeatureType");
        return FALSE;
    }

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CX/AxisType");
    if (!gwy_strequal(s, "I")) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    /* TRANSLATORS: type and axis are symbols such as I, CX, ...*/
                    _("Only type %s is supported for axis %s."),
                    "I", "CX");
        return FALSE;
    }

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CY/AxisType");
    if (x3pfile->feature_type != X3P_FEATURE_PRF && !gwy_strequal(s, "I")) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("Only type %s is supported for axis %s."),
                    "I", "CY");
        return FALSE;
    }

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CZ/AxisType");
    if (!gwy_strequal(s, "A")) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("Only type %s is supported for axis %s."),
                    "A", "CZ");
        return FALSE;
    }

    /* Then check sizes, offsets and steps when we know the grid is regular. */
    if (!require_keys(x3pfile->hash, error,
                      AXES_PREFIX "/CX/Increment",
                      AXES_PREFIX "/CY/Increment",
                      AXES_PREFIX "/CX/Offset",
                      AXES_PREFIX "/CY/Offset",
                      MAT_DIM_PREFIX "/SizeX",
                      MAT_DIM_PREFIX "/SizeY",
                      MAT_DIM_PREFIX "/SizeZ",
                      NULL))
        return FALSE;

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, MAT_DIM_PREFIX "/SizeX");
    x3pfile->xres = atoi(s);

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, MAT_DIM_PREFIX "/SizeY");
    x3pfile->yres = atoi(s);

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, MAT_DIM_PREFIX "/SizeZ");
    x3pfile->zres = atoi(s);

    gwy_debug("xres=%u, yres=%u, zres=%u",
              x3pfile->xres, x3pfile->yres, x3pfile->zres);

    if (err_DIMENSION(error, x3pfile->xres)
        || err_DIMENSION(error, x3pfile->yres)
        || err_DIMENSION(error, x3pfile->zres))
        return FALSE;

    /* PRF feature types are sets of profiles N×1×M. */
    if (x3pfile->feature_type == X3P_FEATURE_PRF && x3pfile->yres != 1) {
        err_UNSUPPORTED(error, MAT_DIM_PREFIX "/SizeY");
        return FALSE;
    }

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CX/Increment");
    x3pfile->dx = g_ascii_strtod(s, NULL);
    if (!((x3pfile->dx = fabs(x3pfile->dx)) > 0)) {
        g_warning("Real x step is 0.0, fixing to 1.0");
        x3pfile->dx = 1.0;
    }

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CY/Increment");
    x3pfile->dy = g_ascii_strtod(s, NULL);
    if (!((x3pfile->dy = fabs(x3pfile->dy)) > 0)) {
        g_warning("Real x step is 0.0, fixing to 1.0");
        x3pfile->dy = 1.0;
    }

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CX/Offset");
    x3pfile->xoff = g_ascii_strtod(s, NULL);

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CY/Offset");
    x3pfile->yoff = g_ascii_strtod(s, NULL);

    /* Defaults that are good for floating point data conversion.  If a file
     * with floating point data specifies Increment and Offset, we apply them
     * without hesitation.  The behaviour is probably undefined.  */
    x3pfile->dz = 1.0;
    x3pfile->zoff = 0.0;

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CZ/Increment");
    if (s)
        x3pfile->dz = g_ascii_strtod(s, NULL);

    s = (gchar*)g_hash_table_lookup(x3pfile->hash, AXES_PREFIX "/CZ/Offset");
    if (s)
        x3pfile->zoff = g_ascii_strtod(s, NULL);

    gwy_debug("dz=%g, zoff=%g", x3pfile->dz, x3pfile->zoff);

    x3pfile->ndata = x3pfile->xres*x3pfile->yres*x3pfile->zres;
    x3pfile->values = g_new(gdouble, x3pfile->ndata);
    x3pfile->valid = g_new(gboolean, x3pfile->ndata);
    x3pfile->datapos = 0;

    return TRUE;
}
Ejemplo n.º 2
0
static gboolean
get_scales(GHashTable *hash,
           gboolean is_text,
           gint *xres, gint *yres,
           gdouble *xreal, gdouble *yreal,
           gdouble *xoff, gdouble *yoff,
           GwySIUnit *si_unit_xy,
           gdouble *zscale,
           gdouble *zoff,
           GwySIUnit *si_unit_z,
           GError **error)
{
    GwySIUnit *unit;
    gint power10, zp;
    gchar *p;
    gboolean has_unit = FALSE;

    /* Dimensions are mandatory. */
    if (!require_keys(hash, error,
                      "SCANNING PARAMS::PixelsX",
                      "SCANNING PARAMS::PixelsY",
                      "SCANNING PARAMS::PixelsZ",
                      "SCANNING PARAMS::SizeX",
                      "SCANNING PARAMS::SizeY",
                      "SCANNING PARAMS::SizeZ",
                      NULL))
        return FALSE;

    *xres = atoi(g_hash_table_lookup(hash, "SCANNING PARAMS::PixelsX"));
    if (err_DIMENSION(error, *xres))
        return FALSE;
    *yres = atoi(g_hash_table_lookup(hash, "SCANNING PARAMS::PixelsY"));
    if (err_DIMENSION(error, *yres))
        return FALSE;

    unit = gwy_si_unit_new(NULL);

    p = g_hash_table_lookup(hash, "SCANNING PARAMS::SizeX");
    *xreal = fabs(g_ascii_strtod(p, &p));
    if (!*xreal) {
        g_warning("Real x size is 0.0, fixing to 1.0");
        *xreal = 1.0;
    }
    gwy_si_unit_set_from_string_parse(si_unit_xy, p, &power10);
    *xreal *= pow10(power10);

    p = g_hash_table_lookup(hash, "SCANNING PARAMS::SizeY");
    *yreal = fabs(g_ascii_strtod(p, &p));
    if (!*yreal) {
        g_warning("Real y size is 0.0, fixing to 1.0");
        *yreal = 1.0;
    }
    gwy_si_unit_set_from_string_parse(unit, p, &power10);
    *yreal *= pow10(power10);
    if (!gwy_si_unit_equal(unit, si_unit_xy)) {
        g_warning("X and Y units differ, using X");
    }

    zp = atoi(g_hash_table_lookup(hash, "SCANNING PARAMS::PixelsZ"));
    if (!zp) {
        g_warning("Z pixels is 0, fixing to 1");
        zp = 1;
    }
    p = g_hash_table_lookup(hash, "SCANNING PARAMS::SizeZ");
    *zscale = g_ascii_strtod(p, &p);
    *zoff = 0.0;
    gwy_si_unit_set_from_string_parse(si_unit_z, p, &power10);
    *zscale *= pow10(power10)/zp;
    /* XXX: Version 4 can have UNIT section that takes precedence.  The Conv
     * factor may not be enough.  Apparently, binary phase data need
     * subtracting 180 deg because data are unsinged.  Bite me. */
    if ((p = g_hash_table_lookup(hash, "UNIT::Unit"))) {
        const gchar *s = g_hash_table_lookup(hash, "UNIT::Name");
        has_unit = TRUE;
        gwy_si_unit_set_from_string_parse(si_unit_z, p, &power10);
        *zscale *= pow10(power10);
        if ((p = g_hash_table_lookup(hash, "UNIT::Conv")))
            *zscale *= g_ascii_strtod(p, NULL);

        if (!is_text && gwy_strequal(s, "Phase"))
            *zoff = -180.0;
    }

    /* Offsets are optional. */
    *xoff = 0.0;
    if ((p = g_hash_table_lookup(hash, "SCANNING PARAMS::OffsetX"))) {
        *xoff = g_ascii_strtod(p, &p);
        gwy_si_unit_set_from_string_parse(unit, p, &power10);
        if (gwy_si_unit_equal(unit, si_unit_xy))
            *xoff *= pow10(power10);
        else {
            g_warning("X offset units differ from X size units, ignoring.");
            *xoff = 0.0;
        }
    }

    *yoff = 0.0;
    if ((p = g_hash_table_lookup(hash, "SCANNING PARAMS::OffsetY"))) {
        *yoff = g_ascii_strtod(p, &p);
        gwy_si_unit_set_from_string_parse(unit, p, &power10);
        if (gwy_si_unit_equal(unit, si_unit_xy))
            *yoff *= pow10(power10);
        else {
            g_warning("Y offset units differ from Y size units, ignoring.");
            *yoff = 0.0;
        }
    }

    // Don't know what to do with the offset when UNIT section is present.
    // It seems to be always 0 in wrong units, so skip it.
    if (!has_unit) {
        if ((p = g_hash_table_lookup(hash, "SCANNING PARAMS::OffsetZ"))) {
            *zoff = g_ascii_strtod(p, &p);
            gwy_si_unit_set_from_string_parse(unit, p, &power10);
            if (gwy_si_unit_equal(unit, si_unit_z))
                *zoff *= pow10(power10);
            else {
                g_warning("Z offset units differ from Z size units, ignoring.");
                *zoff = 0.0;
            }
        }
    }

    g_object_unref(unit);

    return TRUE;
}
Ejemplo n.º 3
0
static GwyContainer*
plt_load(const gchar *filename,
         G_GNUC_UNUSED GwyRunType mode,
         GError **error)
{
    GwyContainer *container = NULL;
    GwyDataField *dfield = NULL;
    GwyTextHeaderParser parser;
    GwySIUnit *xunit, *yunit, *zunit;
    gchar *p, *value, *buffer = NULL;
    GHashTable *hash = NULL;
    gsize size;
    GError *err = NULL;
    G_GNUC_UNUSED gdouble xreal, yreal, zreal;
    gint i, xres, yres;
    gdouble *data;

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

    if (strncmp(buffer, MAGIC1, MIN(size, sizeof(MAGIC1)-1))) {
        err_FILE_TYPE(error, "Nanosurf PLT");
        goto fail;
    }

    /* Find the first line not starting with '#' */
    for (p = buffer; (p - buffer) + 1 < size; p++) {
        if ((p[0] == '\n' || p[0] == '\r')
            && (p[1] != '\n' && p[1] != '#')) {
            break;
        }
    }
    *p = '\0';
    p++;

    gwy_clear(&parser, 1);
    parser.line_prefix = "#";
    parser.key_value_separator = ":";
    hash = gwy_text_header_parse(buffer, &parser, NULL, NULL);
    if (!require_keys(hash, error,
                      "Channel", "Lines", "Points",
                      "XRange", "YRange", "ZRange",
                      NULL))
        goto fail;

    xres = atoi(g_hash_table_lookup(hash, "Points"));
    yres = atoi(g_hash_table_lookup(hash, "Lines"));
    if (err_DIMENSION(error, xres) || err_DIMENSION(error, yres))
        goto fail;

    value = g_hash_table_lookup(hash, "XRange");
    xreal = g_ascii_strtod(value, &value);
    xunit = gwy_si_unit_new(value);

    value = g_hash_table_lookup(hash, "YRange");
    yreal = g_ascii_strtod(value, &value);
    yunit = gwy_si_unit_new(value);

    value = g_hash_table_lookup(hash, "ZRange");
    zreal = g_ascii_strtod(value, &value);
    zunit = gwy_si_unit_new(value);

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

    if (!gwy_si_unit_equal(xunit, yunit))
        g_warning("X and Y units differ, using X");

    dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE);
    gwy_data_field_set_si_unit_xy(dfield, xunit);
    gwy_data_field_set_si_unit_z(dfield, zunit);
    g_object_unref(xunit);
    g_object_unref(yunit);
    g_object_unref(zunit);

    data = gwy_data_field_get_data(dfield);
    value = p;
    for (i = 0; i < xres*yres; i++) {
        data[i] = g_ascii_strtod(value, &p);
        value = p;
    }

    container = gwy_container_new();
    gwy_container_set_object(container, gwy_app_get_data_key_for_id(0), dfield);
    g_object_unref(dfield);

    if ((value = g_hash_table_lookup(hash, "Channel")))
        gwy_container_set_string_by_name(container, "/0/data/title",
                                         g_strdup(value));
    else
        gwy_app_channel_title_fall_back(container, 0);

    gwy_file_channel_import_log_add(container, 0, NULL, filename);

fail:
    g_free(buffer);
    g_hash_table_destroy(hash);

    return container;
}
Ejemplo n.º 4
0
static GwyContainer*
asc_load(const gchar *filename,
         G_GNUC_UNUSED GwyRunType mode,
         GError **error)
{
    GwyContainer *container = NULL;
    GwyDataField *dfield = NULL, *mfield = NULL;
    GwyTextHeaderParser parser;
    GwySIUnit *unit;
    gchar *line, *p, *value, *buffer = NULL;
    GHashTable *hash = NULL;
    gsize size;
    GError *err = NULL;
    gdouble xreal, yreal, q;
    gint i, xres, yres;
    gdouble *data;

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

    p = buffer;
    line = gwy_str_next_line(&p);
    if (!gwy_strequal(line, MAGIC_BARE)) {
        err_FILE_TYPE(error, "SPIP ASCII data");
        goto fail;
    }

    gwy_clear(&parser, 1);
    parser.line_prefix = "#";
    parser.key_value_separator = "=";
    parser.terminator = "# Start of Data:";
    parser.error = &header_error;
    parser.end = &header_end;
    if (!(hash = gwy_text_header_parse(p, &parser, &p, &err))) {
        g_propagate_error(error, err);
        goto fail;
    }
    if (!require_keys(hash, error,
                      "x-pixels", "y-pixels", "x-length", "y-length",
                      NULL))
        goto fail;

    xres = atoi(g_hash_table_lookup(hash, "x-pixels"));
    yres = atoi(g_hash_table_lookup(hash, "y-pixels"));
    if (err_DIMENSION(error, xres) || err_DIMENSION(error, yres))
        goto fail;

    xreal = Nanometer * g_ascii_strtod(g_hash_table_lookup(hash, "x-length"),
                                       NULL);
    yreal = Nanometer * g_ascii_strtod(g_hash_table_lookup(hash, "y-length"),
                                       NULL);
    /* Use negated positive conditions to catch NaNs */
    if (!((xreal = fabs(xreal)) > 0)) {
        g_warning("Real x size is 0.0, fixing to 1.0");
        xreal = 1.0;
    }
    if (!((yreal = fabs(yreal)) > 0)) {
        g_warning("Real y size is 0.0, fixing to 1.0");
        yreal = 1.0;
    }

    dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE);

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

    if ((value = g_hash_table_lookup(hash, "z-unit"))) {
        gint power10;

        unit = gwy_si_unit_new_parse(value, &power10);
        gwy_data_field_set_si_unit_z(dfield, unit);
        g_object_unref(unit);
        q = pow10(power10);
    }
    else if ((value = g_hash_table_lookup(hash, "Bit2nm"))) {
        q = Nanometer * g_ascii_strtod(value, NULL);
        unit = gwy_si_unit_new("m");
        gwy_data_field_set_si_unit_z(dfield, unit);
        g_object_unref(unit);
    }
    else
        q = 1.0;

    data = gwy_data_field_get_data(dfield);
    value = p;
    for (i = 0; i < xres*yres; i++) {
        data[i] = q*g_ascii_strtod(value, &p);
        if (p == value && (!*p || g_ascii_isspace(*p))) {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("End of file reached when reading sample #%d of %d"),
                        i, xres*yres);
            goto fail;
        }
        if (p == value) {
            g_set_error(error, GWY_MODULE_FILE_ERROR,
                        GWY_MODULE_FILE_ERROR_DATA,
                        _("Malformed data encountered when reading sample "
                          "#%d of %d"),
                        i, xres*yres);
            goto fail;
        }
        value = p;
    }

    if ((value = g_hash_table_lookup(hash, "voidpixels")) && atoi(value)) {
        mfield = gwy_data_field_new_alike(dfield, FALSE);
        data = gwy_data_field_get_data(mfield);
        value = p;
        for (i = 0; i < xres*yres; i++) {
            data[i] = 1.0 - g_ascii_strtod(value, &p);
            value = p;
        }
        if (!gwy_app_channel_remove_bad_data(dfield, mfield))
            GWY_OBJECT_UNREF(mfield);
    }

    container = gwy_container_new();

    gwy_container_set_object(container, gwy_app_get_data_key_for_id(0), dfield);

    if (mfield) {
        gwy_container_set_object(container, gwy_app_get_mask_key_for_id(0),
                                 mfield);
        g_object_unref(mfield);
    }

    gwy_file_channel_import_log_add(container, 0, NULL, filename);

fail:
    GWY_OBJECT_UNREF(dfield);
    g_free(buffer);
    if (hash)
        g_hash_table_destroy(hash);

    return container;
}
Ejemplo n.º 5
0
static GwyContainer*
hitachi_load(const gchar *filename,
             G_GNUC_UNUSED GwyRunType mode,
             GError **error)
{
    GwyContainer *container = NULL, *meta;
    GdkPixbuf *pixbuf = NULL;
    GwyDataField *dfield = NULL;
    gchar *value, *imagename = NULL, *header = NULL;
    guchar *pixels;
    GHashTable *hash = NULL;
    GError *err = NULL;
    gdouble dx;
    gint pxres, pyres, hxres, hyres, rowstride, nchannels, i, j;
    gdouble *data;

    if (!(hash = hitachi_load_header(filename, &header, error)))
        return NULL;

    if (!require_keys(hash, error,
                      "ImageName", "DataSize", "PixelSize",
                      NULL))
        goto fail;
    value = g_hash_table_lookup(hash, "ImageName");

    if (!(imagename = hitachi_find_data_name(filename, value))) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("No corresponding data file was found for header file."));
        goto fail;
    }

    if (!(pixbuf = gdk_pixbuf_new_from_file(imagename, &err))) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_IO,
                    _("Cannot load image: %s"), err->message);
        g_clear_error(&err);
        goto fail;
    }

    /* We know the image dimensions so check them. */
    pxres = gdk_pixbuf_get_width(pixbuf);
    pyres = gdk_pixbuf_get_height(pixbuf);

    value = g_hash_table_lookup(hash, "DataSize");
    if (sscanf(value, "%ux%u", &hxres, &hyres) != 2) {
        err_INVALID(error, "DataSize");
        goto fail;
    }
    if (hxres != pxres || hyres != pyres) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("Field DataSize %ux%u does not match image dimensions "
                      "%ux%u."),
                    hxres, hyres, pxres, pyres);
        goto fail;
    }
    if (err_DIMENSION(error, hxres) || err_DIMENSION(error, hyres))
        goto fail;

    dx = g_ascii_strtod(g_hash_table_lookup(hash, "PixelSize"), NULL);
    /* Use negated positive conditions to catch NaNs */
    if (!((dx = fabs(dx)) > 0)) {
        g_warning("Pixel size is 0.0, fixing to 1.0");
        dx = 1.0;
    }
    dx *= Nanometre;

    dfield = gwy_data_field_new(hxres, hyres, hxres*dx, hyres*dx, FALSE);
    gwy_si_unit_set_from_string(gwy_data_field_get_si_unit_xy(dfield), "m");

    data = gwy_data_field_get_data(dfield);
    pixels = gdk_pixbuf_get_pixels(pixbuf);
    rowstride = gdk_pixbuf_get_rowstride(pixbuf);
    nchannels = gdk_pixbuf_get_n_channels(pixbuf);
    for (i = 0; i < hyres; i++) {
        gdouble *drow = data + i*hxres;
        guchar *p = pixels + i*rowstride;

        for (j = 0; j < hxres; j++, p += nchannels)
            drow[j] = (p[0] + p[1] + p[2])/765.0;
    }

    container = gwy_container_new();
    gwy_container_set_object(container, gwy_app_get_data_key_for_id(0), dfield);
    g_object_unref(dfield);

    if ((value = g_hash_table_lookup(hash, "SampleName"))
        && *value)
        gwy_container_set_string_by_name(container, "/0/data/title",
                                         g_strdup(value));
    else
        gwy_container_set_string_by_name(container, "/0/data/title",
                                         g_strdup("SEM"));

    meta = gwy_container_new();
    g_hash_table_foreach(hash, store_meta, meta);
    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_object_unref(pixbuf);
    g_free(imagename);
    g_free(header);
    g_hash_table_destroy(hash);

    return container;
}
Ejemplo n.º 6
0
static GwyDataField*
hash_to_data_field(GHashTable *hash,
                   GHashTable *scannerlist,
                   GHashTable *scanlist,
                   NanoscopeFileType file_type,
                   gboolean has_version,
                   guint bufsize,
                   gchar *buffer,
                   gint gxres,
                   gint gyres,
                   gchar **p,
                   GError **error)
{
    NanoscopeValue *val;
    GwyDataField *dfield;
    GwySIUnit *unitz, *unitxy;
    gchar *s, *end;
    gchar un[5];
    gint xres, yres, bpp, offset, size, power10;
    gdouble xreal, yreal, q;
    gdouble *data;
    gboolean size_ok, use_global;

    if (!require_keys(hash, error, "Samps/line", "Number of lines",
                      "Scan size", "Data offset", "Data length", NULL))
        return NULL;

    val = g_hash_table_lookup(hash, "Samps/line");
    xres = GWY_ROUND(val->hard_value);

    val = g_hash_table_lookup(hash, "Number of lines");
    yres = GWY_ROUND(val->hard_value);

    val = g_hash_table_lookup(hash, "Bytes/pixel");
    bpp = val ? GWY_ROUND(val->hard_value) : 2;

    /* scan size */
    val = g_hash_table_lookup(hash, "Scan size");
    xreal = g_ascii_strtod(val->hard_value_str, &end);
    if (errno || *end != ' ') {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("Cannot parse `Scan size' field."));
        return NULL;
    }
    gwy_debug("xreal = %g", xreal);
    s = end+1;
    yreal = g_ascii_strtod(s, &end);
    if (errno || *end != ' ') {
        /* Old files don't have two numbers here, assume equal dimensions */
        yreal = xreal;
        end = s;
    }
    gwy_debug("yreal = %g", yreal);
    while (g_ascii_isspace(*end))
        end++;
    if (sscanf(end, "%4s", un) != 1) {
        g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA,
                    _("Cannot parse `Scan size' field."));
        return NULL;
    }
    gwy_debug("xy unit: <%s>", un);
    unitxy = gwy_si_unit_new_parse(un, &power10);
    q = pow10(power10);
    xreal *= q;
    yreal *= q;

    offset = size = 0;
    if (file_type == NANOSCOPE_FILE_TYPE_BIN) {
        val = g_hash_table_lookup(hash, "Data offset");
        offset = GWY_ROUND(val->hard_value);

        val = g_hash_table_lookup(hash, "Data length");
        size = GWY_ROUND(val->hard_value);

        size_ok = FALSE;
        use_global = FALSE;

        /* Try channel size and local size */
        if (!size_ok && size == bpp*xres*yres)
            size_ok = TRUE;

        if (!size_ok && size == bpp*gxres*gyres) {
            size_ok = TRUE;
            use_global = TRUE;
        }

        /* If they don't match exactly, try whether they at least fit inside */
        if (!size_ok && size > bpp*MAX(xres*yres, gxres*gyres)) {
            size_ok = TRUE;
            use_global = (xres*yres < gxres*gyres);
        }

        if (!size_ok && size > bpp*MIN(xres*yres, gxres*gyres)) {
            size_ok = TRUE;
            use_global = (xres*yres > gxres*gyres);
        }

        if (!size_ok) {
            err_SIZE_MISMATCH(error, size, bpp*xres*yres);
            return NULL;
        }

        if (use_global) {
            if (gxres) {
                xreal *= (gdouble)gxres/xres;
                xres = gxres;
            }
            if (gyres) {
                yreal *= (gdouble)gyres/yres;
                yres = gyres;
            }
        }

        if (offset + size > (gint)bufsize) {
            err_SIZE_MISMATCH(error, offset + size, bufsize);
            return NULL;
        }
    }

    q = 1.0;
    unitz = get_physical_scale(hash, scannerlist, scanlist, has_version,
                               &q, error);
    if (!unitz)
        return NULL;

    dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE);
    data = gwy_data_field_get_data(dfield);
    switch (file_type) {
        case NANOSCOPE_FILE_TYPE_TXT:
        if (!read_ascii_data(xres*yres, data, p, bpp, error)) {
            g_object_unref(dfield);
            return NULL;
        }
        break;

        case NANOSCOPE_FILE_TYPE_BIN:
        if (!read_binary_data(xres*yres, data, buffer + offset, bpp, error)) {
            g_object_unref(dfield);
            return NULL;
        }
        break;

        default:
        g_assert_not_reached();
        break;
    }
    gwy_data_field_multiply(dfield, q);
    gwy_data_field_invert(dfield, TRUE, FALSE, FALSE);
    gwy_data_field_set_si_unit_z(dfield, unitz);
    g_object_unref(unitz);

    gwy_data_field_set_si_unit_xy(dfield, unitxy);
    g_object_unref(unitxy);

    return dfield;
}
Ejemplo n.º 7
0
static GwyContainer*
micromap_load(const gchar *filename,
              G_GNUC_UNUSED GwyRunType mode,
              GError **error)
{
    SDFile sdfile;
    GwyContainer *container = NULL;
    gchar *p, *buffer = NULL;
    gsize len, size = 0;
    GError *err = NULL;
    GwyDataField *dfield = NULL;
    gdouble objectivemag, tubemag, cameraxpixel, cameraypixel;

    if (!g_file_get_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }
    len = size;
    p = buffer;
    if (sdfile_read_header_text(&p, &len, &sdfile, error)) {
        if (check_params(&sdfile, len, error))
            dfield = sdfile_read_data_text(&sdfile, error);
    }
    if (!dfield) {
        g_free(buffer);
        return NULL;
    }

    if (!sdfile.extras) {
        err_MISSING_FIELD(error, "OBJECTIVEMAG");
        goto fail;
    }

    if (!require_keys(sdfile.extras, error,
                      "OBJECTIVEMAG", "TUBEMAG", "CAMERAXPIXEL", "CAMERAYPIXEL",
                      NULL))
        goto fail;

    objectivemag = g_ascii_strtod(g_hash_table_lookup(sdfile.extras,
                                                      "OBJECTIVEMAG"), NULL);
    tubemag = g_ascii_strtod(g_hash_table_lookup(sdfile.extras,
                                                 "TUBEMAG"), NULL);
    cameraxpixel = g_ascii_strtod(g_hash_table_lookup(sdfile.extras,
                                                      "CAMERAXPIXEL"), NULL);
    cameraypixel = g_ascii_strtod(g_hash_table_lookup(sdfile.extras,
                                                      "CAMERAYPIXEL"), NULL);

    sdfile_set_units(&sdfile, dfield);
    gwy_data_field_set_xreal(dfield,
                             Micrometer * sdfile.xres * objectivemag
                             * tubemag * cameraxpixel);
    gwy_data_field_set_yreal(dfield,
                             Micrometer * sdfile.yres * objectivemag
                             * tubemag * cameraypixel);

    container = gwy_container_new();
    gwy_container_set_object_by_name(container, "/0/data", dfield);
    gwy_container_set_string_by_name(container, "/0/data/title",
                                     g_strdup("Topography"));

fail:
    g_object_unref(dfield);
    g_free(buffer);
    if (sdfile.extras)
        g_hash_table_destroy(sdfile.extras);

    return container;
}