/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% FFFFF IIIII TTTTT SSSSS %
% F I T SS %
% FFF I T SSS %
% F I T SS %
% F IIIII T SSSSS %
% %
% %
% Read/Write Flexible Image Transport System Images. %
% %
% Software Design %
% John Cristy %
% July 1992 %
% %
% %
% Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization %
% dedicated to making software imaging solutions freely available. %
% %
% You may not use this file except in compliance with the License. You may %
% obtain a copy of the License at %
% %
% http://www.imagemagick.org/script/license.php %
% %
% Unless required by applicable law or agreed to in writing, software %
% distributed under the License is distributed on an "AS IS" BASIS, %
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
% See the License for the specific language governing permissions and %
% limitations under the License. %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%
*/
/*
Include declarations.
*/
#include "magick/studio.h"
#include "magick/property.h"
#include "magick/blob.h"
#include "magick/blob-private.h"
#include "magick/color-private.h"
#include "magick/colorspace.h"
#include "magick/constitute.h"
#include "magick/exception.h"
#include "magick/exception-private.h"
#include "magick/image.h"
#include "magick/image-private.h"
#include "magick/list.h"
#include "magick/magick.h"
#include "magick/memory_.h"
#include "magick/monitor.h"
#include "magick/quantum-private.h"
#include "magick/quantum-private.h"
#include "magick/static.h"
#include "magick/statistic.h"
#include "magick/string_.h"
#include "magick/module.h"
#include "magick/module.h"
/*
Forward declarations.
*/
static MagickBooleanType
WriteFITSImage(const ImageInfo *,Image *);
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% I s F I T S %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% IsFITS() returns MagickTrue if the image format type, identified by the
% magick string, is FITS.
%
% The format of the IsFITS method is:
%
% MagickBooleanType IsFITS(const unsigned char *magick,const size_t length)
%
% A description of each parameter follows:
%
% o magick: This string is generally the first few bytes of an image file
% or blob.
%
% o length: Specifies the length of the magick string.
%
*/
static MagickBooleanType IsFITS(const unsigned char *magick,const size_t length)
{
if (length < 6)
return(MagickFalse);
if (LocaleNCompare((char *) magick,"IT0",3) == 0)
return(MagickTrue);
if (LocaleNCompare((char *) magick,"SIMPLE",6) == 0)
return(MagickTrue);
return(MagickFalse);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e a d F I T S I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ReadFITSImage() reads a FITS image file and returns it. It
% allocates the memory necessary for the new Image structure and returns a
% pointer to the new image.
%
% The format of the ReadFITSImage method is:
%
% Image *ReadFITSImage(const ImageInfo *image_info,
% ExceptionInfo *exception)
%
% A description of each parameter follows:
%
% o image: Method ReadFITSImage returns a pointer to the image after
% reading. A null image is returned if there is a memory shortage or if
% the image cannot be read.
%
% o filename: Specifies the name of the image to read.
%
% o exception: return any errors or warnings in this structure.
%
*/
static inline size_t MagickMin(const size_t x,const size_t y)
{
if (x < y)
return(x);
return(y);
}
static Image *ReadFITSImage(const ImageInfo *image_info,
ExceptionInfo *exception)
{
typedef struct _FITSInfo
{
int
simple,
bits_per_pixel,
columns,
rows,
number_axes,
number_planes;
double
min_data,
max_data,
zero,
scale;
} FITSInfo;
char
keyword[MaxTextExtent],
value[MaxTextExtent];
double
exponential[2048],
pixel,
scale,
scale_pixel;
FITSInfo
fits_info;
Image
*image;
IndexPacket
index;
int
c,
quantum;
long
exponent,
j,
k,
l,
scene,
y;
MagickBooleanType
status,
value_expected;
MagickSizeType
number_pixels;
register IndexPacket
*indexes;
register long
x;
register PixelPacket
*q;
register long
i;
register unsigned char
*p;
ssize_t
count;
size_t
packet_size;
unsigned char
*fits_pixels,
long_quantum[8];
/*
Open image file.
*/
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickSignature);
if (image_info->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
image_info->filename);
assert(exception != (ExceptionInfo *) NULL);
assert(exception->signature == MagickSignature);
image=AllocateImage(image_info);
status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
if (status == MagickFalse)
{
image=DestroyImageList(image);
return((Image *) NULL);
}
/*
Initialize image header.
*/
fits_info.simple=MagickFalse;
fits_info.bits_per_pixel=8;
fits_info.columns=1;
fits_info.rows=1;
fits_info.rows=1;
fits_info.number_planes=1;
fits_info.number_axes=0;
fits_info.min_data=0.0;
fits_info.max_data=0.0;
fits_info.zero=0.0;
fits_info.scale=1.0;
/*
Decode image header.
*/
c=ReadBlobByte(image);
if (c == EOF)
{
image=DestroyImage(image);
return((Image *) NULL);
}
for ( ; c != EOF; )
{
if (isalnum((int) ((unsigned char) c)) == 0)
c=ReadBlobByte(image);
else
{
register char
*p;
/*
Determine a keyword and its value.
*/
p=keyword;
do
{
if ((size_t) (p-keyword) < (MaxTextExtent/2))
*p++=(char) c;
c=ReadBlobByte(image);
} while ((isalnum((int) ((unsigned char) c)) != MagickFalse) ||
((int) c == '_'));
*p='\0';
if (LocaleCompare(keyword,"END") == 0)
break;
value_expected=MagickFalse;
while ((isspace((int) ((unsigned char) c)) != 0) || ((int) c == '='))
{
if ((int) c == '=')
value_expected=MagickTrue;
c=ReadBlobByte(image);
}
if (value_expected == MagickFalse)
continue;
p=value;
while (isalnum(c) || (c == '-') || (c == '+') || (c == '.'))
{
if ((size_t) (p-value) < (MaxTextExtent/2))
*p++=c;
c=ReadBlobByte(image);
}
*p='\0';
/*
Assign a value to the specified keyword.
*/
if (LocaleCompare(keyword,"SIMPLE") == 0)
fits_info.simple=(int) ((*value == 'T') || (*value == 't'));
if (LocaleCompare(keyword,"BITPIX") == 0)
fits_info.bits_per_pixel=atoi(value);
if (LocaleCompare(keyword,"NAXIS") == 0)
fits_info.number_axes=atoi(value);
if (LocaleCompare(keyword,"NAXIS1") == 0)
fits_info.columns=atoi(value);
if (LocaleCompare(keyword,"NAXIS2") == 0)
fits_info.rows=atoi(value);
if (LocaleCompare(keyword,"NAXIS3") == 0)
fits_info.number_planes=atoi(value);
if (LocaleCompare(keyword,"DATAMAX") == 0)
fits_info.max_data=atof(value);
if (LocaleCompare(keyword,"DATAMIN") == 0)
fits_info.min_data=atof(value);
if (LocaleCompare(keyword,"BZERO") == 0)
fits_info.zero=atof(value);
if (LocaleCompare(keyword,"BSCALE") == 0)
fits_info.scale=atof(value);
(void) SetImageProperty(image,keyword,value);
}
while (((TellBlob(image) % 80) != 0) && (c != EOF))
c=ReadBlobByte(image);
c=ReadBlobByte(image);
}
while (((TellBlob(image) % 2880) != 0) && (c != EOF))
c=ReadBlobByte(image);
/*
Verify that required image information is defined.
*/
number_pixels=(MagickSizeType) fits_info.columns*fits_info.rows;
if ((fits_info.simple == 0) || (fits_info.number_axes < 1) ||
(fits_info.number_axes > 4) || (number_pixels == 0))
ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
if (fits_info.bits_per_pixel == -32)
{
exponential[150]=1.0;
for (i=151; i < 256; i++)
exponential[i]=2.0*exponential[i-1];
for (i=149; i >= 0; i--)
exponential[i]=exponential[i+1]/2.0;
}
if (fits_info.bits_per_pixel == -64)
{
exponential[1075]=1.0;
for (i=1076; i < 2048; i++)
exponential[i]=2.0*exponential[i-1];
for (i=1074; i >= 0; i--)
exponential[i]=exponential[i+1]/2.0;
}
for (scene=0; scene < (long) fits_info.number_planes; scene++)
{
/*
Create linear colormap.
*/
image->columns=(unsigned long) fits_info.columns;
image->rows=(unsigned long) fits_info.rows;
image->depth=(unsigned long) (fits_info.bits_per_pixel <= 8 ? 8 :
MagickMin(QuantumDepth,16));
image->storage_class=PseudoClass;
image->scene=(unsigned long) scene;
if (AllocateImageColormap(image,1UL << image->depth) == MagickFalse)
ThrowReaderException(ResourceLimitError,"UnableToAllocateColormap");
if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
if (image->scene >= (image_info->scene+image_info->number_scenes-1))
break;
/*
Initialize image structure.
*/
if (SetImageExtent(image,0,0) == MagickFalse)
{
InheritException(exception,&image->exception);
return(DestroyImageList(image));
}
packet_size=(size_t) fits_info.bits_per_pixel/8;
if (fits_info.bits_per_pixel < 0)
packet_size=(size_t) (-fits_info.bits_per_pixel/8);
number_pixels=(MagickSizeType) image->columns*image->rows;
fits_pixels=(unsigned char *) AcquireQuantumMemory(image->columns,
image->rows*packet_size*sizeof(*fits_pixels));
if (fits_pixels == (unsigned char *) NULL)
ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
/*
Convert FITS pixels to pixel packets.
*/
count=ReadBlob(image,packet_size*image->columns*image->rows,fits_pixels);
if (count != (ssize_t) (packet_size*image->columns*image->rows))
ThrowReaderException(CorruptImageError,"InsufficientImageDataInFile");
if ((fits_info.min_data != 0.0) || (fits_info.max_data != 0.0))
{
if ((fits_info.bits_per_pixel != 0) && (fits_info.max_data == 0.0))
fits_info.max_data=(double) (1UL << fits_info.bits_per_pixel)-1;
}
else
{
/*
Determine minimum and maximum intensity.
*/
p=fits_pixels;
long_quantum[0]=(*p);
quantum=(*p++);
for (j=1; j <= (long) (packet_size-1); j++)
{
long_quantum[j]=(*p);
quantum=(quantum << 8) | (*p++);
}
pixel=(double) quantum;
if (fits_info.bits_per_pixel == 16)
{
if ((long_quantum[0] & 0x80) == 0)
pixel=(double) ((long_quantum[0] << 8) | long_quantum[1]);
else
pixel=(double) ((long_quantum[0] << 8) | long_quantum[1] | ~0xFFFF);
}
if (fits_info.bits_per_pixel == -32)
{
j=((long) long_quantum[1] << 16) | ((long) long_quantum[2] << 8) |
(long) long_quantum[3];
k=(int) *long_quantum;
exponent=((k & 0x7f) << 1) | (j >> 23);
*(float *) long_quantum=exponential[exponent]*
(float) (j | 0x800000);
if ((exponent | j) == 0)
*(float *) long_quantum=0.0;
if (k & 0x7f)
*(float *) long_quantum=(-(*(float *) long_quantum));
pixel=(double) (*((float *) long_quantum));
}
if (fits_info.bits_per_pixel == -64)
{
j=((long) long_quantum[1] << 24) | ((long) long_quantum[2] << 16) |
((long) long_quantum[3] << 8) | (long) long_quantum[4];
k=(int) *long_quantum;
l=((int) long_quantum[5] << 16) | ((int) long_quantum[6] << 8) |
(int) long_quantum[7];
exponent=((k & 0x7f) << 4) | (j >> 28);
*(double *) long_quantum=exponential[exponent]*(16777216.0*
(double) ((j & 0x0FFFFFFF) | 0x10000000)+(double) l);
if ((exponent | j | l) == 0)
*(double *) long_quantum=0.0;
if (k & 0x80)
*(double *) long_quantum=(-(*(double *) long_quantum));
pixel=(double) (*((double *) long_quantum));
}
fits_info.min_data=pixel*fits_info.scale+fits_info.zero;
fits_info.max_data=pixel*fits_info.scale+fits_info.zero;
for (i=1; i < (long) number_pixels; i++)
{
long_quantum[0]=(*p);
quantum=(*p++);
for (j=1; j <= (long) (packet_size-1); j++)
{
long_quantum[j]=(*p);
quantum=(quantum << 8) | (*p++);
}
pixel=(double) quantum;
if (fits_info.bits_per_pixel == 16)
{
if ((long_quantum[0] & 0x80) == 0)
pixel=(double) ((long_quantum[0] << 8) | long_quantum[1]);
else
pixel=(double) ((long_quantum[0] << 8) | long_quantum[1] | ~0xFFFF);
}
if (fits_info.bits_per_pixel == -32)
{
j=((long) long_quantum[1] << 16) | ((long) long_quantum[2] << 8) |
(long) long_quantum[3];
k=(int) *long_quantum;
exponent=((k & 0x7f) << 1) | (j >> 23);
*(float *) long_quantum=exponential[exponent]*(float)
(j | 0x800000);
if ((exponent | j) == 0)
*(float *) long_quantum=0.0;
if (k & 0x80)
*(float *) long_quantum=(-(*(float *) long_quantum));
pixel=(double) (*((float *) long_quantum));
}
if (fits_info.bits_per_pixel == -64)
{
j=((long) long_quantum[1] << 24) |
((long) long_quantum[2] << 16) | ((long) long_quantum[3] << 8) |
(long) long_quantum[4];
k=(int) *long_quantum;
l=((int) long_quantum[5] << 16) | ((int) long_quantum[6] << 8) |
(int) long_quantum[7];
exponent=((k & 0x7f) << 4) | (j >> 28);
*(double *) long_quantum=exponential[exponent]*(16777216.0*
(double) ((j & 0x0FFFFFFF) | 0x10000000)+(double) l);
if ((exponent | j | l) == 0)
*(double *) long_quantum=0.0;
if (k & 0x80)
*(double *)long_quantum=(-(*(double *) long_quantum));
pixel=(double) (*((double *) long_quantum));
}
scale_pixel=pixel*fits_info.scale+fits_info.zero;
if (scale_pixel < fits_info.min_data)
fits_info.min_data=scale_pixel;
if (scale_pixel > fits_info.max_data)
fits_info.max_data=scale_pixel;
}
}
/*
Convert FITS pixels to pixel packets.
*/
scale=1.0;
if ((fits_info.bits_per_pixel < 0) || ((fits_info.max_data-
fits_info.min_data) > (double) ((1UL << image->depth)-1)))
scale=(double) ((1UL << image->depth)-1)/(fits_info.max_data-
fits_info.min_data);
p=fits_pixels;
for (y=(long) image->rows-1; y >= 0; y--)
{
q=SetImagePixels(image,0,y,image->columns,1);
if (q == (PixelPacket *) NULL)
break;
indexes=GetIndexes(image);
for (x=0; x < (long) image->columns; x++)
{
long_quantum[0]=(*p);
quantum=(*p++);
for (j=1; j <= (long) (packet_size-1); j++)
{
long_quantum[j]=(*p);
quantum=(quantum << 8) | (*p++);
}
pixel=(double) quantum;
if (fits_info.bits_per_pixel == 16)
{
if ((long_quantum[0] & 0x80) == 0)
pixel=(double) ((long_quantum[0] << 8) | long_quantum[1]);
else
pixel=(double) ((long_quantum[0] << 8) | long_quantum[1] | ~0xFFFF);
}
if (fits_info.bits_per_pixel == -32)
{
j=((long) long_quantum[1] << 16) | ((long) long_quantum[2] << 8) |
(long) long_quantum[3];
k=(int) *long_quantum;
exponent=((k & 0x7f) << 1) | (j >> 23);
*(float *) long_quantum=exponential[exponent]*(float)
(j | 0x800000);
if ((exponent | j) == 0)
*(float *) long_quantum=0.0;
if (k & 0x80)
*(float *) long_quantum=(-(*(float *) long_quantum));
pixel=(double) (*((float *) long_quantum));
}
if (fits_info.bits_per_pixel == -64)
{
j=((long) long_quantum[1] << 24) | ((long) long_quantum[2] << 16) |
((long) long_quantum[3] << 8) | (long) long_quantum[4];
k=(long) *long_quantum;
l=((long) long_quantum[5] << 16) | ((long) long_quantum[6] << 8) |
(long) long_quantum[7];
exponent=(long) ((((unsigned long) k & 0x7f) << 4) |
((unsigned long) j >> 28));
*(double *) long_quantum=exponential[exponent]*(16777216.0*
(double) ((j & 0x0FFFFFFF) | 0x10000000)+(double) l);
if ((exponent | j | l) == 0)
*(double *) long_quantum=0.0;
if ((k & 0x80) != 0)
*(double *) long_quantum=(-(*(double *) long_quantum));
pixel=(double) (*((double *) long_quantum));
}
scale_pixel=scale*(pixel*fits_info.scale-fits_info.min_data+
fits_info.zero);
index=(IndexPacket) ((scale_pixel < 0.0) ? 0 : ((unsigned long)
scale_pixel > ((1UL << image->depth)-1)) ? ((1UL << image->depth)-1) :
(unsigned long) (scale_pixel+0.5));
index=ConstrainColormapIndex(image,1UL*index);
indexes[x]=index;
*q++=image->colormap[(long) index];
}
if (SyncImagePixels(image) == MagickFalse)
break;
if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
(QuantumTick(y,image->rows) != MagickFalse))
{
status=image->progress_monitor(LoadImageTag,y,image->rows,
image->client_data);
if (status == MagickFalse)
break;
}
}
fits_pixels=(unsigned char *) RelinquishMagickMemory(fits_pixels);
if (EOFBlob(image) != MagickFalse)
{
ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
image->filename);
break;
}
/*
Proceed to next image.
*/
if (image_info->number_scenes != 0)
if (image->scene >= (image_info->scene+image_info->number_scenes-1))
break;
if (scene < (long) (fits_info.number_planes-1))
{
/*
Allocate next image structure.
*/
AllocateNextImage(image_info,image);
if (GetNextImageInList(image) == (Image *) NULL)
{
image=DestroyImageList(image);
return((Image *) NULL);
}
image=SyncNextImageInList(image);
if (image->progress_monitor != (MagickProgressMonitor) NULL)
{
status=image->progress_monitor(LoadImagesTag,TellBlob(image),
GetBlobSize(image),image->client_data);
if (status == MagickFalse)
break;
}
}
}
CloseBlob(image);
return(GetFirstImageInList(image));
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% R e g i s t e r F I T S I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% RegisterFITSImage() adds attributes for the FITS image format to
% the list of supported formats. The attributes include the image format
% tag, a method to read and/or write the format, whether the format
% supports the saving of more than one frame to the same file or blob,
% whether the format supports native in-memory I/O, and a brief
% description of the format.
%
% The format of the RegisterFITSImage method is:
%
% unsigned long RegisterFITSImage(void)
%
*/
ModuleExport unsigned long RegisterFITSImage(void)
{
MagickInfo
*entry;
entry=SetMagickInfo("FITS");
entry->decoder=(DecodeImageHandler *) ReadFITSImage;
entry->encoder=(EncodeImageHandler *) WriteFITSImage;
entry->magick=(IsImageFormatHandler *) IsFITS;
entry->adjoin=MagickFalse;
entry->description=ConstantString("Flexible Image Transport System");
entry->module=ConstantString("FITS");
(void) RegisterMagickInfo(entry);
entry=SetMagickInfo("FTS");
entry->decoder=(DecodeImageHandler *) ReadFITSImage;
entry->encoder=(EncodeImageHandler *) WriteFITSImage;
entry->magick=(IsImageFormatHandler *) IsFITS;
entry->adjoin=MagickFalse;
entry->description=ConstantString("Flexible Image Transport System");
entry->module=ConstantString("FTS");
(void) RegisterMagickInfo(entry);
return(MagickImageCoderSignature);
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% U n r e g i s t e r F I T S I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% UnregisterFITSImage() removes format registrations made by the
% FITS module from the list of supported formats.
%
% The format of the UnregisterFITSImage method is:
%
% UnregisterFITSImage(void)
%
*/
ModuleExport void UnregisterFITSImage(void)
{
(void) UnregisterMagickInfo("FITS");
(void) UnregisterMagickInfo("FTS");
}
/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% %
% %
% %
% W r i t e F I T S I m a g e %
% %
% %
% %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% WriteFITSImage() writes a Flexible Image Transport System image to a
% file as gray scale intensities [0..255].
%
% The format of the WriteFITSImage method is:
%
% MagickBooleanType WriteFITSImage(const ImageInfo *image_info,
% Image *image)
%
% A description of each parameter follows.
%
% o image_info: The image info.
%
% o image: The image.
%
*/
static MagickBooleanType WriteFITSImage(const ImageInfo *image_info,
Image *image)
{
char
header[MaxTextExtent],
*fits_info;
IndexPacket
*indexes;
long
y;
MagickBooleanType
status;
MagickRealType
pixel;
MagickSizeType
length;
register const PixelPacket
*p;
register long
i,
x;
size_t
packet_size;
ssize_t
offset;
unsigned char
*pixels;
unsigned long
number_planes;
/*
Open output image file.
*/
assert(image_info != (const ImageInfo *) NULL);
assert(image_info->signature == MagickSignature);
assert(image != (Image *) NULL);
assert(image->signature == MagickSignature);
if (image->debug != MagickFalse)
(void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
if (status == MagickFalse)
return(status);
if (image_info->colorspace == UndefinedColorspace)
(void) SetImageColorspace(image,RGBColorspace);
/*
Allocate image memory.
*/
image->endian=MSBEndian;
image->depth=GetImageQuantumDepth(image,MagickTrue);
packet_size=(size_t) image->depth/8;
fits_info=(char *) AcquireQuantumMemory(2880UL,sizeof(*fits_info));
pixels=(unsigned char *) AcquireQuantumMemory(image->columns,packet_size*
sizeof(*pixels));
if ((fits_info == (char *) NULL) || (pixels == (unsigned char *) NULL))
ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
/*
Initialize image header.
*/
offset=0;
for (i=0; i < 2880; i++)
fits_info[i]=' ';
(void) FormatMagickString(header,MaxTextExtent,
"SIMPLE = T");
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) FormatMagickString(header,MaxTextExtent,"BITPIX = %10lu",
image->depth);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
number_planes=1;
if (IsGrayImage(image,&image->exception) == MagickFalse)
{
number_planes=3;
if (image->colorspace == CMYKColorspace)
number_planes++;
if (image->matte != MagickFalse)
number_planes++;
}
(void) FormatMagickString(header,MaxTextExtent,"NAXIS = %10lu",
number_planes >= 3 ? number_planes : 2);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) FormatMagickString(header,MaxTextExtent,"NAXIS1 = %10lu",
image->columns);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) FormatMagickString(header,MaxTextExtent,"NAXIS2 = %10lu",
image->rows);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
if (number_planes > 2)
{
(void) FormatMagickString(header,MaxTextExtent,"NAXIS3 = %10lu",
number_planes);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
}
(void) FormatMagickString(header,MaxTextExtent,"BSCALE = %E",1.0);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) FormatMagickString(header,MaxTextExtent,"BZERO = %E",
image->depth > 8 ? 1.0*(1UL << (image->depth-1UL)) : 0.0);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) FormatMagickString(header,MaxTextExtent,"DATAMAX = %E",
image->depth == 32 ? 4294967295.0 : 1.0*(1UL << image->depth)-1.0);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) FormatMagickString(header,MaxTextExtent,"DATAMIN = %E",0.0);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) FormatMagickString(header,MaxTextExtent,"HISTORY %.72s",
GetMagickVersion((unsigned long *) NULL));
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) strncpy(header,"END",MaxTextExtent);
(void) strncpy(fits_info+offset,header,strlen(header));
offset+=80;
(void) WriteBlob(image,2880,(unsigned char *) fits_info);
/*
Convert image to fits scale PseudoColor class.
*/
for (i=0; i < (long) number_planes; i++)
{
for (y=(long) image->rows-1; y >= 0; y--)
{
p=AcquireImagePixels(image,0,y,image->columns,1,&image->exception);
if (p == (const PixelPacket *) NULL)
break;
indexes=GetIndexes(image);
for (x=0; x < (long) image->columns; x++)
{
switch (i)
{
default:
case 0:
{
pixel=(MagickRealType) p->red;
if (number_planes == 1)
pixel=(MagickRealType) PixelIntensity(p);
break;
}
case 1: pixel=(MagickRealType) p->green; break;
case 2: pixel=(MagickRealType) p->blue; break;
case 3:
{
if (image->colorspace == CMYKColorspace)
pixel=(MagickRealType) indexes[x];
}
case 4: pixel=(MagickRealType) p->opacity; break;
}
if (image->depth > 8)
pixel+=1.0*(1UL << (image->depth-1UL));
if (image->depth > 16)
{
(void) WriteBlobByte(image,((unsigned char)
((unsigned long) (pixel+0.5) >> 24) & 0xff));
(void) WriteBlobByte(image,((unsigned char)
((unsigned long) (pixel+0.5) >> 16) & 0xff));
}
if (image->depth > 8)
(void) WriteBlobByte(image,((unsigned char)
((unsigned long) (pixel+0.5) >> 8) & 0xff));
(void) WriteBlobByte(image,(unsigned char)
((unsigned long) (pixel+0.5) & 0xff));
p++;
}
}
if ((image->progress_monitor != (MagickProgressMonitor) NULL) &&
(QuantumTick(i,number_planes) != MagickFalse))
{
status=image->progress_monitor(SaveImageTag,i,number_planes,
image->client_data);
if (status == MagickFalse)
break;
}
}
(void) ResetMagickMemory(fits_info,0,2880*sizeof(*fits_info));
length=packet_size*image->columns*image->rows;
(void) WriteBlob(image,2880-((size_t) length % 2880),(unsigned char *)
fits_info);
fits_info=DestroyString(fits_info);
pixels=(unsigned char *) RelinquishMagickMemory(pixels);
CloseBlob(image);
return(MagickTrue);
}
|