/* * Copyright (C) 2011-2013 Karlsruhe Institute of Technology * * This file is part of Ufo. * * This library is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include #include #include "readers/ufo-reader.h" #include "readers/ufo-edf-reader.h" struct _UfoEdfReaderPrivate { FILE *fp; guint start; gssize size; gsize height; guint bytes_per_sample; gboolean big_endian; }; static void ufo_reader_interface_init (UfoReaderIface *iface); G_DEFINE_TYPE_WITH_CODE (UfoEdfReader, ufo_edf_reader, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (UFO_TYPE_READER, ufo_reader_interface_init)) #define UFO_EDF_READER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_EDF_READER, UfoEdfReaderPrivate)) UfoEdfReader * ufo_edf_reader_new (void) { UfoEdfReader *reader = g_object_new (UFO_TYPE_EDF_READER, NULL); return reader; } static gboolean ufo_edf_reader_can_open (UfoReader *reader, const gchar *filename) { return g_str_has_suffix (filename, ".edf"); } static gboolean ufo_edf_reader_open (UfoReader *reader, const gchar *filename, guint start, GError **error) { UfoEdfReaderPrivate *priv; priv = UFO_EDF_READER_GET_PRIVATE (reader); priv->fp = fopen (filename, "rb"); fseek (priv->fp, 0L, SEEK_END); priv->size = (gsize) ftell (priv->fp); fseek (priv->fp, 0L, SEEK_SET); priv->start = start; return TRUE; } static void ufo_edf_reader_close (UfoReader *reader) { UfoEdfReaderPrivate *priv; priv = UFO_EDF_READER_GET_PRIVATE (reader); g_assert (priv->fp != NULL); fclose (priv->fp); priv->fp = NULL; priv->size = 0; } static gboolean ufo_edf_reader_data_available (UfoReader *reader) { UfoEdfReaderPrivate *priv; priv = UFO_EDF_READER_GET_PRIVATE (reader); return priv->fp != NULL && ftell (priv->fp) < priv->size; } static gsize ufo_edf_reader_read (UfoReader *reader, UfoBuffer *buffer, UfoRequisition *requisition, guint roi_y, guint roi_height, guint roi_step, guint image_step) { UfoEdfReaderPrivate *priv; gsize num_bytes; gsize num_read; gssize offset; gchar *data; gsize to_skip; guint start = 0; priv = UFO_EDF_READER_GET_PRIVATE (reader); data = (gchar *) ufo_buffer_get_host_array (buffer, NULL); /* size of the image width in bytes */ const gsize width = requisition->dims[0] * priv->bytes_per_sample; const guint num_rows = requisition->dims[1]; if (priv->start) { start = priv->start; priv->start = 0; } const gsize end_position = ftell (priv->fp) + priv->height * width; offset = 0; /* Go to the first desired row at *start* image index */ fseek (priv->fp, start * priv->height * width + roi_y * width, SEEK_CUR); if (roi_step == 1) { /* Read the full ROI at once if no stepping is specified */ num_bytes = width * roi_height; num_read = fread (data, 1, num_bytes, priv->fp); if (num_read != num_bytes) return 0; } else { for (guint i = 0; i < num_rows - 1; i++) { num_read = fread (data + offset, 1, width, priv->fp); if (num_read != width) return 0; offset += width; fseek (priv->fp, (roi_step - 1) * width, SEEK_CUR); } /* Read the last row without moving the file pointer so that the fseek to * the image end works properly */ num_read = fread (data + offset, 1, width, priv->fp); if (num_read != width) return 0; } /* Go to the image end to be in a consistent state for the next read */ fseek (priv->fp, end_position, SEEK_SET); /* Skip the desired number of images */ to_skip = MIN (image_step - 1, (priv->size - (gsize) ftell (priv->fp)) / (priv->height * width)); fseek (priv->fp, to_skip * priv->height * width, SEEK_CUR); if ((G_BYTE_ORDER == G_LITTLE_ENDIAN) && priv->big_endian) { guint32 *conv = (guint32 *) ufo_buffer_get_host_array (buffer, NULL); guint n_pixels = requisition->dims[0] * requisition->dims[1]; for (guint i = 0; i < n_pixels; i++) conv[i] = g_ntohl (conv[i]); } return to_skip + 1; } static void ufo_edf_reader_get_depth (const gchar *value, UfoBufferDepth *depth, guint *bytes) { struct { const gchar *name; UfoBufferDepth depth; guint bytes; } map[] = { {"UnsignedShort", UFO_BUFFER_DEPTH_16U, 2}, {"SignedInteger", UFO_BUFFER_DEPTH_32S, 4}, {"UnsignedLong", UFO_BUFFER_DEPTH_32U, 4}, {"Float", UFO_BUFFER_DEPTH_32F, 4}, {"FloatValue", UFO_BUFFER_DEPTH_32F, 4}, {NULL} }; for (guint i = 0; map[i].name != NULL; i++) { if (!g_strcmp0 (value, map[i].name)) { *depth = map[i].depth; *bytes = map[i].bytes; return; } } g_warning ("Unsupported data type"); *depth = UFO_BUFFER_DEPTH_8U; *bytes = 1; } static gboolean ufo_edf_reader_get_meta (UfoReader *reader, UfoRequisition *requisition, gsize *num_images, UfoBufferDepth *bitdepth, GError **error) { UfoEdfReaderPrivate *priv; gchar **tokens; gchar *header, *header_trig_position; gsize data_position; priv = UFO_EDF_READER_GET_PRIVATE (reader); header = g_malloc (priv->size); if (fread (header, 1, priv->size, priv->fp) != (gsize) priv->size) { g_set_error_literal (error, UFO_TASK_ERROR, UFO_TASK_ERROR_SETUP, "Could not read EDF header."); g_free (header); fclose (priv->fp); priv->fp = NULL; return FALSE; } header_trig_position = g_strstr_len (header, -1, "}"); data_position = header_trig_position - header + 2; if (header_trig_position == NULL || data_position % 512) { g_set_error_literal (error, UFO_TASK_ERROR, UFO_TASK_ERROR_SETUP, "Corrupt EDF header or not an EDF file."); g_free (header); fclose (priv->fp); priv->fp = NULL; return FALSE; } /* Go to the data position */ fseek (priv->fp, data_position, SEEK_SET); /* Don't process binary data */ header[data_position] = '\0'; tokens = g_strsplit (header, ";", 0); priv->big_endian = FALSE; requisition->n_dims = 2; for (guint i = 0; tokens[i] != NULL; i++) { gchar **key_value; gchar *key; gchar *value; key_value = g_strsplit (tokens[i], "=", 0); if (key_value[0] == NULL || key_value[1] == NULL) continue; key = g_strstrip (key_value[0]); value = g_strstrip (key_value[1]); if (!g_strcmp0 (key, "Dim_1")) { requisition->dims[0] = (guint) atoi (value); } else if (!g_strcmp0 (key, "Dim_2")) { requisition->dims[1] = priv->height = atoi (value); } else if (!g_strcmp0 (key, "DataType")) { ufo_edf_reader_get_depth (value, bitdepth, &priv->bytes_per_sample); } else if (!g_strcmp0 (key, "ByteOrder") && !g_strcmp0 (value, "HighByteFirst")) { priv->big_endian = TRUE; } else if (!g_strcmp0 (key, "Size")) { /* * Override file size if Size key is given. Using the determined * file size can cause wrong assumption about the number of images * in the EDF file. */ priv->size = atoi (value); } g_strfreev (key_value); } *num_images = requisition->dims[0] * requisition->dims[1] * priv->bytes_per_sample / (priv->size - data_position); g_strfreev (tokens); g_free (header); return TRUE; } static void ufo_edf_reader_finalize (GObject *object) { UfoEdfReaderPrivate *priv; priv = UFO_EDF_READER_GET_PRIVATE (object); if (priv->fp != NULL) { fclose (priv->fp); priv->fp = NULL; } G_OBJECT_CLASS (ufo_edf_reader_parent_class)->finalize (object); } static void ufo_reader_interface_init (UfoReaderIface *iface) { iface->can_open = ufo_edf_reader_can_open; iface->open = ufo_edf_reader_open; iface->close = ufo_edf_reader_close; iface->read = ufo_edf_reader_read; iface->get_meta = ufo_edf_reader_get_meta; iface->data_available = ufo_edf_reader_data_available; } static void ufo_edf_reader_class_init (UfoEdfReaderClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = ufo_edf_reader_finalize; g_type_class_add_private (gobject_class, sizeof (UfoEdfReaderPrivate)); } static void ufo_edf_reader_init (UfoEdfReader *self) { UfoEdfReaderPrivate *priv = NULL; self->priv = priv = UFO_EDF_READER_GET_PRIVATE (self); priv->fp = NULL; }