/*
* 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 "readers/ufo-reader.h"
#include "readers/ufo-tiff-reader.h"
struct _UfoTiffReaderPrivate {
TIFF *tiff;
gboolean more;
};
static void ufo_reader_interface_init (UfoReaderIface *iface);
G_DEFINE_TYPE_WITH_CODE (UfoTiffReader, ufo_tiff_reader, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (UFO_TYPE_READER,
ufo_reader_interface_init))
#define UFO_TIFF_READER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), UFO_TYPE_TIFF_READER, UfoTiffReaderPrivate))
UfoTiffReader *
ufo_tiff_reader_new (void)
{
UfoTiffReader *reader = g_object_new (UFO_TYPE_TIFF_READER, NULL);
return reader;
}
static gboolean
ufo_tiff_reader_can_open (UfoReader *reader,
const gchar *filename)
{
return g_str_has_suffix (filename, ".tiff") || g_str_has_suffix (filename, ".tif");
}
static gboolean
ufo_tiff_reader_open (UfoReader *reader,
const gchar *filename,
guint start,
GError **error)
{
UfoTiffReaderPrivate *priv;
priv = UFO_TIFF_READER_GET_PRIVATE (reader);
priv->tiff = TIFFOpen (filename, "r");
priv->more = TRUE;
if (priv->tiff == NULL) {
g_set_error (error, UFO_TASK_ERROR, UFO_TASK_ERROR_SETUP,
"Cannot open %s", filename);
return FALSE;
}
for (guint i = 0; i < start; i++)
priv->more = TIFFReadDirectory (priv->tiff) == 1;
return TRUE;
}
static void
ufo_tiff_reader_close (UfoReader *reader)
{
UfoTiffReaderPrivate *priv;
priv = UFO_TIFF_READER_GET_PRIVATE (reader);
g_assert (priv->tiff != NULL);
TIFFClose (priv->tiff);
priv->tiff = NULL;
}
static gboolean
ufo_tiff_reader_data_available (UfoReader *reader)
{
UfoTiffReaderPrivate *priv;
priv = UFO_TIFF_READER_GET_PRIVATE (reader);
return priv->more && priv->tiff != NULL;
}
static void
read_data (UfoTiffReaderPrivate *priv,
UfoBuffer *buffer,
UfoRequisition *requisition,
guint16 bits,
guint roi_y,
guint roi_height,
guint roi_step)
{
gchar *dst;
gsize step;
gsize offset;
step = requisition->dims[0] * bits / 8;
dst = (gchar *) ufo_buffer_get_host_array (buffer, NULL);
offset = 0;
if (requisition->n_dims == 3) {
/* RGB data */
gchar *src;
gsize plane_size;
/* Allow things like roi_height=1 and roi_step=20 */
plane_size = step * ((roi_height - 1) / roi_step + 1);
src = g_new0 (gchar, step * 3);
for (guint i = roi_y; i < roi_y + roi_height; i += roi_step) {
guint xd = 0;
guint xs = 0;
TIFFReadScanline (priv->tiff, src, i, 0);
for (; xd < requisition->dims[0]; xd += 1, xs += 3) {
dst[offset + xd] = src[xs];
dst[offset + plane_size + xd] = src[xs + 1];
dst[offset + 2 * plane_size + xd] = src[xs + 2];
}
offset += step;
}
g_free (src);
}
else {
for (guint i = roi_y; i < roi_y + roi_height; i += roi_step) {
TIFFReadScanline (priv->tiff, dst + offset, i, 0);
offset += step;
}
}
}
static void
read_64_bit_data (UfoTiffReaderPrivate *priv,
UfoBuffer *buffer,
UfoRequisition *requisition,
guint roi_y,
guint roi_height,
guint roi_step)
{
gdouble *src;
gfloat *dst;
dst = ufo_buffer_get_host_array (buffer, NULL);
src = g_new0 (gdouble, requisition->dims[0]);
for (guint i = roi_y; i < roi_y + roi_height; i += roi_step) {
TIFFReadScanline (priv->tiff, src, i, 0);
for (guint j = 0; j < requisition->dims[0]; j++)
dst[j] = (gfloat) src[j];
dst += requisition->dims[0];
}
g_free (src);
}
static void
ufo_tiff_reader_read (UfoReader *reader,
UfoBuffer *buffer,
UfoRequisition *requisition,
guint roi_y,
guint roi_height,
guint roi_step)
{
UfoTiffReaderPrivate *priv;
guint16 bits;
priv = UFO_TIFF_READER_GET_PRIVATE (reader);
TIFFGetField (priv->tiff, TIFFTAG_BITSPERSAMPLE, &bits);
if (bits == 64)
read_64_bit_data (priv, buffer, requisition, roi_y, roi_height, roi_step);
else
read_data (priv, buffer, requisition, bits, roi_y, roi_height, roi_step);
priv->more = TIFFReadDirectory (priv->tiff) == 1;
}
static gboolean
ufo_tiff_reader_get_meta (UfoReader *reader,
UfoRequisition *requisition,
UfoBufferDepth *bitdepth,
GError **error)
{
UfoTiffReaderPrivate *priv;
guint32 width;
guint32 height;
guint32 samples;
guint16 bits_per_sample;
priv = UFO_TIFF_READER_GET_PRIVATE (reader);
g_assert (priv->tiff != NULL);
TIFFGetField (priv->tiff, TIFFTAG_IMAGEWIDTH, &width);
TIFFGetField (priv->tiff, TIFFTAG_IMAGELENGTH, &height);
TIFFGetField (priv->tiff, TIFFTAG_SAMPLESPERPIXEL, &samples);
TIFFGetField (priv->tiff, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);
requisition->n_dims = samples == 3 ? 3 : 2;
requisition->dims[0] = (gsize) width;
requisition->dims[1] = (gsize) height;
requisition->dims[2] = samples == 3 ? 3 : 0;
switch (bits_per_sample) {
case 8:
*bitdepth = UFO_BUFFER_DEPTH_8U;
break;
case 12:
*bitdepth = UFO_BUFFER_DEPTH_12U;
break;
case 16:
*bitdepth = UFO_BUFFER_DEPTH_16U;
break;
default:
*bitdepth = UFO_BUFFER_DEPTH_32F;
}
return TRUE;
}
static void
ufo_tiff_reader_finalize (GObject *object)
{
UfoTiffReaderPrivate *priv;
priv = UFO_TIFF_READER_GET_PRIVATE (object);
if (priv->tiff != NULL)
ufo_tiff_reader_close (UFO_READER (object));
G_OBJECT_CLASS (ufo_tiff_reader_parent_class)->finalize (object);
}
static void
ufo_reader_interface_init (UfoReaderIface *iface)
{
iface->can_open = ufo_tiff_reader_can_open;
iface->open = ufo_tiff_reader_open;
iface->close = ufo_tiff_reader_close;
iface->read = ufo_tiff_reader_read;
iface->get_meta = ufo_tiff_reader_get_meta;
iface->data_available = ufo_tiff_reader_data_available;
}
static void
ufo_tiff_reader_class_init(UfoTiffReaderClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->finalize = ufo_tiff_reader_finalize;
g_type_class_add_private (gobject_class, sizeof (UfoTiffReaderPrivate));
}
static void
ufo_tiff_reader_init (UfoTiffReader *self)
{
UfoTiffReaderPrivate *priv = NULL;
self->priv = priv = UFO_TIFF_READER_GET_PRIVATE (self);
priv->tiff = NULL;
priv->more = FALSE;
TIFFSetWarningHandler(NULL);
}