static void fix_scales(EZDSection *section, gint idx, GwyContainer *container) { GwyDataField *dfield; GwySIUnit *siunit; gchar key[40]; gint power10; gdouble r; g_snprintf(key, sizeof(key), "/%d/data", idx); dfield = GWY_DATA_FIELD(gwy_container_get_object_by_name(container, key)); /* Fix value scale */ siunit = gwy_si_unit_new_parse(section->zrange.unit, &power10); gwy_data_field_set_si_unit_z(dfield, siunit); g_object_unref(siunit); r = pow10(power10); gwy_data_field_multiply(dfield, r*section->zrange.range); gwy_data_field_add(dfield, r*section->zrange.min); /* Fix lateral scale */ siunit = gwy_si_unit_new_parse(section->xrange.unit, &power10); gwy_data_field_set_si_unit_xy(dfield, siunit); g_object_unref(siunit); gwy_data_field_set_xreal(dfield, pow10(power10)*section->xrange.range); siunit = gwy_si_unit_new_parse(section->yrange.unit, &power10); gwy_data_field_set_yreal(dfield, pow10(power10)*section->yrange.range); g_object_unref(siunit); /* Some metadata */ if (section->zrange.name) { const gchar *s; switch (section->direction) { case SCAN_FORWARD: s = " forward"; break; case SCAN_BACKWARD: s = " backward"; break; default: s = ""; break; } g_snprintf(key, sizeof(key), "/%d/data/title", idx); gwy_container_set_string_by_name(container, key, g_strdup_printf("%s%s", section->zrange.name, s)); } }
static void update_range_lables(GtkWidget *from, GtkWidget *to, GtkWidget *unit, gdouble min, gdouble max, const gchar *unitstring) { GwySIValueFormat *vf; GwySIUnit *siunit; gint power10; gchar *s; siunit = gwy_si_unit_new_parse(unitstring, &power10); min *= pow10(power10); max *= pow10(power10); vf = gwy_si_unit_get_format_with_digits(siunit, GWY_SI_UNIT_FORMAT_VFMARKUP, MAX(fabs(min), fabs(max)), 3, NULL); s = g_strdup_printf("%.*f", vf->precision, min/vf->magnitude); gtk_label_set_markup(GTK_LABEL(from), s); g_free(s); s = g_strdup_printf("%.*f", vf->precision, max/vf->magnitude); gtk_label_set_markup(GTK_LABEL(to), s); g_free(s); gtk_label_set_markup(GTK_LABEL(unit), vf->units); gwy_si_unit_value_format_free(vf); g_object_unref(siunit); }
static GwySIUnit* read_real_size(const NetCDF *cdffile, const gchar *name, gdouble *real, gint *power10) { const NetCDFVar *var; const NetCDFAttr *attr; GwySIUnit *siunit; const guchar *p; gchar *s; *real = 1.0; *power10 = 0; if (!(var = cdffile_get_var(cdffile, name))) return NULL; /* * Warning: Madness ahead. * * Older GXSM files contain "AA" in "unit", that makes sense, as the units * are Angstroems. * * Newer GXSM files contain "nm" in "unit" though, in spite of the units * being still Angstroems. They seem to contain the real units in * "var_unit". The info field reads: * * This number is alwalys stored in Angstroem. Unit is used for user * display only. * * In addition they invented yet another Angstroem abbreviation: Ang. */ attr = cdffile_get_attr(var->attrs, var->nattrs, "var_unit"); if (!attr || attr->type != NC_CHAR) { attr = cdffile_get_attr(var->attrs, var->nattrs, "unit"); if (!attr || attr->type != NC_CHAR) return NULL; } if (!attr->nelems) s = NULL; else s = g_strndup(attr->values, attr->nelems); siunit = gwy_si_unit_new_parse(s, power10); g_free(s); p = (const guchar*)(cdffile->buffer + var->begin); if (var->type == NC_DOUBLE) *real = gwy_get_gdouble_be(&p); else if (var->type == NC_FLOAT) *real = gwy_get_gfloat_be(&p); else g_warning("Size is not a floating point number"); return siunit; }
/* Lateral units are a weird thing but they contain the actual units in * bracket somewhere. If there are no brackes, try to interpret the entire * string as units -- I've been told this is the right thing. */ static GwySIUnit* extract_units(const gchar *label, gdouble *q) { GwySIUnit *unit; gint power10; const gchar *s; gchar *t; if ((s = strchr(label, '['))) { t = g_strdup(s + 1); if (strchr(t, ']')) *strchr(t, ']') = '\0'; unit = gwy_si_unit_new_parse(t, &power10); g_free(t); } else unit = gwy_si_unit_new_parse(label, &power10); *q = pow10(power10); return unit; }
static void oldmda_read_params(MDAXMLParams *par, OldMDAFile *mdafile) { MDAAxis axis; mdafile->zres = par->res; mdafile->xdata = par->xdata; axis = g_array_index(par->axes, MDAAxis, 0); if (axis.unitname) mdafile->siunitz = gwy_si_unit_new(axis.unitname); else mdafile->siunitz = gwy_si_unit_new(""); axis = g_array_index(par->axes, MDAAxis, 1); if (axis.unitname) mdafile->siunitx = gwy_si_unit_new_parse(axis.unitname, &mdafile->power10x); else mdafile->siunitx = gwy_si_unit_new(""); mdafile->xres = axis.maxindex - axis.minindex + 1; if (mdafile->xres < 1) mdafile->xres = 1; if (axis.scale <= 0.0) axis.scale = 1.0; mdafile->xreal = axis.scale * mdafile->xres * pow(10.0, mdafile->power10x); axis = g_array_index(par->axes, MDAAxis, 2); if (axis.unitname) mdafile->siunity = gwy_si_unit_new_parse(axis.unitname, &mdafile->power10y); else mdafile->siunity = gwy_si_unit_new(""); mdafile->yres = axis.maxindex - axis.minindex + 1; if (mdafile->yres < 1) mdafile->yres = 1; if (axis.scale <= 0.0) axis.scale = 1.0; mdafile->yreal = axis.scale * mdafile->yres * pow(10.0, mdafile->power10y); }
static GObject* gwy_si_unit_duplicate_real(GObject *object) { GwySIUnit *si_unit, *duplicate; g_return_val_if_fail(GWY_IS_SI_UNIT(object), NULL); si_unit = GWY_SI_UNIT(object); duplicate = gwy_si_unit_new_parse("", NULL); duplicate->power10 = si_unit->power10; g_array_append_vals(duplicate->units, si_unit->units->data, si_unit->units->len); return (GObject*)duplicate; }
static void set_combo_from_unit(GtkWidget *combo, const gchar *str, gint basepower) { GwySIUnit *unit; gint power10; unit = gwy_si_unit_new_parse(str, &power10); power10 += basepower; gwy_combo_box_metric_unit_set_unit(GTK_COMBO_BOX(combo), power10 - 6, power10 + 6, unit); g_object_unref(unit); }
static SensolyticsChannel* create_fields(GHashTable *hash, /* Can we obtain any useful information from this? */ G_GNUC_UNUSED gchar *line, gint ndata, const Dimensions *dimensions) { SensolyticsChannel *channels; GString *str; const gchar *value; GwySIUnit *unit; gint i, power10; str = g_string_new(NULL); channels = g_new0(SensolyticsChannel, ndata+1); for (i = 0; i < ndata; i++) { channels[i].dfield = gwy_data_field_new(dimensions->xres, dimensions->yres, dimensions->xreal, dimensions->yreal, FALSE); channels[i].data = gwy_data_field_get_data(channels[i].dfield); unit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_xy(channels[i].dfield, unit); g_object_unref(unit); g_string_printf(str, "Channel %d Unit", i+1); channels[i].q = 1.0; if ((value = g_hash_table_lookup(hash, str->str))) { unit = gwy_si_unit_new_parse(value, &power10); gwy_data_field_set_si_unit_z(channels[i].dfield, unit); g_object_unref(unit); channels[i].q = pow10(power10); } else g_warning("Channel %d has no units", i+1); g_string_printf(str, "Channel %d Name", i+1); if (!(channels[i].name = g_hash_table_lookup(hash, str->str))) g_warning("Channel %d has no name", i+1); } return channels; }
static gboolean parse_scale(gchar **p, const gchar *name, double *value, GwySIUnit **units, GError **error) { gint power10; gchar *vp, *line; line = gwy_str_next_line(p); if (!line) { err_MISSING_FIELD(error, name); return FALSE; } vp = strchr(line, ':'); if (!vp) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Missing colon in header line.")); return FALSE; } *vp = '\0'; vp++; gwy_debug("<%s> = <%s>", name, vp); if (!gwy_strequal(line, name)) { err_MISSING_FIELD(error, name); return FALSE; } *value = g_ascii_strtod(vp, &vp); *units = gwy_si_unit_new_parse(vp, &power10); *value *= pow10(power10); if (!*value) { g_warning("%s is 0.0, fixing to 1.0", name); *value = 1.0; } return TRUE; }
static GwyDataField* omicron_read_data(OmicronFile *ofile, OmicronTopoChannel *channel, GError **error) { GError *err = NULL; GwyDataField *dfield; GwySIUnit *siunit; gchar *filename; gdouble *data; guchar *buffer; const gint16 *d; gdouble scale; gsize size; guint i, j, n; gint power10 = 0; filename = omicron_fix_file_name(ofile->filename, channel->filename, error); if (!filename) return NULL; gwy_debug("Succeeded with <%s>", filename); if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { g_free(filename); err_GET_FILE_CONTENTS(error, &err); return NULL; } g_free(filename); n = ofile->xres*ofile->yres; if (err_SIZE_MISMATCH(error, 2*n, size, TRUE)) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } scale = (channel->max_phys - channel->min_phys) /(channel->max_raw - channel->min_raw); dfield = gwy_data_field_new(ofile->xres, ofile->yres, ofile->xreal, ofile->yreal, FALSE); data = gwy_data_field_get_data(dfield); d = (const gint16*)buffer; for (i = 0; i < ofile->yres; i++) { for (j = 0; j < ofile->xres; j++) data[(ofile->yres-1 - i)*ofile->xres + j] = scale*GINT16_FROM_BE(d[i*ofile->xres + j]); } gwy_file_abandon_contents(buffer, size, NULL); siunit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_xy(dfield, siunit); g_object_unref(siunit); siunit = gwy_si_unit_new_parse(channel->units, &power10); gwy_data_field_set_si_unit_z(dfield, siunit); g_object_unref(siunit); if (power10) gwy_data_field_multiply(dfield, pow10(power10)); return dfield; }
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; }
/** * gwy_si_unit_new: * @unit_string: Unit string (it can be %NULL for an empty unit). * * Creates a new SI unit from string representation. * * Unit string represents unit with no prefixes * (e. g. "m", "N", "A", etc.) * * Returns: A new SI unit. **/ GwySIUnit* gwy_si_unit_new(const char *unit_string) { return gwy_si_unit_new_parse(unit_string, NULL); }
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; }
static GwySIUnit* get_physical_scale(GHashTable *hash, GHashTable *scannerlist, GHashTable *scanlist, gboolean has_version, gdouble *scale, GError **error) { GwySIUnit *siunit, *siunit2; NanoscopeValue *val, *sval; gchar *key; gint q; /* Very old style scales (files with Version field) */ if (!has_version) { if (!(val = g_hash_table_lookup(hash, "Z magnify image"))) { err_MISSING_FIELD(error, "Z magnify image"); return NULL; } /* TODO: Luminescence */ siunit = gwy_si_unit_new("m"); /* According to Markus, the units are 1/100 nm, but his scale * calculation is raw/655.36 [nm]. We have the factor 1/65536 applied * automatically, that gives 1e-7 [m]. Whatever. */ *scale = 1e-7 * val->hard_value; return siunit; } /* XXX: This is a damned heuristics. For some value types we try to guess * a different quantity scale to look up. */ if (!(val = g_hash_table_lookup(hash, "@2:Z scale"))) { if (!(val = g_hash_table_lookup(hash, "Z scale"))) { err_MISSING_FIELD(error, "Z scale"); return NULL; } /* Old style scales */ siunit = gwy_si_unit_new_parse(val->hard_value_units, &q); *scale = val->hard_value * pow10(q); if (val->hard_scale) *scale *= 65536.0/val->hard_scale; return siunit; } key = g_strdup_printf("@%s", val->soft_scale); if (!(sval = g_hash_table_lookup(scannerlist, key)) && (!scanlist || !(sval = g_hash_table_lookup(scanlist, key)))) { g_warning("`%s' not found", key); g_free(key); /* XXX */ *scale = val->hard_value; return gwy_si_unit_new(""); } *scale = val->hard_value*sval->hard_value; if (!sval->hard_value_units || !*sval->hard_value_units) { if (gwy_strequal(val->soft_scale, "Sens. Phase")) siunit = gwy_si_unit_new("deg"); else siunit = gwy_si_unit_new("V"); } else { siunit = gwy_si_unit_new_parse(sval->hard_value_units, &q); siunit2 = gwy_si_unit_new("V"); gwy_si_unit_multiply(siunit, siunit2, siunit); gwy_debug("Scale1 = %g V/LSB", val->hard_value); gwy_debug("Scale2 = %g %s", sval->hard_value, sval->hard_value_units); *scale *= pow10(q); gwy_debug("Total scale = %g %s/LSB", *scale, gwy_si_unit_get_string(siunit, GWY_SI_UNIT_FORMAT_PLAIN)); g_object_unref(siunit2); } g_free(key); return siunit; }
static GwyContainer* quesant_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL; guchar *buffer = NULL; gsize size = 0; GError *err = NULL; GwySIUnit *units = NULL; gint32 power10; FileInfo info; int row, col; GwyDataField *dfield; gdouble multiplier; const guint16 *p; gdouble *d; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size <= HEADER_SIZE) { gwy_file_abandon_contents(buffer, size, NULL); err_TOO_SHORT(error); return NULL; } if (!read_file_info(buffer, size, &info, error)) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } // create units and datafield units = gwy_si_unit_new_parse("um", &power10); dfield = gwy_data_field_new(info.img_res, info.img_res, info.real_size * pow10(power10), info.real_size * pow10(power10), FALSE); // set units for XY axes gwy_data_field_set_si_unit_xy(dfield, units); g_object_unref(units); // set units for Z axis units = gwy_si_unit_new_parse("um", &power10); gwy_data_field_set_si_unit_z(dfield, units); g_object_unref(units); multiplier = info.z_scale * pow10(power10); p = info.image_data; d = gwy_data_field_get_data(dfield); // values are stored in unsigned int16 type for (row = 0; row < info.img_res; row++) { for (col = 0; col < info.img_res; col++) { d[row*info.img_res + col] = GUINT16_FROM_LE(*p) * multiplier; p++; } } // create container container = gwy_container_new(); // put datafield into container gwy_container_set_object_by_name(container, "/0/data", dfield); g_object_unref(dfield); gwy_app_channel_title_fall_back(container, 0); gwy_file_channel_import_log_add(container, 0, NULL, filename); gwy_file_abandon_contents(buffer, size, NULL); return container; }
static GwyContainer* csmfile_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *meta, *container = NULL; GHashTable *hash = NULL; guchar *d24, *buffer = NULL; gsize size = 0; GError *err = NULL; GwyDataField *dfield = NULL; guint xres, yres, bmpsize, header_size, maxval, i, j; gdouble real, zmin, zmax, q, z0; GwyTextHeaderParser parser; GwySIUnit *unit = NULL; gchar *value, *end, *header = NULL; gdouble *data; gint power10; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < BMP_HEADER_SIZE) { err_TOO_SHORT(error); goto fail; } if (!read_bmp_header(buffer, &xres, &yres, &bmpsize) || size <= bmpsize) { err_FILE_TYPE(error, "CSM"); goto fail; } header_size = size - bmpsize; header = g_new(gchar, header_size + 1); memcpy(header, buffer + bmpsize, header_size); header[header_size] = '\0'; gwy_clear(&parser, 1); parser.key_value_separator = "="; hash = gwy_text_header_parse(header, &parser, NULL, NULL); /* Do NOT use the fields Image width, Image height from the added footer. * Even though it is specifically added by Benyuan it can disagree with the * BMP diemsions and when they disagree the BMP diemsions are apparently * right. */ if (err_DIMENSION(error, xres)) goto fail; if (err_DIMENSION(error, yres)) goto fail; if (!(value = g_hash_table_lookup(hash, "ScanSize"))) { err_MISSING_FIELD(error, "ScanSize"); goto fail; } real = g_ascii_strtod(value, NULL); /* Use negated positive conditions to catch NaNs */ if (!((real = fabs(real)) > 0)) { g_warning("Real size is 0.0, fixing to 1.0"); real = 1.0; } if (!(value = g_hash_table_lookup(hash, "HeightScale"))) { err_MISSING_FIELD(error, "HeightScale"); goto fail; } zmax = g_ascii_strtod(value, &end); unit = gwy_si_unit_new_parse(end, &power10); /* Optional stuff for which we try to fall back. */ if (!(value = g_hash_table_lookup(hash, "StartHeightScale"))) zmin = 0.0; else zmin = g_ascii_strtod(value, NULL); if (!(value = g_hash_table_lookup(hash, "MaxValue"))) maxval = 0xffff; else maxval = MAX(atoi(value), 1); dfield = gwy_data_field_new(xres, yres, real*Nanometre, real*Nanometre, FALSE); data = gwy_data_field_get_data(dfield); d24 = buffer + BMP_HEADER_SIZE; q = pow10(power10)*(zmax - zmin)/maxval; z0 = pow10(power10)*zmin; for (i = 0; i < yres; i++) { gdouble *row = data + (yres-1 - i)*xres; for (j = 0; j < xres; j++, row++, d24 += 3) *row = (d24[0] + 256.0*d24[1])*q + z0; } gwy_si_unit_set_from_string(gwy_data_field_get_si_unit_xy(dfield), "m"); gwy_data_field_set_si_unit_z(dfield, unit); container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", dfield); g_object_unref(dfield); 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); if ((value = g_hash_table_lookup(hash, "sTitle")) && g_utf8_validate(value, -1, NULL)) { 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: gwy_file_abandon_contents(buffer, size, NULL); GWY_OBJECT_UNREF(unit); if (header) g_free(header); if (hash) g_hash_table_destroy(hash); return container; }
static GwyContainer* zeiss_load_tiff(const GwyTIFF *tiff, GError **error) { GwyContainer *container = NULL, *meta = NULL; GwyDataField *dfield; GwySIUnit *siunit; GwyTIFFImageReader *reader = NULL; GHashTable *hash = NULL; gint i, power10; gchar *value, *end, *comment = NULL; gdouble *data; gboolean new_file; double factor, dx; /* Comment with parameters is common for all data fields */ if (!gwy_tiff_get_string0(tiff, ZEISS_HEADER_TAG, &comment)) { err_FILE_TYPE(error, "Carl Zeiss SEM"); goto fail; } if (strstr(comment, MAGIC_COMMENT)) new_file = TRUE; else if (g_str_has_prefix(comment, SOMEWHAT_LESS_MAGIC_COMMENT)) new_file = FALSE; else { err_FILE_TYPE(error, "Carl Zeiss SEM"); goto fail; } /* Read the comment header. */ if (new_file) { hash = parse_comment(comment); if ((value = g_hash_table_lookup(hash, "Image Pixel Size"))) { gwy_debug("Using dx from Image Pixel Size: %s", value); } else if ((value = g_hash_table_lookup(hash, "Pixel Size"))) { gwy_debug("Using dx from Pixel Size: %s", value); } else { err_MISSING_FIELD(error, "Pixel Size"); goto fail; } } else { /* The first thing is the pixel size, apparently. */ value = comment + strlen(SOMEWHAT_LESS_MAGIC_COMMENT); gwy_debug("Using dx from old-style comment: %s", value); } dx = g_ascii_strtod(value, &end); /* Use negated positive conditions to catch NaNs */ if (!((dx = fabs(dx)) > 0)) { g_warning("Real pixel size is 0.0, fixing to 1.0"); dx = 1.0; } if (!new_file) end = "m"; /* Request a reader, this ensures dimensions and stuff are defined. * NB: Newer versions store the image as RGB. Not useful here; just * average the channels. */ if (!(reader = gwy_tiff_get_image_reader(tiff, 0, 3, error))) goto fail; siunit = gwy_si_unit_new_parse(end, &power10); factor = pow10(power10); dfield = gwy_data_field_new(reader->width, reader->height, reader->width * factor * dx, reader->height * factor * dx, FALSE); gwy_data_field_set_si_unit_xy(dfield, siunit); g_object_unref(siunit); data = gwy_data_field_get_data(dfield); if (reader->samples_per_pixel > 1) { gdouble *datarow = g_new(gdouble, reader->width); gint ch, j, spp = reader->samples_per_pixel; gwy_data_field_clear(dfield); for (i = 0; i < reader->height; i++) { for (ch = 0; ch < spp; ch++) { gwy_tiff_read_image_row(tiff, reader, 0, i, 1.0, 0.0, datarow); for (j = 0; j < reader->width; j++) data[i*reader->width + j] += datarow[j]; } } g_free(datarow); gwy_data_field_multiply(dfield, 1.0/spp); gwy_data_field_invalidate(dfield); } else { for (i = 0; i < reader->height; i++) gwy_tiff_read_image_row(tiff, reader, 0, i, 1.0, 0.0, data + i*reader->width); } container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", dfield); g_object_unref(dfield); gwy_container_set_string_by_name(container, "/0/data/title", g_strdup("Secondary electron count")); if (new_file) { meta = gwy_container_new(); g_hash_table_foreach(hash, add_meta, meta); if (gwy_container_get_n_items(meta)) gwy_container_set_object_by_name(container, "/0/meta", meta); g_object_unref(meta); } fail: if (hash) g_hash_table_destroy(hash); g_free(comment); return container; }
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; }
static GwyDataField* unisoku_read_data_field(const guchar *buffer, gsize size, UnisokuFile *ufile, GError **error) { gint i, n, power10; const gchar *unit; GwyDataField *dfield; GwySIUnit *siunit; gdouble q, pmin, pmax, rmin, rmax; gdouble *data; n = ufile->xres * ufile->yres; if (err_SIZE_MISMATCH(error, n*type_sizes[ufile->data_type], size, FALSE)) return NULL; dfield = gwy_data_field_new(ufile->xres, ufile->yres, fabs((ufile->end_x - ufile->start_x)), fabs((ufile->end_y - ufile->start_y)), FALSE); data = gwy_data_field_get_data(dfield); /* FIXME: what to do when ascii_flag is set? */ switch (ufile->data_type) { case UNISOKU_UINT8: for (i = 0; i < n; i++) data[i] = buffer[i]; break; case UNISOKU_SINT8: for (i = 0; i < n; i++) data[i] = (signed char)buffer[i]; break; case UNISOKU_UINT16: { const guint16 *pdata = (const guint16*)buffer; for (i = 0; i < n; i++) data[i] = GUINT16_FROM_LE(pdata[i]); } break; case UNISOKU_SINT16: { const gint16 *pdata = (const gint16*)buffer; for (i = 0; i < n; i++) data[i] = GINT16_FROM_LE(pdata[i]); } break; case UNISOKU_FLOAT: for (i = 0; i < n; i++) data[i] = gwy_get_gfloat_le(&buffer); break; default: g_return_val_if_reached(NULL); break; } unit = ufile->unit_x; if (!*unit) unit = "nm"; siunit = gwy_si_unit_new_parse(unit, &power10); gwy_data_field_set_si_unit_xy(dfield, siunit); q = pow10((gdouble)power10); gwy_data_field_set_xreal(dfield, q*gwy_data_field_get_xreal(dfield)); gwy_data_field_set_yreal(dfield, q*gwy_data_field_get_yreal(dfield)); g_object_unref(siunit); unit = ufile->unit_z; /* XXX: No fallback yet, just make z unitless */ siunit = gwy_si_unit_new_parse(unit, &power10); gwy_data_field_set_si_unit_z(dfield, siunit); q = pow10((gdouble)power10); pmin = q*ufile->min_z; pmax = q*ufile->max_z; rmin = ufile->min_raw_z; rmax = ufile->max_raw_z; gwy_data_field_multiply(dfield, (pmax - pmin)/(rmax - rmin)); gwy_data_field_add(dfield, (pmin*rmax - pmax*rmin)/(rmax - rmin)); g_object_unref(siunit); return dfield; }
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; }
static GwySpectra* omicron_read_cs_data(OmicronFile *ofile, OmicronSpectroChannel *channel, GError **error) { GError *err = NULL; GwyDataLine *dline; GwySIUnit *siunit = NULL, *coord_unit = NULL; GwySpectra *spectra = NULL; GPtrArray *spectrum = NULL; gchar *filename; gdouble *data, x, y; gdouble *coords = NULL; gchar *buffer; gdouble scale; guint i, j; gint power10 = 0; gint ncurves = 0; gchar* line; filename = omicron_fix_file_name(ofile->filename, channel->filename, error); if (!filename) return NULL; gwy_debug("Succeeded with <%s>", filename); if (!g_file_get_contents(filename, &buffer, NULL , &err)) { g_free(filename); err_GET_FILE_CONTENTS(error, &err); return NULL; } g_free(filename); scale = channel->resolution; /* can also be extracted from min&max raw and phys settings */ while ((line = gwy_str_next_line(&buffer))) { if (strstr(line, ";n_curves")) { /* Find number of curves this should appear first in file */ ncurves = g_ascii_strtod(strchr(line, ':')+1, NULL); } if (strstr(line, "BEGIN COORD")) { /* Read in cordinates Spectroscopy Curves */ i = 0; coord_unit = gwy_si_unit_new_parse("nm", &power10); while ((line = gwy_str_next_line(&buffer))) { gchar *val2; if (strstr(line, "END")) { if (i != ncurves) { gwy_debug("Less coords than ncurves"); } break; } if (i == ncurves) { g_critical("More coords than ncurves."); break; } if (!coords) { if (!(coords = g_new0(gdouble, ncurves*2))) { gwy_debug("Failed to allocate mem: coords"); return NULL; } } val2 = line+16; x = g_ascii_strtod(line, &val2) * pow10(power10); y = g_ascii_strtod(val2, NULL) * pow10(power10); gwy_debug("Coord %i: x:%g y:%g", i, x, y); coords[2*i] = x; coords[2*i+1] = y; i++; } /* i is set to 0 and used as a counter for the dline */ i = 0; } if (strstr(line, "BEGIN") && !strstr(line, "COORD")) { /* Read spectroscopy points */ dline = gwy_data_line_new(channel->npoints, channel->end - channel->start, FALSE); gwy_data_line_set_offset(dline, (channel->start)); data = gwy_data_line_get_data(dline); j = 0; while ((line = gwy_str_next_line(&buffer))) { gchar *val2; if (strstr(line, "END") || j >= channel->npoints) break; val2 = line+13; x = g_ascii_strtod(line, &val2); y = g_ascii_strtod(val2, NULL)*scale; data[j] = y; j++; } /* Set Units for the parameter (x) axis */ if ((channel->param[0] == 'V') || (channel->param[0] == 'E')) { siunit = gwy_si_unit_new("V"); power10 = 0; } else if (channel->param[0] == 'I') siunit = gwy_si_unit_new_parse("nA", &power10); else if (channel->param[0] == 'Z') siunit = gwy_si_unit_new_parse("nm", &power10); else { gwy_debug("Parameter unit not recognised"); } if (siunit) { gwy_data_line_set_si_unit_x(dline, siunit); g_object_unref(siunit); } if (power10) { gdouble offset = 0; gdouble realsize = 0; offset = gwy_data_line_get_offset(dline)*pow10(power10); realsize = gwy_data_line_get_real(dline)*pow10(power10); gwy_data_line_set_offset(dline, offset); gwy_data_line_set_real(dline, realsize); } /* Set Units for the Value (y) Axis */ siunit = gwy_si_unit_new_parse(channel->units, &power10); gwy_data_line_set_si_unit_y(dline, siunit); g_object_unref(siunit); if (power10) gwy_data_line_multiply(dline, pow10(power10)); if (!spectrum) spectrum = g_ptr_array_sized_new(ncurves); g_ptr_array_add(spectrum, dline); } } if (!spectrum) spectrum = g_ptr_array_new(); if (spectrum->len < ncurves) { gwy_debug("Less actual spectra than ncurves"); ncurves = spectrum->len; } if (spectrum->len > ncurves) { gwy_debug("More actual spectra than ncurves, " "remaining pos will be set at (0.0,0.0)"); coords = g_renew(gdouble, coords, spectrum->len*2); if (!coords) { g_critical("Could not reallocate mem for coords."); return NULL; } while (spectrum->len > ncurves) { coords[ncurves*2] = 0.0; coords[ncurves*2+1] = 0.0; ncurves++; } } spectra = gwy_spectra_new(); if (coord_unit) { gwy_spectra_set_si_unit_xy(spectra, coord_unit); g_object_unref(coord_unit); } for (i = 0; i < ncurves; i++) { dline = g_ptr_array_index(spectrum, i); gwy_spectra_add_spectrum(spectra, dline, coords[i*2], ofile->yreal - coords[i*2+1]); g_object_unref(dline); } g_ptr_array_free(spectrum, TRUE); g_free(coords); g_free(buffer); return spectra; }
static GwyContainer* surffile_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { SurfFile surffile; gint coef = 0; GwyContainer *meta, *container = NULL; guchar *buffer = NULL; const guchar *p; gsize expected_size, size = 0; GError *err = NULL; gchar signature[12]; gint add = 0; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < SURF_HEADER_SIZE + 2) { err_TOO_SHORT(error); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } p = buffer; get_CHARARRAY(signature, &p); if (strncmp(signature, "DIGITAL SURF", 12) != 0) { err_FILE_TYPE(error, "Surf"); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } surffile.format = gwy_get_guint16_le(&p); surffile.nobjects = gwy_get_guint16_le(&p); surffile.version = gwy_get_guint16_le(&p); surffile.type = gwy_get_guint16_le(&p); get_CHARS0(surffile.object_name, &p, 30); get_CHARS0(surffile.operator_name, &p, 30); surffile.material_code = gwy_get_guint16_le(&p); surffile.acquisition = gwy_get_guint16_le(&p); surffile.range = gwy_get_guint16_le(&p); surffile.special_points = gwy_get_guint16_le(&p); surffile.absolute = gwy_get_guint16_le(&p); /*reserved*/ p += 8; surffile.pointsize = gwy_get_guint16_le(&p); surffile.zmin = gwy_get_gint32_le(&p); surffile.zmax = gwy_get_gint32_le(&p); surffile.xres = gwy_get_gint32_le(&p); surffile.yres = gwy_get_gint32_le(&p); surffile.nofpoints = gwy_get_guint32_le(&p); surffile.dx = gwy_get_gfloat_le(&p); surffile.dy = gwy_get_gfloat_le(&p); surffile.dz = gwy_get_gfloat_le(&p); get_CHARS0(surffile.xaxis, &p, 16); get_CHARS0(surffile.yaxis, &p, 16); get_CHARS0(surffile.zaxis, &p, 16); get_CHARS0(surffile.dx_unit, &p, 16); get_CHARS0(surffile.dy_unit, &p, 16); get_CHARS0(surffile.dz_unit, &p, 16); get_CHARS0(surffile.xlength_unit, &p, 16); get_CHARS0(surffile.ylength_unit, &p, 16); get_CHARS0(surffile.zlength_unit, &p, 16); surffile.xunit_ratio = gwy_get_gfloat_le(&p); surffile.yunit_ratio = gwy_get_gfloat_le(&p); surffile.zunit_ratio = gwy_get_gfloat_le(&p); surffile.imprint = gwy_get_guint16_le(&p); surffile.inversion = gwy_get_guint16_le(&p); surffile.leveling = gwy_get_guint16_le(&p); p += 12; surffile.seconds = gwy_get_guint16_le(&p); surffile.minutes = gwy_get_guint16_le(&p); surffile.hours = gwy_get_guint16_le(&p); surffile.day = gwy_get_guint16_le(&p); surffile.month = gwy_get_guint16_le(&p); surffile.year = gwy_get_guint16_le(&p); surffile.dayof = gwy_get_guint16_le(&p); surffile.measurement_duration = gwy_get_gfloat_le(&p); p += 10; surffile.comment_size = gwy_get_guint16_le(&p); surffile.private_size = gwy_get_guint16_le(&p); get_CHARARRAY(surffile.client_zone, &p); surffile.XOffset = gwy_get_gfloat_le(&p); surffile.YOffset = gwy_get_gfloat_le(&p); surffile.ZOffset = gwy_get_gfloat_le(&p); gwy_debug("fileformat: %d, n_of_objects: %d, " "version: %d, object_type: %d", surffile.format, surffile.nobjects, surffile.version, surffile.type); gwy_debug("object name: <%s>", surffile.object_name); gwy_debug("operator name: <%s>", surffile.operator_name); gwy_debug("material code: %d, acquisition type: %d", surffile.material_code, surffile.acquisition); gwy_debug("range type: %d, special points: %d, absolute: %d", surffile.range, surffile.special_points, (gint)surffile.absolute); gwy_debug("data point size: %d", surffile.pointsize); gwy_debug("zmin: %d, zmax: %d", surffile.zmin, surffile.zmax); gwy_debug("xres: %d, yres: %d (xres*yres = %d)", surffile.xres, surffile.yres, (surffile.xres*surffile.yres)); gwy_debug("total number of points: %d", surffile.nofpoints); gwy_debug("dx: %g, dy: %g, dz: %g", surffile.dx, surffile.dy, surffile.dz); gwy_debug("X axis name: %16s", surffile.xaxis); gwy_debug("Y axis name: %16s", surffile.yaxis); gwy_debug("Z axis name: %16s", surffile.zaxis); gwy_debug("dx unit: %16s", surffile.dx_unit); gwy_debug("dy unit: %16s", surffile.dy_unit); gwy_debug("dz unit: %16s", surffile.dz_unit); gwy_debug("X axis unit: %16s", surffile.xlength_unit); gwy_debug("Y axis unit: %16s", surffile.ylength_unit); gwy_debug("Z axis unit: %16s", surffile.zlength_unit); gwy_debug("xunit_ratio: %g, yunit_ratio: %g, zunit_ratio: %g", surffile.xunit_ratio, surffile.yunit_ratio, surffile.zunit_ratio); gwy_debug("imprint: %d, inversion: %d, leveling: %d", surffile.imprint, surffile.inversion, surffile.leveling); gwy_debug("Time: %d:%d:%d, Date: %d.%d.%d", surffile.hours, surffile.minutes, surffile.seconds, surffile.day, surffile.month, surffile.year); gwy_debug("private zone size: %d, comment size %d", surffile.private_size, surffile.comment_size); if (err_DIMENSION(error, surffile.xres) || err_DIMENSION(error, surffile.yres)) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } expected_size = (SURF_HEADER_SIZE + surffile.pointsize/8*surffile.xres*surffile.yres); if (expected_size != size) { gwy_debug("Size mismatch!"); if (size > expected_size) add = size - expected_size; /*TODO correct this !*/ else { err_SIZE_MISMATCH(error, expected_size, size, TRUE); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } } /* Use negated positive conditions to catch NaNs */ if (!((surffile.dx = fabs(surffile.dx)) > 0)) { g_warning("Real x step is 0.0, fixing to 1.0"); surffile.dx = 1.0; } if (!((surffile.dy = fabs(surffile.dy)) > 0)) { g_warning("Real y step is 0.0, fixing to 1.0"); surffile.dy = 1.0; } p = buffer + SURF_HEADER_SIZE + add; /*units*/ coef = 0; surffile.xyunit = gwy_si_unit_new_parse(surffile.dx_unit, &coef); surffile.dx *= pow10(coef); coef = 0; surffile.xyunit = gwy_si_unit_new_parse(surffile.dy_unit, &coef); surffile.dy *= pow10(coef); coef = 0; surffile.zunit = gwy_si_unit_new_parse (surffile.dz_unit, &coef); if (!fill_data_fields(&surffile, p, error)) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } switch (surffile.inversion) { case SURF_INV_Z: gwy_data_field_invert(surffile.dfield, FALSE, FALSE, TRUE); break; case SURF_FLIP_Z: gwy_data_field_invert(surffile.dfield, FALSE, TRUE, TRUE); break; case SURF_FLOP_Z: gwy_data_field_invert(surffile.dfield, TRUE, FALSE, TRUE); break; default: break; } gwy_data_field_multiply(surffile.dfield, pow10(coef)); surffile.ZOffset *= pow10(coef); gwy_data_field_add(surffile.dfield, surffile.ZOffset); container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", surffile.dfield); g_object_unref(surffile.dfield); meta = surffile_get_metadata(&surffile); gwy_container_set_object_by_name(container, "/0/meta", meta); g_object_unref(meta); gwy_app_channel_check_nonsquare(container, 0); gwy_file_channel_import_log_add(container, 0, NULL, filename); return container; }
static GwyDataField* read_data_field(const guchar *buffer, guint size, guchar version, gchar **title, gint *direction, GError **error) { enum { MIN_REMAINDER = 2620 }; /* information offsets in different versions, in r5+ relative to data * start, in order: * data offset, * pixel dimensions, * physical dimensions, * value multiplier, * unit string, * data type, (if zero, use channel title) * channel title (if zero, use data type) */ const guint offsets34[] = { 0x0104, 0x0196, 0x01a2, 0x01b2, 0x01c2, 0x0400, 0x0000 }; const guint offsets56[] = { 0x0104, 0x025c, 0x0268, 0x0288, 0x02a0, 0x0708, 0x0000 }; const guint offsets7[] = { 0x0104, 0x029c, 0x02a8, 0x02c8, 0x02e0, 0x0000, 0x0b90 }; gint xres, yres, doffset, i, power10, type; gdouble xreal, yreal, q, z0; GwyDataField *dfield; GwySIUnit *unitxy, *unitz; gdouble *data; const guint *offset; const guchar *p, *r, *last; /* get floats in single precision from r4 but double from r5+ */ gdouble (*getflt)(const guchar**); *title = NULL; *direction = -1; if (version == '5' || version == '6' || version == '7') { /* There are more headers in r5, * try to find something that looks like #R5. */ last = r = buffer; while ((p = memchr(r, '#', size - (r - buffer) - MIN_REMAINDER))) { if (p[1] == 'R' && p[2] == version && p[3] == '.') { gwy_debug("pos: %ld", (long)(p - buffer)); last = p; r = p + MIN_REMAINDER-1; } else r = p + 1; } offset = (version == '7') ? &offsets7[0] : &offsets56[0]; buffer = last; getflt = &gwy_get_gdouble_le; } else { offset = &offsets34[0]; getflt = &get_gfloat_le_as_double; } p = buffer + *(offset++); doffset = gwy_get_guint32_le(&p); /* this appears to be the same number as in the ASCII miniheader -- so get it here since it's easier */ gwy_debug("data offset = %u", doffset); p = buffer + *(offset++); xres = gwy_get_guint32_le(&p); yres = gwy_get_guint32_le(&p); if (err_DIMENSION(error, xres) || err_DIMENSION(error, yres)) return NULL; p = buffer + *(offset++); xreal = -getflt(&p); xreal += getflt(&p); yreal = -getflt(&p); yreal += getflt(&p); 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; } p = buffer + *(offset++); q = getflt(&p); z0 = getflt(&p); gwy_debug("xreal.raw = %g, yreal.raw = %g, q.raw = %g, z0.raw = %g", xreal, yreal, q, z0); p = buffer + *(offset++); unitz = gwy_si_unit_new_parse(p, &power10); q *= pow10(power10); z0 *= pow10(power10); unitxy = gwy_si_unit_new_parse(p + 10, &power10); xreal *= pow10(power10); yreal *= pow10(power10); gwy_debug("xres = %d, yres = %d, xreal = %g, yreal = %g, q = %g, z0 = %g", xres, yres, xreal, yreal, q, z0); gwy_debug("unitxy = %s, unitz = %s", p, p + 10); if (offset[1]) { /* We know channel title */ offset++; p = buffer + *(offset++); *title = g_strndup(p, size - (p - buffer)); gwy_debug("title = <%s>", *title); } else { /* We know data type */ p = buffer + *(offset++); type = gwy_get_guint16_le(&p); *direction = gwy_get_guint16_le(&p); gwy_debug("type = %d, dir = %d", type, *direction); offset++; *title = type_to_title(type); } p = buffer + doffset; if (err_SIZE_MISMATCH(error, 2*xres*yres, size - (p - buffer), FALSE)) return NULL; dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE); gwy_data_field_set_si_unit_xy(dfield, unitxy); g_object_unref(unitxy); gwy_data_field_set_si_unit_z(dfield, unitz); g_object_unref(unitz); data = gwy_data_field_get_data(dfield); for (i = 0; i < xres*yres; i++) data[i] = (p[2*i] + 256.0*p[2*i + 1])*q + z0; return dfield; }
static GwyContainer* lif_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL; LIFHeader *header = NULL; LIFMemBlock *memblock = NULL; LIFFile *file = NULL; LIFElement *element = NULL; LIFDimension *dimension = NULL; LIFChannel *channel = NULL; gsize size = 0, memblock_size = 0; gint64 remaining = 0; gchar *buffer; const guchar *p; GError *err = NULL; GwyDataField *dfield = NULL; GwyBrick *brick = NULL; gdouble *data = NULL; gint i, j, channelno = 0, volumeno = 0; gchar *strkey, *lutname; GMarkupParser parser = { header_start_element, header_end_element, header_parse_text, NULL, NULL }; GMarkupParseContext *context; XMLParserData *xmldata; gint x, xres, xstep, y, yres, ystep, z, zres, zstep, offset, res; gdouble xreal, yreal, zreal, xoffset, yoffset, zoffset; gdouble zscale = 1.0, wscale = 1.0; GwySIUnit *siunitxy = NULL, *siunitz = NULL; GwySIUnit *siunitx = NULL, *siunity = NULL, *siunitw = NULL; gint power10xy = 1; gint power10x = 1, power10y = 1, power10z = 1, power10w = 1; if (!g_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); goto fail; } if (size < 13) { /* header too short */ err_TOO_SHORT(error); goto fail; } p = buffer; remaining = size; header = g_new0(LIFHeader, 1); header->magic = gwy_get_gint32_le(&p); gwy_debug("Magic = %d", header->magic); header->size = gwy_get_guint32_le(&p); gwy_debug("Size = %d", header->size); header->testcode = *(p++); gwy_debug("Testcode = 0x%x", header->testcode); if (header->testcode != TESTCODE) { err_FILE_TYPE(error, "Leica LIF"); goto fail; } header->xmllen = gwy_get_guint32_le(&p); gwy_debug("XML length = %d", header->xmllen); if (size < 13 + header->xmllen * 2) { err_TOO_SHORT(error); goto fail; } remaining -= 13; header->xmlheader = g_convert((const gchar*)p, 2 * header->xmllen, "UTF-8", "UTF-16", NULL, NULL, NULL); p += header->xmllen * 2; remaining -= header->xmllen * 2; // gwy_debug("%s", header->xmlheader); /* Parse XML header */ xmldata = g_new0(XMLParserData, 1); xmldata->file = g_new0(LIFFile, 1); xmldata->file->elements = g_array_new(FALSE, TRUE, sizeof(LIFElement)); xmldata->elements = g_ptr_array_new(); context = g_markup_parse_context_new(&parser, G_MARKUP_TREAT_CDATA_AS_TEXT, (gpointer)xmldata, NULL); if (!g_markup_parse_context_parse(context, header->xmlheader, -1, &err) || !g_markup_parse_context_end_parse(context, &err)) { error = &err; g_clear_error(&err); } g_markup_parse_context_free(context); file = xmldata->file; file->header = header; g_ptr_array_free(xmldata->elements, TRUE); g_free(xmldata); /* Reading memblocks */ file->memblocks = g_hash_table_new(g_str_hash, g_str_equal); while (remaining > 0) { memblock = lif_read_memblock(p, &memblock_size, file->version); if (!memblock) { break; } remaining -= memblock_size; if (remaining >= 0) { gwy_debug("remaining = %" G_GUINT64_FORMAT "", remaining); p += memblock_size; g_hash_table_insert(file->memblocks, memblock->memid, memblock); } } container = gwy_container_new(); for (i = 0; i < file->elements->len; i++) { element = &g_array_index(file->elements, LIFElement, i); if ((element->dimensions == NULL) || (element->channels == NULL)) { gwy_debug("Empty element"); continue; } gwy_debug("Dimensions = %d channels=%d", element->dimensions->len, element->channels->len); gwy_debug("memid=%s", element->memid); /* check if we can load this type of data into * Gwyddion structures */ res = 0; if ((element->dimensions->len != 2) && (element->dimensions->len != 3)) { /* check for case ndim == 4 && res == 1 */ for (i = 0; i < element->dimensions->len; i++) { dimension = &g_array_index(element->dimensions, LIFDimension, i); xres = dimension->res; gwy_debug("dim[%d].res=%d", i, xres); if (i == 2) { res = xres; } } if ((element->dimensions->len == 4) && (res == 1)) { gwy_debug("4D volume"); } else { gwy_debug("not loading"); continue; } } memblock = (LIFMemBlock *)g_hash_table_lookup(file->memblocks, element->memid); if (!memblock) { gwy_debug("Failed to locate memblock with key %s", element->memid); continue; } p = memblock->data; if (element->dimensions->len == 2) { /* Image */ for (j = 0; j < element->channels->len; j++) { dimension = &g_array_index(element->dimensions, LIFDimension, 0); xres = dimension->res; xreal = dimension->length; xoffset = dimension->origin; xstep = dimension->bytesinc; siunitxy = gwy_si_unit_new_parse(dimension->unit, &power10xy); dimension = &g_array_index(element->dimensions, LIFDimension, 1); yres = dimension->res; yreal = dimension->length; yoffset = dimension->origin; ystep = dimension->bytesinc; if (xreal <= 0.0) xreal = 1.0; if (yreal <= 0.0) yreal = 1.0; channel = &g_array_index(element->channels, LIFChannel, j); offset = channel->bytesinc; siunitz = gwy_si_unit_new_parse(channel->unit, &power10z); zscale = pow10(power10z); if (offset + (xres - 1) * xstep + (yres - 1)* ystep > memblock->memsize) { gwy_debug("Memblock too small"); gwy_debug("%d %" G_GUINT64_FORMAT "", offset + (xres-1)*xstep + (yres-1)*ystep, memblock->memsize); err_SIZE_MISMATCH(error, memblock->memsize, offset+(xres-1)*xstep +(yres-1)*ystep, FALSE); goto fail; } dfield = gwy_data_field_new(xres, yres, xreal*pow10(power10xy), yreal*pow10(power10xy), TRUE); gwy_data_field_set_xoffset(dfield, xoffset*pow10(power10xy)); gwy_data_field_set_yoffset(dfield, yoffset*pow10(power10xy)); data = gwy_data_field_get_data(dfield); for (y = 0; y < yres; y++) for (x = 0; x < xres; x++) { *(data++) = zscale * (gdouble)*(p + offset + x*xstep + y*ystep); } if (siunitxy) { gwy_data_field_set_si_unit_xy(dfield, siunitxy); g_object_unref(siunitxy); } if (siunitz) { gwy_data_field_set_si_unit_z(dfield, siunitz); g_object_unref(siunitz); } strkey = g_strdup_printf("/%d/data", channelno); gwy_container_set_object_by_name(container, strkey, dfield); g_object_unref(dfield); g_free(strkey); if (element->name) { strkey = g_strdup_printf("/%d/data/title", channelno); gwy_container_set_string_by_name(container, strkey, g_strdup(element->name)); g_free(strkey); } if (element->metadata) { strkey = g_strdup_printf("/%d/meta", channelno); gwy_container_set_object_by_name(container, strkey, element->metadata); g_free(strkey); } if (channel->lut) { lutname = NULL; if (gwy_strequal(channel->lut, "Red")) lutname = g_strdup_printf("RGB-Red"); else if (gwy_strequal(channel->lut, "Green")) lutname = g_strdup_printf("RGB-Green"); else if (gwy_strequal(channel->lut, "Blue")) lutname = g_strdup_printf("RGB-Blue"); else if (gwy_strequal(channel->lut, "Gray")) lutname = g_strdup_printf("Gray"); if (lutname) { strkey = g_strdup_printf("/%u/base/palette", channelno); gwy_container_set_string_by_name(container, strkey, lutname); g_free(strkey); } } gwy_file_channel_import_log_add(container, channelno, NULL, filename); channelno++; } } else if ((element->dimensions->len == 3) || ((element->dimensions->len == 4) && (res == 1))) { /* Volume */ for (j = 0; j < element->channels->len; j++) { dimension = &g_array_index(element->dimensions, LIFDimension, 0); xres = dimension->res; xreal = dimension->length; xoffset = dimension->origin; xstep = dimension->bytesinc; siunitx = gwy_si_unit_new_parse(dimension->unit, &power10x); dimension = &g_array_index(element->dimensions, LIFDimension, 1); yres = dimension->res; yreal = dimension->length; yoffset = dimension->origin; ystep = dimension->bytesinc; siunity = gwy_si_unit_new_parse(dimension->unit, &power10y); if (element->dimensions->len == 3) { dimension = &g_array_index(element->dimensions, LIFDimension, 2); } else { dimension = &g_array_index(element->dimensions, LIFDimension, 3); } zres = dimension->res; zreal = dimension->length; zoffset = dimension->origin; zstep = dimension->bytesinc; siunitz = gwy_si_unit_new_parse(dimension->unit, &power10z); channel = &g_array_index(element->channels, LIFChannel, j); offset = channel->bytesinc; siunitw = gwy_si_unit_new_parse(channel->unit, &power10w); wscale = pow10(power10w); if (offset + (xres-1)*xstep + (yres-1)*ystep + (zres-1)*zstep > memblock->memsize) { gwy_debug("Memblock too small"); gwy_debug("%d %" G_GUINT64_FORMAT "", offset + (xres-1)*xstep + (yres-1)*ystep + (zres-1)*zstep, memblock->memsize); err_SIZE_MISMATCH(error, memblock->memsize, offset + (xres-1)*xstep + (yres-1)*ystep + (zres-1)*zstep, FALSE); goto fail; } brick = gwy_brick_new(xres, yres, zres, xreal*pow10(power10x), yreal*pow10(power10y), zreal*pow10(power10z), TRUE); gwy_brick_set_xoffset(brick, xoffset*pow10(power10x)); gwy_brick_set_yoffset(brick, yoffset*pow10(power10y)); gwy_brick_set_zoffset(brick, zoffset*pow10(power10z)); data = gwy_brick_get_data(brick); for (z = 0; z < zres; z++) for (y = 0; y < yres; y++) for (x = 0; x < xres; x++) { *(data++) = wscale * (gdouble)*(p + offset + x*xstep + y*ystep + z*zstep); } if (siunitx) { gwy_brick_set_si_unit_x(brick, siunitx); g_object_unref(siunitx); } if (siunity) { gwy_brick_set_si_unit_y(brick, siunity); g_object_unref(siunity); } if (siunitz) { gwy_brick_set_si_unit_z(brick, siunitz); g_object_unref(siunitz); } if (siunitw) { gwy_brick_set_si_unit_w(brick, siunitw); g_object_unref(siunitw); } strkey = g_strdup_printf("/brick/%d", volumeno); gwy_container_set_object_by_name(container, strkey, brick); g_free(strkey); if (element->name) { strkey = g_strdup_printf("/brick/%d/title", volumeno); gwy_container_set_string_by_name(container, strkey, g_strdup(element->name)); g_free(strkey); } if (element->metadata) { strkey = g_strdup_printf("/brick/%d/meta", volumeno); gwy_container_set_object_by_name(container, strkey, element->metadata); g_free(strkey); } if (channel->lut) { lutname = NULL; if (gwy_strequal(channel->lut, "Red")) lutname = g_strdup_printf("RGB-Red"); else if (gwy_strequal(channel->lut, "Green")) lutname = g_strdup_printf("RGB-Green"); else if (gwy_strequal(channel->lut, "Blue")) lutname = g_strdup_printf("RGB-Blue"); else if (gwy_strequal(channel->lut, "Gray")) lutname = g_strdup_printf("Gray"); if (lutname) { strkey = g_strdup_printf("/brick/%d/preview/palette", volumeno); gwy_container_set_string_by_name(container, strkey, lutname); g_free(strkey); } } dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE); gwy_brick_mean_plane(brick, dfield, 0, 0, 0, xres, yres, -1, FALSE); strkey = g_strdup_printf("/brick/%d/preview", volumeno); gwy_container_set_object_by_name(container, strkey, dfield); g_free(strkey); g_object_unref(brick); g_object_unref(dfield); gwy_file_volume_import_log_add(container, volumeno, NULL, filename); volumeno++; } /* for (channels) */ } /* if (volume) */ } fail: /* freeing all stuff */ if (file) { if (file->memblocks) { g_hash_table_foreach_remove(file->memblocks, lif_remove_memblock, NULL); g_hash_table_unref(file->memblocks); } if (file->elements) { for (i = 0; i < file->elements->len; i++) { element = &g_array_index(file->elements, LIFElement, i); if (element->dimensions) { for (j = 0; j < element->dimensions->len; j++) { dimension = &g_array_index(element->dimensions, LIFDimension, j); if (dimension->unit) g_free(dimension->unit); } g_array_free(element->dimensions, TRUE); } if (element->channels) { for (j = 0; j < element->channels->len; j++) { channel = &g_array_index(element->channels, LIFChannel, j); if (channel->unit) g_free(channel->unit); if (channel->lut) g_free(channel->lut); } g_array_free(element->channels, TRUE); } if (element->name) g_free(element->name); if (element->memid) g_free(element->memid); if (element->metadata) g_object_unref(element->metadata); } g_array_free(file->elements, TRUE); } g_free(file); } if (header->xmlheader) g_free(header->xmlheader); if (header) { g_free(header); } return container; }
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; }