static void merge_do_join(MergeArgs *args) { GwyDataField *dfield1, *dfield2; gint xres1, xres2, yres1, yres2; gint maxover, i, off = 0; gint px1, py1, px2, py2; GwyContainer *data1, *data2; gdouble s, smin = G_MAXDOUBLE; GwyMergeBoundaryType real_boundary = args->boundary; GwyMergeDirectionType real_dir = args->direction; GQuark quark; data1 = gwy_app_data_browser_get(args->op1.datano); quark = gwy_app_get_data_key_for_id(args->op1.id); dfield1 = GWY_DATA_FIELD(gwy_container_get_object(data1, quark)); data2 = gwy_app_data_browser_get(args->op2.datano); quark = gwy_app_get_data_key_for_id(args->op2.id); dfield2 = GWY_DATA_FIELD(gwy_container_get_object(data2, quark)); /* Reduce joining to two cases. */ if (args->direction == GWY_MERGE_DIRECTION_UP || args->direction == GWY_MERGE_DIRECTION_LEFT) { GWY_SWAP(GwyDataField*, dfield1, dfield2); if (args->direction == GWY_MERGE_DIRECTION_UP) real_dir = GWY_MERGE_DIRECTION_DOWN; else if (args->direction == GWY_MERGE_DIRECTION_LEFT) real_dir = GWY_MERGE_DIRECTION_RIGHT; else { g_assert_not_reached(); } if (args->boundary == GWY_MERGE_BOUNDARY_FIRST) real_boundary = GWY_MERGE_BOUNDARY_SECOND; else if (args->boundary == GWY_MERGE_BOUNDARY_SECOND) real_boundary = GWY_MERGE_BOUNDARY_FIRST; } xres1 = gwy_data_field_get_xres(dfield1); yres1 = gwy_data_field_get_yres(dfield1); xres2 = gwy_data_field_get_xres(dfield2); yres2 = gwy_data_field_get_yres(dfield2); if (real_dir == GWY_MERGE_DIRECTION_DOWN) { g_return_if_fail(xres1 == xres2); maxover = 2*MIN(yres1, yres2)/5; for (i = 1; i <= maxover; i++) { s = get_row_difference(dfield1, 0, yres1 - i, dfield2, 0, 0, xres1, i); if (s < smin) { off = i; smin = s; } } /* Turn one-pixel overlap to no overlap. */ if (off == 1) off = 0; px1 = px2 = 0; py1 = 0; py2 = yres1 - off; } else if (real_dir == GWY_MERGE_DIRECTION_RIGHT) { g_return_if_fail(yres1 == yres2); maxover = 2*MIN(xres1, xres2)/5; for (i = 1; i <= maxover; i++) { s = get_column_difference(dfield1, xres1 - i, 0, dfield2, 0, 0, i, yres1); if (s < smin) { off = i; smin = s; } } /* Turn one-pixel overlap to no overlap. */ if (off == 1) off = 0; py1 = py2 = 0; px1 = 0; px2 = xres1 - off; } else { g_assert_not_reached(); } create_merged_field(data1, args->op1.id, dfield1, dfield2, px1, py1, px2, py2, real_boundary, real_dir, FALSE, FALSE); }
static GwyContainer* int_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL, *meta; GwyDataField *dfield = NULL, *mfield = NULL; CodeVGridDataType type; gchar *line, *p, *comment, *end, *buffer = NULL; const gchar *unit, *title; gchar **fields = NULL; gsize size; GError *err = NULL; gdouble xreal, yreal; gint i, xres, yres, no_data_value = 32767; guint fi; gdouble scale_size, wavelength, q = 1.0, x_scale = 1.0; gboolean nearest_neighbour = FALSE; gdouble *data, *mdata; if (!g_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); goto fail; } /* Skip comments. */ p = buffer; for (line = gwy_str_next_line(&p); line && line[0] == '!'; line = gwy_str_next_line(&p)) { gwy_debug("comment <%s>", line); } if (!line) { err_FILE_TYPE(error, "Code V INT"); goto fail; } /* The title. */ comment = line; if (!(line = gwy_str_next_line(&p))) { err_FILE_TYPE(error, "Code V INT"); goto fail; } gwy_debug("comment <%s>", comment); fields = split_line_in_place(line); if (!fields || g_strv_length(fields) < 8 || !gwy_strequal(fields[0], "GRD") || !(xres = atoi(fields[1])) || !(yres = atoi(fields[2])) || !(type = gwy_stramong(fields[3], "SUR", "WFR", "FIL", "THV", "BIR", "CAO", NULL)) || !gwy_strequal(fields[4], "WVL") || (!(wavelength = g_ascii_strtod(fields[5], &end)) && end == fields[5])) { err_FILE_TYPE(error, "Code V INT"); goto fail; } gwy_debug("type %u (%s)", type, fields[3]); gwy_debug("xres %d, yres %d", xres, yres); gwy_debug("wavelength %g", wavelength); fi = 6; if (gwy_strequal(fields[fi], "NNB")) { nearest_neighbour = TRUE; fi++; } gwy_debug("nearest_neighbour %d", nearest_neighbour); if (!fields[fi] || !gwy_strequal(fields[fi], "SSZ")) { err_FILE_TYPE(error, "Code V INT"); goto fail; } fi++; if (!(scale_size = g_ascii_strtod(fields[fi], &end)) && end == fields[fi]) { err_FILE_TYPE(error, "Code V INT"); goto fail; } gwy_debug("scale_size %g", scale_size); if (!scale_size) { g_warning("Zero SSZ, fixing to 1.0"); scale_size = 1.0; } fi++; if (fields[fi] && gwy_strequal(fields[fi], "NDA")) { fi++; if (!fields[fi]) { err_FILE_TYPE(error, "Code V INT"); goto fail; } no_data_value = atoi(fields[fi]); fi++; } gwy_debug("no_data_value %d", no_data_value); if (fields[fi] && gwy_strequal(fields[fi], "XSC")) { fi++; if (!fields[fi]) { err_FILE_TYPE(error, "Code V INT"); goto fail; } if (!(x_scale = g_ascii_strtod(fields[fi], &end)) && end == fields[fi]) { err_FILE_TYPE(error, "Code V INT"); goto fail; } fi++; } gwy_debug("x_scale %g", x_scale); if (!x_scale) { g_warning("Zero XSC, fixing to 1.0"); x_scale = 1.0; } /* There may be more stuff but we do not know anything about it. */ if (err_DIMENSION(error, xres) || err_DIMENSION(error, yres)) goto fail; yreal = 1.0; xreal = x_scale*yreal; dfield = gwy_data_field_new(xres, yres, xreal, yreal, TRUE); if (type == CODEV_INT_SURFACE_DEFORMATION) { q = 1e-6*wavelength/scale_size; unit = "m"; title = "Surface"; } else if (type == CODEV_INT_WAVEFRONT_DEFORMATION) { q = 1e-6*wavelength/scale_size; unit = "m"; title = "Wavefront"; } else { g_warning("Don't know how to convert this grid data type to physical " "units."); title = fields[3]; } gwy_si_unit_set_from_string(gwy_data_field_get_si_unit_z(dfield), unit); mfield = gwy_data_field_new_alike(dfield, TRUE); data = gwy_data_field_get_data(dfield); mdata = gwy_data_field_get_data(mfield); for (i = 0; i < xres*yres; i++, p = end) { gint value = strtol(p, &end, 10); if (value != no_data_value && (type != CODEV_INT_INTENSITY_FILTER || value >= 0)) { mdata[i] = 1.0; data[i] = q*value; } } if (!gwy_app_channel_remove_bad_data(dfield, mfield)) gwy_object_unref(mfield); container = gwy_container_new(); /* gwy_data_field_invert(dfield, TRUE, FALSE, FALSE); from F. Riguet : apparently no flip is needed (the raw data import module gives the correct orientation without further flipping) */ gwy_container_set_object(container, gwy_app_get_data_key_for_id(0), dfield); g_object_unref(dfield); gwy_app_channel_check_nonsquare(container, 0); gwy_container_set_string_by_name(container, "/0/data/title", g_strdup(title)); if (mfield) { /* gwy_data_field_invert(mfield, FALSE, TRUE, FALSE); */ gwy_container_set_object(container, gwy_app_get_mask_key_for_id(0), mfield); g_object_unref(mfield); } meta = gwy_container_new(); gwy_container_set_string_by_name(meta, "Comment", g_strdup(comment)); gwy_container_set_string_by_name(meta, "Interpolation", g_strdup(nearest_neighbour ? "NNB" : "Linear")); gwy_container_set_string_by_name(meta, "Wavelength", g_strdup_printf("%g μm", wavelength)); 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: g_free(fields); g_free(buffer); 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 void merge_do_correlate(MergeArgs *args) { GwyDataField *dfield1, *dfield2; GwyDataField *correlation_data, *correlation_kernel, *correlation_score; GwyRectangle cdata, kdata; gint max_col, max_row; gint xres1, xres2, yres1, yres2; GwyMergeDirectionType real_dir = args->direction; GwyMergeBoundaryType real_boundary = args->boundary; gint px1, py1, px2, py2; GwyContainer *data1, *data2; GQuark quark; data1 = gwy_app_data_browser_get(args->op1.datano); quark = gwy_app_get_data_key_for_id(args->op1.id); dfield1 = GWY_DATA_FIELD(gwy_container_get_object(data1, quark)); data2 = gwy_app_data_browser_get(args->op2.datano); quark = gwy_app_get_data_key_for_id(args->op2.id); dfield2 = GWY_DATA_FIELD(gwy_container_get_object(data2, quark)); if ((dfield1->xres*dfield1->yres) < (dfield2->xres*dfield2->yres)) { GWY_SWAP(GwyDataField*, dfield1, dfield2); if (args->direction == GWY_MERGE_DIRECTION_UP) real_dir = GWY_MERGE_DIRECTION_DOWN; else if (args->direction == GWY_MERGE_DIRECTION_DOWN) real_dir = GWY_MERGE_DIRECTION_UP; else if (args->direction == GWY_MERGE_DIRECTION_LEFT) real_dir = GWY_MERGE_DIRECTION_RIGHT; else if (args->direction == GWY_MERGE_DIRECTION_RIGHT) real_dir = GWY_MERGE_DIRECTION_LEFT; else g_return_if_reached(); if (args->boundary == GWY_MERGE_BOUNDARY_FIRST) real_boundary = GWY_MERGE_BOUNDARY_SECOND; else if (args->boundary == GWY_MERGE_BOUNDARY_SECOND) real_boundary = GWY_MERGE_BOUNDARY_FIRST; } xres1 = gwy_data_field_get_xres(dfield1); xres2 = gwy_data_field_get_xres(dfield2); yres1 = gwy_data_field_get_yres(dfield1); yres2 = gwy_data_field_get_yres(dfield2); /*cut data for correlation*/ switch (real_dir) { case GWY_MERGE_DIRECTION_UP: cdata.x = 0; cdata.y = 0; cdata.width = xres1; cdata.height = yres1/2; kdata.width = MIN(xres2, cdata.width/2); kdata.height = MIN(yres2, cdata.height/3); kdata.x = MAX(0, xres2/2 - kdata.width/2); kdata.y = MAX(0, yres2 - cdata.height/3); break; case GWY_MERGE_DIRECTION_DOWN: cdata.x = 0; cdata.y = yres1 - (yres1/2); cdata.width = xres1; cdata.height = yres1/2; kdata.width = MIN(xres2, cdata.width/2); kdata.height = MIN(yres2, cdata.height/3); kdata.x = MAX(0, xres2/2 - kdata.width/2); kdata.y = 0; break; case GWY_MERGE_DIRECTION_RIGHT: cdata.x = xres1 - (xres1/2); cdata.y = 0; cdata.width = xres1/2; cdata.height = yres1; kdata.width = MIN(xres2, cdata.width/3); kdata.height = MIN(yres2, cdata.height/2); kdata.x = 0; kdata.y = MAX(0, yres2/2 - kdata.height/2); break; case GWY_MERGE_DIRECTION_LEFT: cdata.x = 0; cdata.y = 0; cdata.width = xres1/2; cdata.height = yres1; kdata.width = MIN(xres2, cdata.width/3); kdata.height = MIN(yres2, cdata.height/2); kdata.x = MAX(0, xres2 - cdata.width/3); kdata.y = MAX(0, yres2/2 - kdata.height/2); break; default: g_assert_not_reached(); break; } correlation_data = gwy_data_field_area_extract(dfield1, cdata.x, cdata.y, cdata.width, cdata.height); correlation_kernel = gwy_data_field_area_extract(dfield2, kdata.x, kdata.y, kdata.width, kdata.height); correlation_score = gwy_data_field_new_alike(correlation_data, FALSE); /* get appropriate correlation score */ if (!get_score_iteratively(correlation_data, correlation_kernel, correlation_score, args)) goto end; find_score_maximum(correlation_score, &max_col, &max_row); gwy_debug("c: %d %d %dx%d k: %d %d %dx%d res: %d %d", cdata.x, cdata.y, cdata.width, cdata.height, kdata.x, kdata.y, kdata.width, kdata.height, max_col, max_row); px1 = 0; px2 = (max_col - (kdata.width-1)/2) + cdata.x - kdata.x; py1 = 0; py2 = (max_row - (kdata.height-1)/2) + cdata.y - kdata.y; if (px2 < 0) { px1 = -px2; px2 = 0; } if (py2 < 0) { py1 = -py2; py2 = 0; } create_merged_field(data1, args->op1.id, dfield1, dfield2, px1, py1, px2, py2, real_boundary, real_dir, args->create_mask, args->crop_to_rectangle); end: g_object_unref(correlation_data); g_object_unref(correlation_kernel); g_object_unref(correlation_score); }
static GwyContainer* burleigh_exp_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL; gchar *buffer = NULL; BurleighExpHeader header; gsize size = 0; GError *err = NULL; GwyDataField *dfield; gdouble *data; guint i, n; if (!g_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < MIN_FILE_SIZE + 2) { err_TOO_SHORT(error); g_free(buffer); return NULL; } if (!burleigh_exp_read_header(&header, buffer, error)) goto fail; n = header.xres * header.yres; if (header.binary) { if (header.bpp != 16) { err_BPP(error, header.bpp); goto fail; } else if (err_SIZE_MISMATCH(error, header.length + 2*n, size, TRUE)) goto fail; } dfield = gwy_data_field_new(header.xres, header.yres, header.xscale, header.yscale, FALSE); data = gwy_data_field_get_data(dfield); if (header.binary) { const gint16 *d16 = (const gint16*)(buffer + header.length); for (i = 0; i < n; i++) data[i] = GINT16_FROM_LE(d16[i]); } else { gchar *p = buffer + header.length; for (i = 0; i < n; i++) data[i] = strtol(p, &p, 10); } gwy_data_field_multiply(dfield, header.zscale/32768.0); /* Units references released in free_header() */ gwy_data_field_set_si_unit_xy(dfield, header.xyunits); gwy_data_field_set_si_unit_z(dfield, header.zunits); container = gwy_container_new(); gwy_container_set_object(container, gwy_app_get_data_key_for_id(0), dfield); g_object_unref(dfield); gwy_app_channel_title_fall_back(container, 0); fail: free_header(&header); g_free(buffer); return container; }
static GwyContainer* sensofar_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { SensofarDataDesc data_desc; GwyContainer *container = NULL; GwyDataField *dfield, *mfield; GwyGraphModel *gmodel; guchar *buffer = NULL; gsize size = 0; GError *err = NULL; const guchar *p; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < HEADER_SIZE + 12) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("File header is truncated")); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } /* Date block */ p = buffer; memcpy(&data_desc.date.str, p, DATE_SIZE); data_desc.date.str[DATE_SIZE-1] = '\0'; p += DATE_SIZE; data_desc.date.t = gwy_get_guint32_le(&p); /* Comment block */ memcpy(&data_desc.user_comment, p, COMMENT_SIZE); data_desc.user_comment[COMMENT_SIZE-1] = '\0'; p += COMMENT_SIZE; /* Calbration block */ data_desc.axes_config.yres = gwy_get_guint32_le(&p); data_desc.axes_config.xres = gwy_get_guint32_le(&p); data_desc.axes_config.N_tall = gwy_get_guint32_le(&p); data_desc.axes_config.dy_multip = gwy_get_gfloat_le(&p); data_desc.axes_config.mppx = gwy_get_gfloat_le(&p); data_desc.axes_config.mppy = gwy_get_gfloat_le(&p); data_desc.axes_config.x_0 = gwy_get_gfloat_le(&p); data_desc.axes_config.y_0 = gwy_get_gfloat_le(&p); data_desc.axes_config.mpp_tall = gwy_get_gfloat_le(&p); data_desc.axes_config.z_0 = gwy_get_gfloat_le(&p); /* Measurement block */ data_desc.measure_config.type = gwy_get_guint32_le(&p); data_desc.measure_config.algorithm = gwy_get_guint32_le(&p); data_desc.measure_config.method = gwy_get_guint32_le(&p); data_desc.measure_config.objective = gwy_get_guint32_le(&p); data_desc.measure_config.area = gwy_get_guint32_le(&p); data_desc.measure_config.xres_area = gwy_get_guint32_le(&p); data_desc.measure_config.yres_area = gwy_get_guint32_le(&p); data_desc.measure_config.xres = gwy_get_guint32_le(&p); data_desc.measure_config.yres = gwy_get_guint32_le(&p); data_desc.measure_config.na = gwy_get_guint32_le(&p); data_desc.measure_config.incr_z = gwy_get_gdouble_le(&p); data_desc.measure_config.range = gwy_get_gfloat_le(&p); data_desc.measure_config.n_planes = gwy_get_guint32_le(&p); data_desc.measure_config.tpc_umbral_F = gwy_get_guint32_le(&p); data_desc.measure_config.restore = gwy_get_gboolean8(&p); data_desc.measure_config.num_layers = *(p++); data_desc.measure_config.version = *(p++); data_desc.measure_config.config_hardware = *(p++); data_desc.measure_config.stack_im_num = *(p++); data_desc.measure_config.reserved = *(p++); p += 2; // struct padding data_desc.measure_config.factor_delmacio = gwy_get_guint32_le(&p); gwy_debug("File date=<%s>, data type=%d, xres=%d, yres=%d, version=%d", data_desc.date.str, data_desc.measure_config.type, data_desc.measure_config.xres, data_desc.measure_config.yres, data_desc.measure_config.version); switch (data_desc.measure_config.type) { case MES_TOPO: case MES_IMATGE: dfield = sensofar_read_data_field(&data_desc, &mfield, &p, size - (p - buffer), error); if (!dfield) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } container = gwy_container_new(); gwy_container_set_object(container, gwy_app_get_data_key_for_id(0), dfield); g_object_unref(dfield); if (mfield) { gwy_container_set_object(container, gwy_app_get_mask_key_for_id(0), mfield); g_object_unref(mfield); } gwy_app_channel_title_fall_back(container, 0); break; case MES_PERFIL: case MES_GRUIX: gmodel = sensofar_read_profile(&data_desc, &p, size - (p - buffer), error); if (!gmodel) { gwy_file_abandon_contents(buffer, size, NULL); return NULL; } container = gwy_container_new(); gwy_container_set_object(container, gwy_app_get_graph_key_for_id(0), gmodel); g_object_unref(gmodel); break; default: err_DATA_TYPE(error, data_desc.measure_config.type); break; } return container; }
static void tip_model_dialog(TipModelArgs *args) { enum { RESPONSE_RESET = 1, RESPONSE_PREVIEW = 2 }; GtkWidget *dialog, *table, *hbox, *spin; TipModelControls controls; GwyPixmapLayer *layer; GwyDataField *dfield; GwySIUnit *unit; GQuark quark; gint response, row; dialog = gtk_dialog_new_with_buttons(_("Model Tip"), NULL, 0, NULL); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), gwy_stock_like_button_new(_("_Update"), GTK_STOCK_EXECUTE), RESPONSE_PREVIEW); gtk_dialog_add_button(GTK_DIALOG(dialog), _("_Reset"), RESPONSE_RESET); gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(dialog), GTK_STOCK_OK, GTK_RESPONSE_OK); gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); hbox = gtk_hbox_new(FALSE, 3); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE, FALSE, 4); controls.args = args; controls.vxres = 200; controls.vyres = 200; /* set up initial tip field */ quark = gwy_app_get_data_key_for_id(args->object.id); dfield = GWY_DATA_FIELD(gwy_container_get_object(args->object.data, quark)); controls.tip = gwy_data_field_new_alike(dfield, TRUE); gwy_data_field_resample(controls.tip, controls.vxres, controls.vyres, GWY_INTERPOLATION_NONE); gwy_data_field_clear(controls.tip); /*set up data of rescaled image of the tip*/ controls.vtip = gwy_container_new(); gwy_app_sync_data_items(args->object.data, controls.vtip, args->object.id, 0, FALSE, GWY_DATA_ITEM_PALETTE, 0); dfield = gwy_data_field_new_alike(controls.tip, TRUE); gwy_container_set_object_by_name(controls.vtip, "/0/data", dfield); g_object_unref(dfield); /* set up resampled view */ controls.view = gwy_data_view_new(controls.vtip); layer = gwy_layer_basic_new(); gwy_pixmap_layer_set_data_key(layer, "/0/data"); gwy_layer_basic_set_gradient_key(GWY_LAYER_BASIC(layer), "/0/base/palette"); gwy_data_view_set_base_layer(GWY_DATA_VIEW(controls.view), layer); /* set up tip model controls */ gtk_box_pack_start(GTK_BOX(hbox), controls.view, FALSE, FALSE, 4); table = gtk_table_new(6, 4, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 2); gtk_table_set_col_spacings(GTK_TABLE(table), 6); gtk_container_set_border_width(GTK_CONTAINER(table), 4); gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 4); row = 0; controls.type = create_preset_menu(G_CALLBACK(tip_type_cb), &controls, args->type); gwy_table_attach_hscale(table, row, _("Tip _type:"), NULL, GTK_OBJECT(controls.type), GWY_HSCALE_WIDGET); row++; controls.nsides = gtk_adjustment_new(args->nsides, 3, 24, 1, 5, 0); gwy_table_attach_hscale(table, row, _("_Number of sides:"), NULL, controls.nsides, 0); row++; controls.angle = gtk_adjustment_new(args->angle, 0.1, 89.9, 0.1, 1, 0); spin = gwy_table_attach_hscale(table, row, _("Tip _slope:"), _("deg"), controls.angle, 0); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 2); row++; controls.theta = gtk_adjustment_new(args->theta, 0, 360, 0.1, 1, 0); spin = gwy_table_attach_hscale(table, row, _("Tip _rotation:"), _("deg"), controls.theta, 0); gtk_spin_button_set_digits(GTK_SPIN_BUTTON(spin), 2); row++; controls.radius = gtk_adjustment_new(1.0, 0.01, 1000.0, 0.01, 1.0, 0.0); controls.radius_spin = gtk_spin_button_new(GTK_ADJUSTMENT(controls.radius), 0.1, 2); gtk_table_attach(GTK_TABLE(table), controls.radius_spin, 2, 3, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); controls.radius_label = gtk_label_new_with_mnemonic(_("Tip _apex radius:")); gtk_misc_set_alignment(GTK_MISC(controls.radius_label), 0.0, 0.5); gtk_label_set_mnemonic_widget(GTK_LABEL(controls.radius_label), controls.radius_spin); gtk_table_attach(GTK_TABLE(table), controls.radius_label, 0, 1, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); unit = gwy_data_field_get_si_unit_xy(dfield); controls.radius_unit = gwy_combo_box_metric_unit_new(G_CALLBACK(radius_changed_cb), &controls, -12, -3, unit, -9); gtk_table_attach(GTK_TABLE(table), controls.radius_unit, 3, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); g_signal_connect(controls.radius, "value-changed", G_CALLBACK(radius_changed_cb), &controls); row++; controls.labsize = gtk_label_new(NULL); gtk_misc_set_alignment(GTK_MISC(controls.labsize), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), controls.labsize, 0, 3, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); row++; controls.tipdone = FALSE; tip_model_dialog_update_controls(&controls, args); preview(&controls, args); gtk_widget_show_all(dialog); do { response = gtk_dialog_run(GTK_DIALOG(dialog)); switch (response) { case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: tip_model_dialog_update_values(&controls, args); gtk_widget_destroy(dialog); tip_model_dialog_abandon(&controls); case GTK_RESPONSE_NONE: return; break; case GTK_RESPONSE_OK: tip_model_do(args, &controls); break; case RESPONSE_RESET: args->nsides = tip_model_defaults.nsides; args->angle = tip_model_defaults.angle; args->radius = tip_model_defaults.radius; args->theta = tip_model_defaults.theta; args->type = tip_model_defaults.type; tip_model_dialog_update_controls(&controls, args); break; case RESPONSE_PREVIEW: tip_model_dialog_update_values(&controls, args); preview(&controls, args); break; default: g_assert_not_reached(); break; } } while (response != GTK_RESPONSE_OK); tip_model_dialog_update_values(&controls, args); gtk_widget_destroy(dialog); tip_model_dialog_abandon(&controls); }
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; }
static GwyContainer* gsf_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *container = NULL, *meta = NULL; GwyDataField *dfield = NULL; GwyTextHeaderParser parser; GwySIUnit *unit; guchar *p, *value, *buffer = NULL, *header = NULL; const guchar *datap; GHashTable *hash = NULL; gsize size, expected_size; GError *err = NULL; gdouble xreal, yreal, xoff, yoff; guint i, xres, yres; gdouble *d; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < MAGIC_SIZE || memcmp(buffer, MAGIC, MAGIC_SIZE) != 0) { err_FILE_TYPE(error, "Gwyddion Simple Field"); goto fail; } p = buffer + MAGIC_SIZE; datap = memchr(p, '\0', size - (p - buffer)); if (!datap) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("File header is truncated.")); goto fail; } header = g_strdup(p); datap += 4 - ((datap - buffer) % 4); gwy_clear(&parser, 1); parser.key_value_separator = "="; if (!(hash = gwy_text_header_parse(header, &parser, NULL, NULL))) { g_propagate_error(error, err); goto fail; } xres = read_pixel_size(hash, "XRes", error); yres = read_pixel_size(hash, "YRes", error); if (!xres || !yres) goto fail; expected_size = (datap - buffer) + sizeof(gfloat)*xres*yres; if (err_SIZE_MISMATCH(error, expected_size, size, TRUE)) goto fail; xreal = read_real_size(hash, "XReal"); yreal = read_real_size(hash, "YReal"); dfield = gwy_data_field_new(xres, yres, xreal, yreal, FALSE); xoff = read_real_offset(hash, "XOffset"); yoff = read_real_offset(hash, "YOffset"); gwy_data_field_set_xoffset(dfield, xoff); gwy_data_field_set_yoffset(dfield, yoff); value = g_hash_table_lookup(hash, "XYUnits"); unit = gwy_si_unit_new(value); gwy_data_field_set_si_unit_xy(dfield, unit); g_object_unref(unit); value = g_hash_table_lookup(hash, "ZUnits"); unit = gwy_si_unit_new(value); gwy_data_field_set_si_unit_z(dfield, unit); g_object_unref(unit); d = gwy_data_field_get_data(dfield); for (i = xres*yres; i; i--) *(d++) = gwy_get_gfloat_le(&datap); 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, "Title"))) { /* FIXME: Ensure valid UTF-8 */ gwy_container_set_string_by_name(container, "/0/data/title", g_strdup(value)); } else gwy_app_channel_title_fall_back(container, 0); 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); gwy_file_channel_import_log_add(container, 0, NULL, filename); fail: gwy_file_abandon_contents(buffer, size, NULL); if (header) g_free(header); if (hash) g_hash_table_destroy(hash); return container; }
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; G_GNUC_UNUSED 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(¯o_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); gwy_file_channel_import_log_add(container, i, NULL, filename); } if (!container) err_NO_DATA(error); gwy_file_abandon_contents(buffer, size, NULL); return container; }
static void tip_blind_dialog(TipBlindArgs *args) { enum { RESPONSE_RESET = 1, RESPONSE_PARTIAL, RESPONSE_FULL }; GtkWidget *dialog, *table, *hbox, *vbox, *label; GwyContainer *data; GwyGraphModel *gmodel; GwyGraphArea *area; TipBlindControls controls; GwyPixmapLayer *layer; GwyDataField *dfield; GQuark quark; GwySIUnit *unit; gint response, row; dialog = gtk_dialog_new_with_buttons(_("Blind Tip Estimation"), NULL, 0, _("Run _Partial"), RESPONSE_PARTIAL, _("Run _Full"), RESPONSE_FULL, _("_Reset Tip"), RESPONSE_RESET, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); gwy_help_add_to_proc_dialog(GTK_DIALOG(dialog), GWY_HELP_DEFAULT); controls.args = args; controls.in_update = TRUE; controls.good_tip = FALSE; controls.dialog = dialog; gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, controls.good_tip); hbox = gtk_hbox_new(FALSE, 4); gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox, FALSE, FALSE, 4); controls.vxres = 240; controls.vyres = 240; controls.oldnstripes = args->nstripes; /* set initial tip properties */ data = gwy_app_data_browser_get(args->source.datano); quark = gwy_app_get_data_key_for_id(args->source.id); dfield = GWY_DATA_FIELD(gwy_container_get_object(data, quark)); controls.tip = gwy_data_field_new_alike(dfield, TRUE); gwy_data_field_resample(controls.tip, args->xres, args->yres, GWY_INTERPOLATION_NONE); gwy_data_field_clear(controls.tip); /* set up data of rescaled image of the tip */ controls.vtip = gwy_container_new(); gwy_app_sync_data_items(data, controls.vtip, args->source.id, 0, FALSE, GWY_DATA_ITEM_PALETTE, 0); dfield = gwy_data_field_new_alike(controls.tip, TRUE); gwy_data_field_resample(dfield, controls.vxres, controls.vyres, GWY_INTERPOLATION_ROUND); gwy_container_set_object_by_name(controls.vtip, "/0/data", dfield); g_object_unref(dfield); /* set up rescaled image of the tip */ vbox = gtk_vbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 4); controls.view = gwy_data_view_new(controls.vtip); layer = gwy_layer_basic_new(); gwy_pixmap_layer_set_data_key(layer, "/0/data"); gwy_layer_basic_set_gradient_key(GWY_LAYER_BASIC(layer), "/0/base/palette"); gwy_data_view_set_base_layer(GWY_DATA_VIEW(controls.view), layer); /* set up tip estimation controls */ gtk_box_pack_start(GTK_BOX(vbox), controls.view, FALSE, FALSE, 0); gmodel = gwy_graph_model_new(); controls.graph = gwy_graph_new(gmodel); g_object_unref(gmodel); gwy_axis_set_visible(gwy_graph_get_axis(GWY_GRAPH(controls.graph), GTK_POS_LEFT), FALSE); gwy_axis_set_visible(gwy_graph_get_axis(GWY_GRAPH(controls.graph), GTK_POS_BOTTOM), FALSE); area = GWY_GRAPH_AREA(gwy_graph_get_area(GWY_GRAPH(controls.graph))); gtk_widget_set_no_show_all(gwy_graph_area_get_label(area), TRUE); g_signal_connect_after(gwy_graph_area_get_label(area), "map", G_CALLBACK(gtk_widget_hide), NULL); gtk_box_pack_start(GTK_BOX(vbox), controls.graph, TRUE, TRUE, 0); table = gtk_table_new(13, 4, FALSE); gtk_table_set_row_spacings(GTK_TABLE(table), 2); gtk_table_set_col_spacings(GTK_TABLE(table), 6); gtk_container_set_border_width(GTK_CONTAINER(table), 4); gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 4); row = 0; controls.data = gwy_data_chooser_new_channels(); gwy_data_chooser_set_filter(GWY_DATA_CHOOSER(controls.data), tip_blind_source_filter, &args->orig, NULL); gwy_data_chooser_set_active_id(GWY_DATA_CHOOSER(controls.data), &args->source); g_signal_connect(controls.data, "changed", G_CALLBACK(data_changed), &args->source); gwy_table_attach_hscale(table, row, _("Related _data:"), NULL, GTK_OBJECT(controls.data), GWY_HSCALE_WIDGET); gtk_table_set_row_spacing(GTK_TABLE(table), row, 8); row++; label = gtk_label_new(_("Estimated Tip Size")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_table_attach(GTK_TABLE(table), label, 0, 4, row, row+1, GTK_FILL, 0, 0, 0); row++; controls.xres = gtk_adjustment_new(args->xres, MIN_RES, MAX_RES, 1, 10, 0); gwy_table_attach_hscale(table, row, _("_Width:"), "px", controls.xres, 0); g_object_set_data(G_OBJECT(controls.xres), "controls", &controls); g_signal_connect(controls.xres, "value-changed", G_CALLBACK(width_changed), &controls); row++; controls.yres = gtk_adjustment_new(args->yres, MIN_RES, MAX_RES, 1, 10, 0); gwy_table_attach_hscale(table, row, _("_Height:"), "px", controls.yres, 0); g_object_set_data(G_OBJECT(controls.yres), "controls", &controls); g_signal_connect(controls.yres, "value-changed", G_CALLBACK(height_changed), &controls); row++; controls.same_resolution = gtk_check_button_new_with_mnemonic(_("_Same resolution")); gtk_table_attach(GTK_TABLE(table), controls.same_resolution, 0, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(controls.same_resolution), args->same_resolution); g_signal_connect(controls.same_resolution, "toggled", G_CALLBACK(same_resolution_changed), &controls); gtk_table_set_row_spacing(GTK_TABLE(table), row, 8); row++; gtk_table_attach(GTK_TABLE(table), gwy_label_new_header(_("Options")), 0, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); row++; controls.threshold = gtk_adjustment_new(1.0, 0.01, 1000.0, 0.01, 1.0, 0.0); controls.threshold_spin = gtk_spin_button_new(GTK_ADJUSTMENT(controls.threshold), 0.1, 2); gtk_table_attach(GTK_TABLE(table), controls.threshold_spin, 2, 3, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); label = gtk_label_new_with_mnemonic(_("Noise suppression t_hreshold:")); gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_label_set_mnemonic_widget(GTK_LABEL(label), controls.threshold_spin); gtk_table_attach(GTK_TABLE(table), label, 0, 2, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); unit = gwy_data_field_get_si_unit_z(dfield); controls.threshold_unit = gwy_combo_box_metric_unit_new(G_CALLBACK(thresh_changed), &controls, -12, -3, unit, -9); gtk_table_attach(GTK_TABLE(table), controls.threshold_unit, 3, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); g_signal_connect(controls.threshold, "value-changed", G_CALLBACK(thresh_changed), &controls); sci_entry_set_value(GTK_ADJUSTMENT(controls.threshold), GTK_COMBO_BOX(controls.threshold_unit), args->thresh); row++; controls.boundaries = gtk_check_button_new_with_mnemonic(_("Use _boundaries")); gtk_table_attach(GTK_TABLE(table), controls.boundaries, 0, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(controls.boundaries), args->use_boundaries); g_signal_connect(controls.boundaries, "toggled", G_CALLBACK(bound_changed), args); gtk_table_set_row_spacing(GTK_TABLE(table), row, 8); row++; gtk_table_attach(GTK_TABLE(table), gwy_label_new_header(_("Stripes")), 0, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); row++; controls.nstripes = gtk_adjustment_new(args->nstripes, MIN_STRIPES, MAX_STRIPES, 1, 10, 0); gwy_table_attach_hscale(table, row, _("_Split to stripes:"), NULL, controls.nstripes, GWY_HSCALE_CHECK); controls.split_to_stripes = gwy_table_hscale_get_check(controls.nstripes); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(controls.split_to_stripes), !args->split_to_stripes); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(controls.split_to_stripes), args->split_to_stripes); g_signal_connect(controls.split_to_stripes, "toggled", G_CALLBACK(split_to_stripes_changed), &controls); g_signal_connect(controls.nstripes, "value-changed", G_CALLBACK(nstripes_changed), &controls); row++; controls.stripeno = gtk_adjustment_new(1, 1, args->nstripes, 1, 10, 0); gwy_table_attach_hscale(table, row, _("_Preview stripe:"), NULL, controls.stripeno, GWY_HSCALE_DEFAULT); g_signal_connect(controls.stripeno, "value-changed", G_CALLBACK(stripeno_changed), &controls); row++; controls.plot_size_graph = gtk_check_button_new_with_mnemonic(_("Plot size _graph")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(controls.plot_size_graph), args->plot_size_graph); gtk_table_attach(GTK_TABLE(table), controls.plot_size_graph, 0, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); g_signal_connect(controls.plot_size_graph, "toggled", G_CALLBACK(plot_size_graph_changed), &controls); row++; controls.create_images = gtk_check_button_new_with_mnemonic(_("Create tip i_mages")); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(controls.create_images), args->create_images); gtk_table_attach(GTK_TABLE(table), controls.create_images, 0, 4, row, row+1, GTK_EXPAND | GTK_FILL, 0, 0, 0); g_signal_connect(controls.create_images, "toggled", G_CALLBACK(create_images_changed), &controls); row++; controls.tipdone = FALSE; controls.in_update = FALSE; split_to_stripes_changed(GTK_TOGGLE_BUTTON(controls.split_to_stripes), &controls); gtk_widget_show_all(dialog); do { response = gtk_dialog_run(GTK_DIALOG(dialog)); switch (response) { case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: gtk_widget_destroy(dialog); case GTK_RESPONSE_NONE: tip_blind_dialog_abandon(&controls); tip_blind_save_args(gwy_app_settings_get(), args); return; break; case GTK_RESPONSE_OK: tip_blind_save_args(gwy_app_settings_get(), args); tip_blind_do(&controls, args); break; case RESPONSE_RESET: reset(&controls, args); break; case RESPONSE_PARTIAL: tip_blind_run(&controls, args, FALSE); break; case RESPONSE_FULL: tip_blind_run(&controls, args, TRUE); break; default: g_assert_not_reached(); break; } } while (response != GTK_RESPONSE_OK); gtk_widget_destroy(dialog); tip_blind_dialog_abandon(&controls); return; }
static GwyContainer* microprof_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { enum { XRES = 0x0026, YRES = 0x002a, XRANGE = 0x0038, YRANGE = 0x0040, ZRANGE = 0x006e, }; GwyContainer *container = NULL; guchar *buffer = NULL; const guchar *p; MicroProfFile mfile; gsize size = 0; GError *err = NULL; guint i, ndata, datasize; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } if (size < MICROPROF_HEADER_SIZE) { err_TOO_SHORT(error); goto fail; } if (memcmp(buffer, MAGIC, MAGIC_SIZE) != 0) { err_FILE_TYPE(error, "MicroProf"); goto fail; } p = buffer + XRES; mfile.xres = gwy_get_guint16_le(&p); if (err_DIMENSION(error, mfile.xres)) goto fail; p = buffer + YRES; mfile.yres = gwy_get_guint16_le(&p); if (err_DIMENSION(error, mfile.xres)) goto fail; p = buffer + XRANGE; mfile.xrange = gwy_get_gdouble_le(&p); if (!(mfile.xrange = fabs(mfile.xrange))) { g_warning("Real x size is 0.0, fixing to 1.0"); mfile.xrange = 1.0; } p = buffer + YRANGE; mfile.yrange = gwy_get_gdouble_le(&p); if (!(mfile.yrange = fabs(mfile.yrange))) { g_warning("Real y size is 0.0, fixing to 1.0"); mfile.yrange = 1.0; } p = buffer + ZRANGE; mfile.zscale = gwy_get_gdouble_le(&p); datasize = 2*mfile.xres*mfile.yres; if (err_SIZE_MISMATCH(error, datasize, size - MICROPROF_HEADER_SIZE, FALSE)) goto fail; /* FIXME: There is weird stuff between channels. Need specs. ndata = (size - MICROPROF_HEADER_SIZE)/datasize; if (!ndata) { err_NO_DATA(error); goto fail; } */ ndata = 1; container = gwy_container_new(); mfile.data = buffer + MICROPROF_HEADER_SIZE; for (i = 0; i < ndata; i++) { GwyDataField *dfield; GQuark quark; dfield = microprof_read_data_field(&mfile, mfile.data + i*datasize); 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); gwy_file_channel_import_log_add(container, i, NULL, filename); } fail: gwy_file_abandon_contents(buffer, size, NULL); return container; }
static GwyContainer* igor_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { GwyContainer *meta = NULL, *container = NULL; GwyDataField *dfield = NULL, *maskfield = NULL; GwyTextHeaderParser parser; IgorFile igorfile; IgorWaveHeader5 *wave5; GError *err = NULL; guchar *p, *buffer = NULL; gint xres, yres; gsize expected_size, size = 0; gchar *note = NULL; const gchar *value; gchar key[64]; guint i, chid; GQuark quark; guint nlabels; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); return NULL; } gwy_clear(&igorfile, 1); if (!igor_read_headers(&igorfile, buffer, size, FALSE, error)) goto fail; /* Only accept v5 files because older do not support 2D data */ if (igorfile.header.version != 5) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Format version is %d. Only version 5 is supported."), igorfile.header.version); goto fail; } /* Detect Asylum research files, leave it at generic if not detected. */ if (memcmp(buffer + size-5, "MFP3D", 5) == 0) igorfile.variant = IGOR_ASYLUM_MPF3D; else if (memcmp(buffer + size-5, "Force", 5) == 0) igorfile.variant = IGOR_ASYLUM_FORCE; gwy_debug("producer variant %u", igorfile.variant); /* Must have exactly 3 dims: xres, yres, nchannels */ wave5 = &igorfile.wave5; xres = wave5->n_dim[0]; yres = wave5->n_dim[1]; igorfile.nchannels = wave5->n_dim[2]; if (igorfile.nchannels==0) igorfile.nchannels=1; if (!xres || !yres || !igorfile.nchannels || wave5->n_dim[3]) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Only two-dimensional data are supported.")); goto fail; } igorfile.type_size = igor_data_type_size(wave5->type); if (!igorfile.type_size) { err_DATA_TYPE(error, wave5->type); goto fail; } if (wave5->npts != xres*yres*igorfile.nchannels) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Number of data points %u does not match resolutions " "%u×%u×%u."), wave5->npts, xres, yres, igorfile.nchannels); goto fail; } if (igorfile.header.wfm_size <= igorfile.wave_header_size) { err_INVALID(error, "wfmSize"); goto fail; } expected_size = igorfile.header.wfm_size - igorfile.wave_header_size; if (expected_size != wave5->npts*igorfile.type_size) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Data size %u does not match " "the number of data points %u×%u."), (guint)expected_size, wave5->npts, igorfile.type_size); } if (err_SIZE_MISMATCH(error, expected_size + igorfile.headers_size, size, FALSE)) goto fail; p = buffer + igorfile.headers_size + expected_size; gwy_debug("remaning data size: %lu", (gulong)(size - (p - buffer))); p += igorfile.header.formula_size; if ((igorfile.variant == IGOR_ASYLUM_FORCE || igorfile.variant == IGOR_ASYLUM_MPF3D) && igorfile.header.note_size && (p - buffer) + igorfile.header.note_size <= size) { note = g_strndup((const gchar*)p, size); gwy_clear(&parser, 1); parser.key_value_separator = ":"; igorfile.meta = gwy_text_header_parse(note, &parser, NULL, NULL); } p += igorfile.header.note_size; /* FIXME: Support extended units for non-Asylum files! */ p += igorfile.header.data_e_units_size; for (i = 0; i < MAXDIMS; i++) p += igorfile.header.dim_e_units_size[i]; /* Skip labels of x and y dimension, we don't know what to do with them. */ for (i = 0; i < 2; i++) p += igorfile.header.dim_labels_size[i]; /* FIXME: The labels are mandatory only in Asylum Research files. */ nlabels = igorfile.header.dim_labels_size[2]/(MAX_WAVE_NAME5+1); expected_size = (MAX_WAVE_NAME5 + 1)*(nlabels); if ((p - buffer) + expected_size > size ) { g_set_error(error, GWY_MODULE_FILE_ERROR, GWY_MODULE_FILE_ERROR_DATA, _("Cannot read channel labels.")); goto fail; } igorfile.titles = read_channel_labels(p, igorfile.nchannels+1, nlabels); p += igorfile.header.dim_labels_size[2]; if (igorfile.meta) { igorfile.channel_info = g_new0(AsylumChannelInfo, igorfile.nchannels); for (i = 0; i < igorfile.nchannels; i++) { AsylumChannelInfo *chinfo = igorfile.channel_info + i; const gchar *title = g_ptr_array_index(igorfile.titles, i+1); if (title) { chinfo->name = canonicalize_title(title); g_snprintf(key, sizeof(key), "%sUnit", chinfo->name); value = g_hash_table_lookup(igorfile.meta, key); if (value) chinfo->units = value; else chinfo->units = channel_title_to_units(chinfo->name); } } } container = gwy_container_new(); for (i = chid = 0; i < igorfile.nchannels; i++, chid++) { const gchar *title = g_ptr_array_index(igorfile.titles, i+1); const gchar *zunits = NULL; if (igorfile.channel_info) { AsylumChannelInfo *chinfo = igorfile.channel_info + i; zunits = chinfo->units; meta = igor_get_metadata(&igorfile, i + 1); } dfield = igor_read_data_field(&igorfile, buffer, i, zunits, FALSE); maskfield = gwy_app_channel_mask_of_nans(dfield, TRUE); quark = gwy_app_get_data_key_for_id(chid); gwy_container_set_object(container, quark, dfield); g_object_unref(dfield); if (maskfield) { g_snprintf(key, sizeof(key), "/%d/mask", chid); gwy_container_set_object_by_name(container, key, maskfield); } if (meta) { g_snprintf(key, sizeof(key), "/%d/meta", chid); gwy_container_set_object_by_name(container, key, meta); } if (title) { g_snprintf(key, sizeof(key), "/%d/data/title", chid); gwy_container_set_string_by_name(container, key, g_strdup(title)); } gwy_app_channel_title_fall_back(container,chid); if (wave5->type & IGOR_COMPLEX) { chid++; dfield = igor_read_data_field(&igorfile, buffer, i, zunits, TRUE); quark = gwy_app_get_data_key_for_id(chid); gwy_container_set_object(container, quark, dfield); g_object_unref(dfield); if (meta) { g_snprintf(key, sizeof(key), "/%d/meta", chid); /* container still holds a reference */ g_object_unref(meta); meta = gwy_container_duplicate(meta); gwy_container_set_object_by_name(container, key, meta); } if (maskfield) { g_snprintf(key, sizeof(key), "/%d/mask", chid); /* container still holds a reference */ g_object_unref(maskfield); maskfield = gwy_data_field_duplicate(maskfield); gwy_container_set_object_by_name(container, key, maskfield); } if (title) { g_snprintf(key, sizeof(key), "/%d/data/title", chid); gwy_container_set_string_by_name(container, key, g_strdup(title)); }; gwy_app_channel_title_fall_back(container,chid); } gwy_object_unref(meta); gwy_object_unref(maskfield); gwy_file_channel_import_log_add(container, chid, NULL, filename); } fail: gwy_file_abandon_contents(buffer, size, NULL); g_free(note); if (igorfile.channel_info) { for (i = 0; i < igorfile.nchannels; i++) g_free(igorfile.channel_info[i].name); g_free(igorfile.channel_info); } if (igorfile.meta) g_hash_table_destroy(igorfile.meta); if (igorfile.titles) { g_ptr_array_foreach(igorfile.titles, (GFunc)g_free, NULL); g_ptr_array_free(igorfile.titles, TRUE); } return container; }
static void maskcor_do(MaskcorArgs *args) { enum { WORK_PER_UPDATE = 50000000 }; GwyDataField *dfield, *kernel, *retfield, *score; GwyContainer *data, *kerneldata; GwyComputationState *state; GQuark quark; gint newid, work, wpi; kerneldata = gwy_app_data_browser_get(args->kernel.datano); quark = gwy_app_get_data_key_for_id(args->kernel.id); kernel = GWY_DATA_FIELD(gwy_container_get_object(kerneldata, quark)); data = gwy_app_data_browser_get(args->data.datano); quark = gwy_app_get_data_key_for_id(args->data.id); dfield = GWY_DATA_FIELD(gwy_container_get_object(data, quark)); retfield = gwy_data_field_new_alike(dfield, FALSE); /* FIXME */ if (args->method == GWY_CORRELATION_NORMAL) { gwy_app_wait_start(gwy_app_find_window_for_channel(data, args->data.id), _("Initializing...")); state = gwy_data_field_correlate_init(dfield, kernel, retfield); gwy_app_wait_set_message(_("Correlating...")); work = 0; wpi = gwy_data_field_get_xres(kernel)*gwy_data_field_get_yres(kernel); wpi = MIN(wpi, WORK_PER_UPDATE); do { gwy_data_field_correlate_iteration(state); work += wpi; if (work > WORK_PER_UPDATE) { work -= WORK_PER_UPDATE; if (!gwy_app_wait_set_fraction(state->fraction)) { gwy_data_field_correlate_finalize(state); gwy_app_wait_finish(); g_object_unref(retfield); return; } } } while (state->state != GWY_COMPUTATION_STATE_FINISHED); gwy_data_field_correlate_finalize(state); gwy_app_wait_finish(); } else gwy_data_field_correlate(dfield, kernel, retfield, args->method); /* score - do new data with score */ if (args->result == GWY_MASKCOR_SCORE) { score = gwy_data_field_duplicate(retfield); newid = gwy_app_data_browser_add_data_field(score, data, TRUE); gwy_app_sync_data_items(data, data, args->data.id, newid, FALSE, GWY_DATA_ITEM_GRADIENT, 0); gwy_app_set_data_field_title(data, newid, _("Correlation score")); g_object_unref(score); gwy_app_channel_log_add_proc(data, args->data.id, newid); } else { /* add mask */ quark = gwy_app_get_mask_key_for_id(args->data.id); gwy_app_undo_qcheckpointv(data, 1, &quark); if (args->result == GWY_MASKCOR_OBJECTS) plot_correlated(retfield, gwy_data_field_get_xres(kernel), gwy_data_field_get_yres(kernel), args->threshold); else if (args->result == GWY_MASKCOR_MAXIMA) gwy_data_field_threshold(retfield, args->threshold, 0.0, 1.0); gwy_container_set_object(data, quark, retfield); gwy_app_channel_log_add_proc(data, args->data.id, args->data.id); } g_object_unref(retfield); }
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; }