aboutsummaryrefslogtreecommitdiff
path: root/libcrystfel/src/image-seedee.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcrystfel/src/image-seedee.c')
-rw-r--r--libcrystfel/src/image-seedee.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/libcrystfel/src/image-seedee.c b/libcrystfel/src/image-seedee.c
new file mode 100644
index 00000000..1965aefa
--- /dev/null
+++ b/libcrystfel/src/image-seedee.c
@@ -0,0 +1,195 @@
+/*
+ * image-seedee.c
+ *
+ * Image loading with Seedee
+ *
+ * Copyright © 2017-2022 Deutsches Elektronen-Synchrotron DESY,
+ * a research centre of the Helmholtz Association.
+ *
+ * Authors:
+ * 2018-2022 Thomas White <taw@physics.org>
+ * 2014 Valerio Mariani
+ * 2017 Stijn de Graaf
+ *
+ * This file is part of CrystFEL.
+ *
+ * CrystFEL is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * CrystFEL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with CrystFEL. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <libcrystfel-config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include <image.h>
+#include <utils.h>
+#include <profile.h>
+
+#include "datatemplate_priv.h"
+
+
+#if defined(HAVE_SEEDEE)
+
+#include <seedee/seedee.h>
+#include <cjson/cJSON.h>
+
+
+static int load_seedee_data(struct panel_template *p,
+ struct SeedeeNDArray *array,
+ float **pdata)
+{
+ int data_size_fs, data_size_ss;
+ float *data = NULL;
+
+ data_size_ss = array->shape[0];
+ data_size_fs = array->shape[1];
+
+ if ( (p->orig_min_fs + PANEL_WIDTH(p) > data_size_fs)
+ || (p->orig_min_ss + PANEL_HEIGHT(p) > data_size_ss) )
+ {
+ ERROR("Data for panel %s (%i x %i + %i + %i) is outside data "
+ "array bounds (%i x %i)\n",
+ p->name,
+ PANEL_WIDTH(p), PANEL_HEIGHT(p),
+ p->orig_min_fs, p->orig_min_ss,
+ data_size_fs, data_size_ss);
+ return 1;
+ }
+
+ if ( (array->datatype == 'u')
+ && (array->itemsize == 2)
+ && (array->byteorder == '<') )
+ {
+ int fs, ss;
+ uint16_t *in_data = (uint16_t *)array->data;
+
+ data = malloc(PANEL_WIDTH(p) * PANEL_HEIGHT(p) * sizeof(float));
+ if ( data == NULL ) return 1;
+
+ for ( ss=0; ss<PANEL_HEIGHT(p); ss++ ) {
+ for ( fs=0; fs<PANEL_WIDTH(p); fs++ ) {
+ size_t idx = fs+p->orig_min_fs + (ss+p->orig_min_ss)*data_size_fs;
+ data[fs+ss*PANEL_WIDTH(p)] = in_data[idx];
+ }
+ }
+ *pdata = data;
+
+ } else {
+ ERROR("Unrecognised data type %c%i%c\n",
+ array->datatype, array->itemsize, array->byteorder);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Read the image data from 'data_block' into 'image', according to 'dtempl' */
+int image_seedee_read(struct image *image,
+ DataTemplate *dtempl,
+ void *data_block,
+ size_t data_block_size,
+ char *meta_data)
+{
+ struct SeedeeNDArray array;
+ int r;
+ bool zero_copy;
+ int i;
+ cJSON *json;
+ cJSON *data_format_str;
+
+ json = cJSON_Parse(meta_data);
+ if ( json == NULL ) {
+ ERROR("Failed to parse JSON\n");
+ return 1;
+ }
+
+ data_format_str = cJSON_GetObjectItemCaseSensitive(json, "_data_format");
+ if ( !cJSON_IsString(data_format_str) ) {
+ ERROR("_data_format isn't a string");
+ cJSON_Delete(json);
+ return 1;
+ }
+
+ profile_start("seedee-get-size");
+ array.size = seedee_get_data_size(data_format_str->valuestring,
+ data_block, data_block_size,
+ &zero_copy, &array);
+ profile_end("seedee-get-size");
+ array.data = malloc(array.size);
+ array.shape = malloc(array.ndims*sizeof(int));
+ if ( (array.data == NULL) || (array.shape == NULL) ) {
+ cJSON_Delete(json);
+ return 1;
+ }
+
+ if ( array.ndims != 2 ) {
+ ERROR("Seedee data has unexpected number of dimensions "
+ "(%i, expected 2)\n", array.ndims);
+ return 1;
+ }
+
+ profile_start("seedee-deserialize");
+ r = seedee_deserialize_ndarray(data_format_str->valuestring,
+ data_block, data_block_size,
+ 0, &array);
+ profile_end("seedee-deserialize");
+ cJSON_Delete(json);
+ if ( r < 0 ) {
+ ERROR("Seedee deserialiation failed.\n");
+ return 1;
+ }
+
+ image->dp = malloc(dtempl->n_panels*sizeof(float *));
+ if ( image->dp == NULL ) {
+ ERROR("Failed to allocate data array.\n");
+ return 1;
+ }
+
+ /* Set all pointers to NULL for easier clean-up */
+ for ( i=0; i<dtempl->n_panels; i++ ) image->dp[i] = NULL;
+
+ profile_start("seedee-panel");
+ for ( i=0; i<dtempl->n_panels; i++ ) {
+ if ( load_seedee_data(&dtempl->panels[i], &array, &image->dp[i]) )
+ {
+ ERROR("Failed to load data for panel '%s'\n",
+ dtempl->panels[i].name);
+ profile_end("seedee-panel");
+ return 1;
+ }
+ }
+ profile_end("seedee-panel");
+
+ return 0;
+}
+
+
+#else /* defined(HAVE_SEEDEE) */
+
+int image_seedee_read(struct image *image,
+ const DataTemplate *dtempl,
+ void *data,
+ size_t data_size,
+ char *meta_data)
+{
+ ERROR("Seedee is not supported in this installation (read).\n");
+ return 1;
+}
+
+#endif /* defined(HAVE_SEEDEE) */