![]() |
![]() |
![]() |
Gwyddion Module Library Reference Manual | ![]() |
---|
File ModulesFile Modules — More about file modules |
File modules implement loading and saving of SPM files. The structure and operation of file modules will be explained on a simple but complete sample file module. This module imports a sample data format that was construed for this tutorial and does not occur in practice. However, the format resembles many (binary) data formats used in practice, except it contains no device and manufacturer information as they are not essential for the example.
The sample file format our module will load looks as follows, all values are stored in little-endian:
Position | Type | Name | Description |
---|---|---|---|
0x00 | char[4] | magic |
Magic header "SMPL"
|
0x04 | uint16 | xres |
Pixels per line |
0x06 | uint16 | xres |
Number of lines |
0x08 | float | measure |
Size of one pixel [nm] |
0x0c | float | z0 |
Value corresponding to 0 in raw data [nm] |
0x10 | float | gain |
Conversion factor from raw data to physical values [nm] |
0x14 |
uint16[xres *yres ] |
data |
Raw data values |
Furthermore we will assume files of this type get the extension
.ssd
(Simple SPM Data). The complete module source
code follows, it will be described in detail below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
#include <string.h> #include <stdio.h> #include <glib/gstdio.h> #include <libgwyddion/gwymacros.h> #include <libgwyddion/gwymath.h> #include <libprocess/stats.h> #include <libgwymodule/gwymodule-file.h> #include <app/gwymoduleutils-file.h> #include "err.h" #define EXTENSION ".ssd" #define MAGIC "SMPL" #define MAGIC_SIZE (sizeof(MAGIC) - 1) enum { HEADER_SIZE = MAGIC_SIZE + 2*2 + 3*4 }; typedef struct { guint xres; guint yres; gdouble measure; gdouble z0; gdouble gain; } SimpleFile; static gboolean module_register(void); static gint simple_detect (const GwyFileDetectInfo *fileinfo, gboolean only_name); static GwyContainer* simple_load (const gchar *filename, GwyRunType mode, GError **error); static GwyModuleInfo module_info = { GWY_MODULE_ABI_VERSION, &module_register, N_("Imports simple data files."), "J. Random Hacker <hacker.jr@example.org>", "1.0", "Bit Rot Inc.", "2006", }; GWY_MODULE_QUERY(module_info) static gboolean module_register(void) { gwy_file_func_register("simple", N_("Simple AFM files (.afm)"), (GwyFileDetectFunc)&simple_detect, (GwyFileLoadFunc)&simple_load, NULL, NULL); return TRUE; } static gint simple_detect(const GwyFileDetectInfo *fileinfo, gboolean only_name) { if (only_name) return g_str_has_suffix(fileinfo->name_lowercase, EXTENSION) ? 20 : 0; if (fileinfo->buffer_len > MAGIC_SIZE && memcmp(fileinfo->head, MAGIC, MAGIC_SIZE) == 0) return 100; return 0; } static GwyContainer* simple_load(const gchar *filename, G_GNUC_UNUSED GwyRunType mode, GError **error) { SimpleFile simple; GwyContainer *container = NULL; GwySIUnit *unit; GwyDataField *dfield; guchar *buffer; const guchar *p; GError *err = NULL; gsize size, expected_size; const guint16 *rawdata; gdouble *data; gint i; if (!gwy_file_get_contents(filename, &buffer, &size, &err)) { err_GET_FILE_CONTENTS(error, &err); g_clear_error(&err); return NULL; } if (size <= HEADER_SIZE) { err_TOO_SHORT(error); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } if (memcmp(buffer, MAGIC, MAGIC_SIZE) != 0) { err_FILE_TYPE(error, "Simple"); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } p = buffer + MAGIC_SIZE; simple.xres = gwy_get_guint16_le(&p); simple.yres = gwy_get_guint16_le(&p); simple.measure = gwy_get_gfloat_le(&p); simple.z0 = gwy_get_gfloat_le(&p); simple.gain = gwy_get_gfloat_le(&p); expected_size = 2*simple.xres*simple.yres + HEADER_SIZE; if (size != expected_size) { err_SIZE_MISMATCH(error, expected_size, size); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } simple.measure *= 1e-9; simple.z0 *= 1e-9; simple.gain *= 1e-9; dfield = gwy_data_field_new(simple.xres, simple.yres, simple.xres*simple.measure, simple.yres*simple.measure, FALSE); data = gwy_data_field_get_data(dfield); rawdata = (const guint16*)p; for (i = 0; i < simple.xres*simple.yres; i++) data[i] = GUINT16_FROM_LE(rawdata[i])*simple.gain + simple.z0; unit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_xy(dfield, unit); g_object_unref(unit); unit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_z(dfield, unit); g_object_unref(unit); container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", dfield); gwy_container_set_string_by_name(container, "/0/data/title", g_strdup("Topography")); g_object_unref(dfield); gwy_file_abandon_contents(buffer, size, NULL); return container; } |
1 |
#include "err.h" |
1 2 3 4 5 6 |
#define EXTENSION ".ssd" #define MAGIC "SMPL" #define MAGIC_SIZE (sizeof(MAGIC) - 1) enum { HEADER_SIZE = MAGIC_SIZE + 2*2 + 3*4 }; |
1 2 3 4 5 6 7 |
typedef struct { guint xres; guint yres; gdouble measure; gdouble z0; gdouble gain; } SimpleFile; |
1 2 3 4 5 6 7 8 9 10 11 12 |
static gboolean module_register(void) { gwy_file_func_register("simple", N_("Simple AFM files (.afm)"), (GwyFileDetectFunc)&simple_detect, (GwyFileLoadFunc)&simple_load, NULL, NULL); return TRUE; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
static gint simple_detect(const GwyFileDetectInfo *fileinfo, gboolean only_name) { if (only_name) return g_str_has_suffix(fileinfo->name_lowercase, EXTENSION) ? 20 : 0; if (fileinfo->buffer_len > MAGIC_SIZE && memcmp(fileinfo->head, MAGIC, MAGIC_SIZE) == 0) return 100; return 0; } |
1 2 3 4 5 |
if (size <= HEADER_SIZE) { err_TOO_SHORT(error); gwy_file_abandon_contents(buffer, size, NULL); return NULL; } |
1 2 3 4 5 6 |
p = buffer + MAGIC_SIZE; simple.xres = gwy_get_guint16_le(&p); simple.yres = gwy_get_guint16_le(&p); simple.measure = gwy_get_gfloat_le(&p); simple.z0 = gwy_get_gfloat_le(&p); simple.gain = gwy_get_gfloat_le(&p); |
1 2 3 4 5 6 7 8 9 10 11 |
simple.measure *= 1e-9; simple.z0 *= 1e-9; simple.gain *= 1e-9; dfield = gwy_data_field_new(simple.xres, simple.yres, simple.xres*simple.measure, simple.yres*simple.measure, FALSE); data = gwy_data_field_get_data(dfield); rawdata = (const guint16*)p; for (i = 0; i < simple.xres*simple.yres; i++) data[i] = GUINT16_FROM_LE(rawdata[i])*simple.gain + simple.z0; |
1 2 3 4 5 6 7 |
unit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_xy(dfield, unit); g_object_unref(unit); unit = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_z(dfield, unit); g_object_unref(unit); |
1 |
unit = gwy_si_unit_new("nA"); |
1 |
unit = gwy_si_unit_new("A"); |
1 |
unit = gwy_si_unit_new_parse("nA", &power10); |
1 2 3 4 5 6 7 8 9 10 |
container = gwy_container_new(); gwy_container_set_object_by_name(container, "/0/data", dfield); gwy_container_set_string_by_name(container, "/0/data/title", g_strdup("Topography")); g_object_unref(dfield); gwy_file_abandon_contents(buffer, size, NULL); return container; |
1 2 3 4 5 6 7 |
meta = gwy_container_new(); gwy_container_set_string_by_name(meta, "Comment", g_strdup(myfile->user_comment)); gwy_container_set_string_by_name(meta, "Tip oscillation frequency", g_strdup_printf("%g Hz", myfile->freq)); gwy_container_set_object_by_name(container, "/0/meta", meta); g_object_unref(meta); |
1 2 3 4 5 6 7 |
struct { char c; LONG i; wchar_t remark[20]; } header; fread(&header, sizeof(header), 1, filehandle); |