libvips/libsrc/format/im_rad2vips.c

336 lines
6.7 KiB
C

/* Read Radiance (.hdr) files
*/
/*
This file is part of VIPS.
VIPS 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 2 of the License, or
(at your option) any later version.
This program 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 program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
Sections of this reader come from Greg Ward and Radiance with kind
permission. The Radience copyright notice appears in "copyright.h".
*/
/*
*/
#define DEBUG
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "rtio.h"
#include "resolu.h"
#include "color.h"
#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif /*WITH_DMALLOC*/
/* What we track during an radiance-file read.
*/
typedef struct {
char *filename;
IMAGE *out;
FILE *fin;
char format[256];
double expos;
COLOR colcor;
double aspect;
RGBPRIMS prims;
COLOR *buf;
} Read;
static int
israd( const char *filename )
{
FILE *fin;
char format[256];
int result;
#ifdef DEBUG
printf( "israd: \"%s\"\n", filename );
#endif /*DEBUG*/
if( !(fin = fopen( filename, "r" )) )
return( 0 );
strcpy( format, "*" );
result = checkheader( fin, format, NULL );
fclose( fin );
return( result );
}
static void
read_destroy( Read *read )
{
IM_FREE( read->filename );
IM_FREEF( fclose, read->fin );
IM_FREE( read->buf );
im_free( read );
}
static Read *
read_new( const char *filename, IMAGE *out )
{
Read *read;
int i;
if( !(read = IM_NEW( NULL, Read )) )
return( NULL );
read->filename = im_strdup( NULL, filename );
read->out = out;
read->fin = NULL;
strcpy( read->format, COLRFMT );
read->expos = 1.0;
for( i = 0; i < 3; i++ )
read->colcor[i] = 1.0;
read->aspect = 1.0;
read->prims[0][0] = CIE_x_r;
read->prims[0][1] = CIE_y_r;
read->prims[1][0] = CIE_x_g;
read->prims[1][1] = CIE_y_g;
read->prims[2][0] = CIE_x_b;
read->prims[2][1] = CIE_y_b;
read->prims[3][0] = CIE_x_w;
read->prims[3][1] = CIE_y_w;
read->buf = NULL;
if( !(read->fin = fopen( filename, "r" )) ) {
read_destroy( read );
return( NULL );
}
return( read );
}
static int
rad2vips_process_line( char *line, Read *read )
{
if( isformat( line ) ) {
if( formatval( line, read->format ) )
return( -1 );
}
else if( isexpos( line ) ) {
read->expos *= exposval( line );
}
else if( iscolcor( line ) ) {
COLOR cc;
int i;
colcorval( cc, line );
for( i = 0; i < 3; i++ )
read->colcor[i] *= cc[i];
}
else if( isaspect( line ) ) {
read->aspect *= aspectval( line );
}
else if( isprims( line ) ) {
primsval( read->prims, line );
}
return( 0 );
}
static const char *prims_name[4][2] = {
{ "rad-prims-rx", "rad-prims-ry" },
{ "rad-prims-gx", "rad-prims-gy" },
{ "rad-prims-bx", "rad-prims-by" },
{ "rad-prims-wx", "rad-prims-wy" }
};
static const char *colcor_name[3] = {
"rad-colcor-r",
"rad-colcor-g",
"rad-colcor-b"
};
static int
rad2vips_get_header( Read *read, FILE *fin, IMAGE *out )
{
RESOLU rs;
int i, j;
if( getheader( fin, (gethfunc *) rad2vips_process_line, read ) ||
!fgetsresolu( &rs, fin ) ) {
im_error( "rad2vips",
"%s", _( "error reading radiance header" ) );
return( -1 );
}
out->Xsize = scanlen( &rs );
out->Ysize = numscans( &rs );
out->Bands = 3;
out->BandFmt = IM_BANDFMT_FLOAT;
out->Bbits = im_bits_of_fmt( out->BandFmt );
out->Coding = IM_CODING_NONE;
out->Xres = 1.0;
out->Yres = read->aspect;
out->Xoffset = 0.0;
out->Yoffset = 0.0;
if( im_meta_set_string( out, "rad-format", read->format ) )
return( -1 );
if( strcmp( read->format, COLRFMT ) == 0 )
out->Type = IM_TYPE_RGB;
else if( strcmp( read->format, CIEFMT ) == 0 )
out->Type = IM_TYPE_XYZ;
else
out->Type = IM_TYPE_MULTIBAND;
if( im_meta_set_double( out, "rad-expos", read->expos ) )
return( -1 );
for( i = 0; i < 3; i++ )
if( im_meta_set_double( out, colcor_name[i], read->colcor[i] ) )
return( -1 );
if( im_meta_set_double( out, "rad-aspect", read->aspect ) )
return( -1 );
for( i = 0; i < 4; i++ )
for( j = 0; j < 2; j++ )
if( im_meta_set_double( out,
prims_name[i][j], read->prims[i][j] ) )
return( -1 );
return( 0 );
}
static int
rad2vips_header( const char *filename, IMAGE *out )
{
Read *read;
#ifdef DEBUG
printf( "rad2vips_header: reading \"%s\"\n", filename );
#endif /*DEBUG*/
if( !(read = read_new( filename, out )) )
return( -1 );
if( rad2vips_get_header( read, read->fin, read->out ) ) {
read_destroy( read );
return( -1 );
}
read_destroy( read );
return( 0 );
}
static int
rad2vips_get_data( Read *read, FILE *fin, IMAGE *im )
{
int y;
#ifdef DEBUG
printf( "rad2vips_get_data\n" );
#endif /*DEBUG*/
if( im_outcheck( im ) ||
im_setupout( im ) )
return( -1 );
if( !(read->buf = IM_ARRAY( NULL, im->Xsize, COLOR )) )
return( -1 );
for( y = 0; y < im->Ysize; y++ ) {
if( freadscan( read->buf, im->Xsize, fin ) ) {
im_error( "rad2vips", "%s",
_( "read error" ) );
return( -1 );
}
if( im_writeline( y, im, (void *) read->buf ) )
return( -1 );
}
return( 0 );
}
static int
rad2vips( const char *filename, IMAGE *out )
{
Read *read;
#ifdef DEBUG
printf( "rad2vips: reading \"%s\"\n", filename );
#endif /*DEBUG*/
if( !(read = read_new( filename, out )) )
return( -1 );
if( rad2vips_get_header( read, read->fin, read->out ) ||
rad2vips_get_data( read, read->fin, read->out ) ) {
read_destroy( read );
return( -1 );
}
read_destroy( read );
return( 0 );
}
static const char *rad_suffs[] = { ".hdr", NULL };
/* rad format adds no new members.
*/
typedef VipsFormat VipsFormatRad;
typedef VipsFormatClass VipsFormatRadClass;
static void
vips_format_rad_class_init( VipsFormatRadClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsFormatClass *format_class = (VipsFormatClass *) class;
object_class->nickname = "rad";
object_class->description = _( "Radiance" );
format_class->is_a = israd;
format_class->header = rad2vips_header;
format_class->load = rad2vips;
format_class->save = NULL;
format_class->suffs = rad_suffs;
}
static void
vips_format_rad_init( VipsFormatRad *object )
{
}
G_DEFINE_TYPE( VipsFormatRad, vips_format_rad, VIPS_TYPE_FORMAT );