dust3d/thirdparty/cgal/CGAL-5.1/include/CGAL/ImageIO/inr_impl.h

506 lines
14 KiB
C
Raw Normal View History

// Copyright (c) 2005-2008 ASCLEPIOS Project, INRIA Sophia-Antipolis (France)
// All rights reserved.
//
2020-10-13 12:44:25 +00:00
// This file is part of the ImageIO Library, and as been adapted for CGAL (www.cgal.org).
//
2020-10-13 12:44:25 +00:00
// $URL: https://github.com/CGAL/cgal/blob/v5.1/CGAL_ImageIO/include/CGAL/ImageIO/inr_impl.h $
// $Id: inr_impl.h 0779373 2020-03-26T13:31:46+01:00 Sébastien Loriot
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//
// Author(s) : ASCLEPIOS Project (INRIA Sophia-Antipolis), Laurent Rineau
#ifdef CGAL_HEADER_ONLY
#define CGAL_INLINE_FUNCTION inline
#else
#define CGAL_INLINE_FUNCTION
#endif
#include <CGAL/ImageIO/fgetns.h>
#include <string>
#include <sstream>
#include <string.h>
/* Magic header for inrimages v4 */
#define INR4_MAGIC "#INRIMAGE-4#{"
/** Magic header for inrimages */
#define INR_MAGIC "#INR"
typedef struct stringListElementStruct {
char *string;
struct stringListElementStruct *next;
} stringListElement;
/* list element with a pointer on a string */
typedef struct {
stringListElement *begin, *end;
} stringListHead;
/* string list descriptor */
#include <clocale>
class Set_numeric_locale {
const char * old_locale;
public:
2020-10-13 12:44:25 +00:00
Set_numeric_locale(const char* locale)
: old_locale(std::setlocale(LC_NUMERIC, locale))
{
}
~Set_numeric_locale() {
std::setlocale(LC_NUMERIC, old_locale);
}
};
static void addStringElement(stringListHead *strhead,
2020-10-13 12:44:25 +00:00
const char *str);
/* add a string element at the tail of given list */
static void concatStringElement(const stringListHead *strhead,
2020-10-13 12:44:25 +00:00
const char *str);
/* concat given string at the last element of given list */
/* Writes the given inrimage header in an already opened file.*/
CGAL_INLINE_FUNCTION
int _writeInrimageHeader(const _image *im, ENDIANNESS end) {
std::size_t pos, i;
char type[30], endianness[5], buf[257], scale[20];
std::ostringstream oss;
Set_numeric_locale num_locale("C");
if(im->openMode != OM_CLOSE) {
/* fix word kind */
switch(im->wordKind) {
case WK_FLOAT:
sprintf(type, "float");
scale[0] = '\0';
break;
case WK_FIXED:
switch(im->sign) {
case SGN_SIGNED:
2020-10-13 12:44:25 +00:00
sprintf(type, "signed fixed");
break;
case SGN_UNSIGNED:
2020-10-13 12:44:25 +00:00
sprintf(type, "unsigned fixed");
break;
default:
2020-10-13 12:44:25 +00:00
return -1;
}
sprintf(scale, "SCALE=2**0\n");
break;
2020-10-13 12:44:25 +00:00
default:
return -1;
}
2020-10-13 12:44:25 +00:00
switch(end) {
case END_LITTLE:
sprintf(endianness, "decm");
break;
case END_BIG:
sprintf(endianness, "sun");
break;
default:
/* fix architecture endianness */
if( _getEndianness() == END_LITTLE)
2020-10-13 12:44:25 +00:00
sprintf(endianness, "decm");
else
2020-10-13 12:44:25 +00:00
sprintf(endianness, "sun");
break;
}
/* write header information */
oss << INR4_MAGIC << "\n";
oss << "XDIM=" << im->xdim << "\n";
oss << "YDIM=" << im->ydim << "\n";
oss << "ZDIM=" << im->zdim << "\n";
oss << "VDIM=" << im->vdim << "\n";
oss << "TYPE=" << type << "\n";
oss << "PIXSIZE=" << im->wdim*8 <<" bits\n";
oss << scale << "CPU=" << endianness << "\n";
oss << "VX=" << im->vx << "\n";
oss << "VY=" << im->vy << "\n";
oss << "VZ=" << im->vz << "\n";
2020-10-13 12:44:25 +00:00
if ( im->cx != 0 )
oss << "XO="<< im->cx << "\n";
2020-10-13 12:44:25 +00:00
if ( im->cy != 0 )
oss << "YO="<< im->cy << "\n";
2020-10-13 12:44:25 +00:00
if ( im->cz != 0 )
oss << "ZO="<< im->cz << "\n";
2020-10-13 12:44:25 +00:00
if ( im->tx != 0.0 )
oss << "TX="<< im->tx << "\n";
2020-10-13 12:44:25 +00:00
if ( im->ty != 0.0 )
oss << "TY="<< im->ty << "\n";
2020-10-13 12:44:25 +00:00
if ( im->tz != 0.0 )
oss << "TZ="<< im->tz << "\n";
2020-10-13 12:44:25 +00:00
if ( im->rx != 0.0 )
oss << "RX="<< im->rx <<"\n";
2020-10-13 12:44:25 +00:00
if ( im->ry != 0.0 )
oss << "RY="<< im->ry << "\n";
2020-10-13 12:44:25 +00:00
if ( im->rz != 0.0 )
oss << "RZ=" << im->rz <<"\n";
pos = oss.str().length();
2020-10-13 12:44:25 +00:00
if(ImageIO_write(im, oss.str().data(), oss.str().length()) == 0)
return -1;
2020-10-13 12:44:25 +00:00
/* write user strings */
2020-10-13 12:44:25 +00:00
if ( im->user != nullptr ) {
for(i = 0; i < im->nuser; i++) {
2020-10-13 12:44:25 +00:00
if ( im->user[i] == nullptr ) continue;
pos += strlen(im->user[i]) + 2;
if(ImageIO_write(im, "#", 1) == 0) return -1;
if(ImageIO_write(im, im->user[i], strlen(im->user[i])) == 0) return -1;
if(ImageIO_write(im, "\n", 1) == 0) return -1;
}
}
/* write end of header */
pos = pos % 256;
if(pos > 252) {
for(i = pos; i < 256; i++)
2020-10-13 12:44:25 +00:00
if(ImageIO_write(im, "\n", 1) != 1) return -1;
pos = 0;
}
buf[0] = '\0';
for(i = pos; i < 252; i++) strcat(buf, "\n");
strcat(buf, "##}\n");
2020-10-13 12:44:25 +00:00
if(ImageIO_write(im, buf, strlen(buf)) == 0) return -1;
else return 1;
}
else return -1;
}
/* Writes the given image body in an already opened file.*/
CGAL_INLINE_FUNCTION
bool _writeInrimageData(const _image *im) {
std::size_t size, nbv, nwrt, i, v;
unsigned char **vp;
2020-10-13 12:44:25 +00:00
if(im->openMode != OM_CLOSE) {
/* scalar or interlaced vectors */
if(im->vectMode != VM_NON_INTERLACED) {
size = im->xdim * im->ydim * im->zdim * im->vdim * im->wdim;
nwrt = ImageIO_write(im, im->data, size);
return nwrt == size;
}
/* non interlaced vectors: interlace for saving */
else {
nbv = im->xdim * im->ydim * im->zdim;
size = im->xdim * im->ydim * im->zdim * im->wdim;
vp = (unsigned char **) ImageIO_alloc(im->vdim * sizeof(unsigned char *));
for(v = 0; v < im->vdim; v++)
2020-10-13 12:44:25 +00:00
vp[v] = (unsigned char *) im->data + v * size;
for(i = 0; i < nbv; i++)
2020-10-13 12:44:25 +00:00
for(v = 0; v < im->vdim; v++) {
if(ImageIO_write(im, (const void *) vp[v], im->wdim) != im->wdim)
return false;
vp[v] += im->wdim;
}
ImageIO_free(vp);
return true;
}
}
else return false;
}
/* read header of an opened inrimage */
CGAL_INLINE_FUNCTION
int readInrimageHeader(const char *,_image *im) {
char str[257];
int n, nusr;
2020-10-13 12:44:25 +00:00
stringListHead strl = { nullptr, nullptr };
stringListElement *oel, *el;
Set_numeric_locale num_locale("C");
if(im->openMode != OM_CLOSE) {
/* read image magic number */
if(!fgetns(str, 257, im )) return -1;
if(strcmp(str, INR4_MAGIC)) return -1;
/* while read line does not begin with '#' or '\n', read line
and decode field */
if(!fgetns(str, 257, im)) return -1;
while(str[0] != '#' && str[0] != '\0') {
if(!strncmp(str, "XDIM=", 5)) {
std::istringstream iss(str+5);
if(!(iss >> im->xdim)) return -1;
}
else if(!strncmp(str, "YDIM=", 5)) {
std::istringstream iss(str+5);
if(!(iss >> im->ydim)) return -1;
}
else if(!strncmp(str, "ZDIM=", 5)) {
std::istringstream iss(str+5);
if(!(iss >> im->zdim)) return -1;
}
else if(!strncmp(str, "VDIM=", 5)) {
std::istringstream iss(str+5);
if(!(iss >> im->vdim)) return -1;
2020-10-13 12:44:25 +00:00
if(im->vdim == 1) im->vectMode = VM_SCALAR;
else im->vectMode = VM_INTERLACED;
}
else if(!strncmp(str, "VX=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->vx)) return -1;
}
else if(!strncmp(str, "VY=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->vy)) return -1;
}
else if(!strncmp(str, "VZ=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->vz)) return -1;
}
else if(!strncmp(str, "TYPE=", 5)) {
2020-10-13 12:44:25 +00:00
if(!strncmp(str+5, "float", 5)) im->wordKind = WK_FLOAT;
else {
if(!strncmp(str+5, "signed fixed", 12)) {
im->wordKind = WK_FIXED;
im->sign = SGN_SIGNED;
}
else if(!strncmp(str+5, "unsigned fixed", 14)) {
im->wordKind = WK_FIXED;
im->sign = SGN_UNSIGNED;
}
else return -1;
}
}
/* before "sscanf(str+8, "%i %n", &im->wdim, &n) != 1"
2020-10-13 12:44:25 +00:00
was used.
However the man said
...
2020-10-13 12:44:25 +00:00
n Nothing is expected; instead, the number of charac­
ters consumed thus far from the input is stored
through the next pointer, which must be a pointer
to int. This is not a conversion, although it can
be suppressed with the * flag. The C standard
says: `Execution of a %n directive does not incre­
ment the assignment count returned at the comple­
tion of execution' but the Corrigendum seems to
contradict this. Probably it is wise not to make
any assumptions on the effect of %n conversions on
the return value.
2020-10-13 12:44:25 +00:00
...
Thus I change it. It was yielding a RETURN_FAILURE with
insight (GM).
*/
else if(!strncmp(str, "PIXSIZE=", 8)) {
std::istringstream iss(str+8);
if(!(iss >> im->wdim)) return -1;
2020-10-13 12:44:25 +00:00
if(im->wdim != 8 && im->wdim != 16 && im->wdim != 32 &&
im->wdim != 64) return -1;
if ( im->wdim <= 9 ) {
if(strncmp(str+8+1, " bits", 5)) return -1;
}
else if ( im->wdim <= 99 ) {
if(strncmp(str+8+2, " bits", 5)) return -1;
}
else {
return -1;
}
im->wdim >>= 3;
}
else if(!strncmp(str, "SCALE=", 6)) ;
else if(!strncmp(str, "CPU=", 4)) {
2020-10-13 12:44:25 +00:00
if(!strncmp(str+4, "decm", 4)) im->endianness = END_LITTLE;
else if(!strncmp(str+4, "alpha", 5)) im->endianness = END_LITTLE;
else if(!strncmp(str+4, "pc", 2)) im->endianness = END_LITTLE;
else if(!strncmp(str+4, "sun", 3)) im->endianness = END_BIG;
else if(!strncmp(str+4, "sgi", 3)) im->endianness = END_BIG;
else return -1;
}
else if(!strncmp(str, "XO=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->cx)) return -1;
}
else if(!strncmp(str, "YO=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->cy)) return -1;
}
else if(!strncmp(str, "ZO=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->cz)) return -1;
}
else if(!strncmp(str, "TX=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->tx)) return -1;
}
else if(!strncmp(str, "TY=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->ty)) return -1;
}
else if(!strncmp(str, "TZ=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->tz)) return -1;
}
else if(!strncmp(str, "RX=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->rx)) return -1;
}
else if(!strncmp(str, "RY=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->ry)) return -1;
}
else if(!strncmp(str, "RZ=", 3)) {
std::istringstream iss(str+3);
if(!(iss >> im->rz)) return -1;
}
if(!fgetns(str, 257, im)) return -1;
}
/* parse user strings */
im->nuser = nusr = 0;
while(str[0] == '#' && strncmp(str, "##}", 3)) {
addStringElement(&strl, str + 1);
while(strlen(str) == 256) {
2020-10-13 12:44:25 +00:00
if(!fgetns(str, 257, im)) return -1;
concatStringElement(&strl, str);
}
nusr++;
2020-10-13 12:44:25 +00:00
if(!fgetns(str, 257, im)) return -1;
}
2020-10-13 12:44:25 +00:00
/* go to end of header */
while(strncmp(str, "##}", 3)) {
if(!fgetns(str, 257, im)) return -1;
}
2020-10-13 12:44:25 +00:00
/* check header validity */
if(im->xdim > 0 && im->ydim > 0 && im->zdim > 0 && im->vdim > 0 &&
im->vx > 0.0 && im->vy > 0.0 && im->vz > 0.0 &&
(im->wordKind == WK_FLOAT || (im->wordKind == WK_FIXED &&
2020-10-13 12:44:25 +00:00
im->sign != SGN_UNKNOWN)) &&
im->endianness != END_UNKNOWN) {
if(nusr > 0) {
2020-10-13 12:44:25 +00:00
im->nuser = nusr;
im->user = (char **) ImageIO_alloc(im->nuser * sizeof(char *));
oel = nullptr;
for(el = strl.begin, n = 0; el != nullptr; el = oel, n++) {
im->user[n] = el->string;
oel = el->next;
ImageIO_free(el);
}
}
return 0;
}
else return -1;
}
else return -1;
}
/* add a string element at the tail of given list */
static void addStringElement(stringListHead *strhead, const char *str) {
stringListElement *el;
el = (stringListElement *) ImageIO_alloc(sizeof(stringListElement));
/* was strdup(str); */
el->string = (char*)ImageIO_alloc( strlen(str)+1);
memcpy(el->string, str, strlen(str)+1);
2020-10-13 12:44:25 +00:00
el->next = nullptr;
if(strhead->begin == nullptr)
strhead->begin = strhead->end = el;
else {
strhead->end->next = el;
strhead->end = el;
}
}
/* concat given string at the last element of given list */
static void concatStringElement(const stringListHead *strhead,
2020-10-13 12:44:25 +00:00
const char *str) {
stringListElement *el;
el = strhead->end;
el->string = (char *) realloc(el->string,
2020-10-13 12:44:25 +00:00
strlen(el->string) + strlen(str) + 1);
strcat(el->string, str);
}
CGAL_INLINE_FUNCTION
int testInrimageHeader(char *magic,const char *) {
if (!strcmp(magic, INR_MAGIC))
return 0;
2020-10-13 12:44:25 +00:00
else
return -1;
}
CGAL_INLINE_FUNCTION
int writeInrimage(char *name,_image *im) {
int res;
_openWriteImage( im, name );
if(!im->fd) {
fprintf(stderr, "writeInrimage: error: unable to open file \'%s\'\n", name );
return ImageIO_OPENING;
}
res = _writeInrimageHeader(im, END_UNKNOWN);
if (res < 0) {
fprintf(stderr, "writeInrimage: error: unable to write header of \'%s\'\n",
2020-10-13 12:44:25 +00:00
name);
ImageIO_close( im );
2020-10-13 12:44:25 +00:00
im->fd = nullptr;
im->openMode = OM_CLOSE;
return( res );
}
2020-10-13 12:44:25 +00:00
if (!_writeInrimageData(im)) {
fprintf(stderr, "writeInrimage: error: unable to write data of \'%s\'\n",
2020-10-13 12:44:25 +00:00
name);
ImageIO_close( im );
2020-10-13 12:44:25 +00:00
im->fd = nullptr;
im->openMode = OM_CLOSE;
return -1;
}
ImageIO_close( im );
2020-10-13 12:44:25 +00:00
im->fd = nullptr;
im->openMode = OM_CLOSE;
2020-10-13 12:44:25 +00:00
return ( res );
}
CGAL_INLINE_FUNCTION
PTRIMAGE_FORMAT createInrimageFormat() {
PTRIMAGE_FORMAT f=(PTRIMAGE_FORMAT) ImageIO_alloc(sizeof(IMAGE_FORMAT));
f->testImageFormat=&testInrimageHeader;
f->readImageHeader=&readInrimageHeader;
f->writeImage=&writeInrimage;
strcpy(f->fileExtension,".inr,.inr.gz,.gradient,.gradient.gz,.gradient_direction,.gradient_direction.gz");
strcpy(f->realName,"Inrimage");
return f;
}