13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
23ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
33ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
43ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
53ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
63ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                        FFFFF  IIIII  TTTTT  SSSSS                           %
73ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                        F        I      T    SS                              %
83ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                        FFF      I      T     SSS                            %
93ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                        F        I      T       SS                           %
103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                        F      IIIII    T    SSSSS                           %
113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%            Read/Write Flexible Image Transport System Images.               %
143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                              Software Design                                %
16de984cdc3631106b1cbbb8d3972b76a0fc27e8e8cristy%                                   Cristy                                    %
173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                 July 1992                                   %
183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
207ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  dedicated to making software imaging solutions freely available.           %
223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  You may not use this file except in compliance with the License.  You may  %
243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  obtain a copy of the License at                                            %
253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    http://www.imagemagick.org/script/license.php                            %
273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  Unless required by applicable law or agreed to in writing, software        %
293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  See the License for the specific language governing permissions and        %
323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  limitations under the License.                                             %
333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Include declarations.
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
424c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
434c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/attribute.h"
444c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob.h"
454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob-private.h"
464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h"
474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/color-private.h"
484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace.h"
49510d06a3f7063e91993e13d546d5685048248074cristy#include "MagickCore/colorspace-private.h"
504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/constitute.h"
514c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h"
524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h"
534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h"
544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h"
554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h"
564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h"
574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h"
584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/module.h"
594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor.h"
604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h"
614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/pixel-accessor.h"
624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/property.h"
634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum-private.h"
644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/static.h"
654c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/statistic.h"
664c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h"
674c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string-private.h"
684c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/module.h"
693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Forward declarations.
723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy#define FITSBlocksize  2880UL
743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Forward declarations.
773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
783ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType
791e178e70fb3c956f9fc1e30c3ba863e882666465cristy  WriteFITSImage(const ImageInfo *,Image *,ExceptionInfo *);
803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   I s F I T S                                                               %
873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  IsFITS() returns MagickTrue if the image format type, identified by the
933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  magick string, is FITS.
943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the IsFITS method is:
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType IsFITS(const unsigned char *magick,const size_t length)
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o magick: compare image format pattern against these bytes.
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o length: Specifies the length of the magick string.
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType IsFITS(const unsigned char *magick,const size_t length)
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length < 6)
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
1103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (LocaleNCompare((const char *) magick,"IT0",3) == 0)
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickTrue);
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (LocaleNCompare((const char *) magick,"SIMPLE",6) == 0)
1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickTrue);
1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickFalse);
1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e a d F I T S I m a g e                                                 %
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  ReadFITSImage() reads a FITS image file and returns it.  It allocates the
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  memory necessary for the new Image structure and returns a pointer to the
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  new image.
1313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the ReadFITSImage method is:
1333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      Image *ReadFITSImage(const ImageInfo *image_info,
1353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%        ExceptionInfo *exception)
1363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows:
1383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image_info: the image info.
1403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o exception: return any errors or warnings in this structure.
1423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
1433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
1443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1453ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic inline double GetFITSPixel(Image *image,int bits_per_pixel)
1463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch (image->depth >> 3)
1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 1:
1503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return((double) ReadBlobByte(image));
1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 2:
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return((double) ((short) ReadBlobShort(image)));
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 4:
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (bits_per_pixel > 0)
1561fe0b879964fa7797e3d68574d297922a47c4034Cristy        return((double) ReadBlobSignedLong(image));
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return((double) ReadBlobFloat(image));
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 8:
1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
1613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (bits_per_pixel > 0)
1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        return((double) ((MagickOffsetType) ReadBlobLongLong(image)));
1633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    default:
1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
1663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(ReadBlobDouble(image));
1683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1704d0ca34912f861b25e5ed95e3f624048cb180358cristystatic MagickOffsetType GetFITSPixelExtrema(Image *image,
1714d0ca34912f861b25e5ed95e3f624048cb180358cristy  const int bits_per_pixel,double *minima,double *maxima)
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixel;
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickOffsetType
1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    offset;
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickSizeType
1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_pixels;
1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  register MagickOffsetType
1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
1843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset=TellBlob(image);
1864d0ca34912f861b25e5ed95e3f624048cb180358cristy  if (offset == -1)
1874d0ca34912f861b25e5ed95e3f624048cb180358cristy    return(-1);
1883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_pixels=(MagickSizeType) image->columns*image->rows;
1893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  *minima=GetFITSPixel(image,bits_per_pixel);
1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  *maxima=(*minima);
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (i=1; i < (MagickOffsetType) number_pixels; i++)
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixel=GetFITSPixel(image,bits_per_pixel);
1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (pixel < *minima)
1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      *minima=pixel;
1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (pixel > *maxima)
1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      *maxima=pixel;
1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
1994d0ca34912f861b25e5ed95e3f624048cb180358cristy  return(SeekBlob(image,offset,SEEK_SET));
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
202bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristystatic inline double GetFITSPixelRange(const size_t depth)
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return((double) ((MagickOffsetType) GetQuantumRange(depth)));
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic void SetFITSUnsignedPixels(const size_t length,
208f84dc8edf517e117a2c1481d841b37cde852a6e9cristy  const size_t bits_per_pixel,const EndianType endian,unsigned char *pixels)
2093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
210bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i;
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
213f84dc8edf517e117a2c1481d841b37cde852a6e9cristy  if (endian != MSBEndian)
214f84dc8edf517e117a2c1481d841b37cde852a6e9cristy    pixels+=(bits_per_pixel >> 3)-1;
215bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (i=0; i < (ssize_t) length; i++)
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *pixels^=0x80;
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixels+=bits_per_pixel >> 3;
2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
2203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic Image *ReadFITSImage(const ImageInfo *image_info,
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ExceptionInfo *exception)
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  typedef struct _FITSInfo
2263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
2273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    MagickBooleanType
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      extend,
2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      simple;
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    int
2323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      bits_per_pixel,
2333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      columns,
2343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      rows,
2353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      number_axes,
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      number_planes;
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    double
2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      min_data,
2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      max_data,
2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      zero,
2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      scale;
2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    EndianType
2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      endian;
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  } FITSInfo;
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *comment,
2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    keyword[9],
251151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy    property[MagickPathExtent],
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    value[73];
2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  double
2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    pixel,
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    scale;
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  FITSInfo
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    fits_info;
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *image;
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  int
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    c;
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickSizeType
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_pixels;
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
273bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  register ssize_t
2743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    i,
2753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    x;
2763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2774c08aed51c5899665ade97263692328eea4af106cristy  register Quantum
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *q;
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ssize_t
281202de443c199963563857f50153b88fbe65afa80cristy    count,
282202de443c199963563857f50153b88fbe65afa80cristy    scene,
283202de443c199963563857f50153b88fbe65afa80cristy    y;
2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Open image file.
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image_info != (const ImageInfo *) NULL);
289e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image_info->signature == MagickCoreSignature);
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image_info->debug != MagickFalse)
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image_info->filename);
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception != (ExceptionInfo *) NULL);
294e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
2959950d57e1124b73f684fb5946e206994cefda628cristy  image=AcquireImage(image_info,exception);
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image=DestroyImageList(image);
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      return((Image *) NULL);
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize image header.
3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(&fits_info,0,sizeof(fits_info));
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.extend=MagickFalse;
3073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.simple=MagickFalse;
3083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.bits_per_pixel=8;
3093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.columns=1;
3103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.rows=1;
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.number_planes=1;
3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.min_data=0.0;
3133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.max_data=0.0;
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.zero=0.0;
3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.scale=1.0;
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info.endian=MSBEndian;
3173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Decode image header.
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
3203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  for (comment=(char *) NULL; EOFBlob(image) == MagickFalse; )
3213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
3223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    for ( ; EOFBlob(image) == MagickFalse; )
3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      register char
3253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        *p;
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      count=ReadBlob(image,8,(unsigned char *) keyword);
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (count != 8)
3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      for (i=0; i < 8; i++)
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
3323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (isspace((int) ((unsigned char) keyword[i])) != 0)
3333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
334466802f1ee909e98875e99242aa81bf512526125cristy        keyword[i]=tolower((int) ((unsigned char) keyword[i]));
3353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
3363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      keyword[i]='\0';
3373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      count=ReadBlob(image,72,(unsigned char *) value);
338e3216eb99bc9e5c5d003554881083db6463ae109cristy      value[72]='\0';
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (count != 72)
3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
3413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      p=value;
3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (*p == '=')
3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          p+=2;
3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          while (isspace((int) ((unsigned char) *p)) != 0)
3463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            p++;
3473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
3483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"end") == 0)
3493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
3503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"extend") == 0)
3513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        fits_info.extend=(*p == 'T') || (*p == 't') ? MagickTrue : MagickFalse;
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"simple") == 0)
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        fits_info.simple=(*p == 'T') || (*p == 't') ? MagickTrue : MagickFalse;
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"bitpix") == 0)
355f2f2727f17ecbb23d902f70bb98f81faabc92dbdcristy        fits_info.bits_per_pixel=StringToLong(p);
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"naxis") == 0)
357f2f2727f17ecbb23d902f70bb98f81faabc92dbdcristy        fits_info.number_axes=StringToLong(p);
3583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"naxis1") == 0)
359f2f2727f17ecbb23d902f70bb98f81faabc92dbdcristy        fits_info.columns=StringToLong(p);
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"naxis2") == 0)
361f2f2727f17ecbb23d902f70bb98f81faabc92dbdcristy        fits_info.rows=StringToLong(p);
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"naxis3") == 0)
363f2f2727f17ecbb23d902f70bb98f81faabc92dbdcristy        fits_info.number_planes=StringToLong(p);
3643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"datamax") == 0)
365dbdd0e35efc03c9bccda644f5407db38b7c17eeccristy        fits_info.max_data=StringToDouble(p,(char **) NULL);
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"datamin") == 0)
367dbdd0e35efc03c9bccda644f5407db38b7c17eeccristy        fits_info.min_data=StringToDouble(p,(char **) NULL);
3683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"bzero") == 0)
369dbdd0e35efc03c9bccda644f5407db38b7c17eeccristy        fits_info.zero=StringToDouble(p,(char **) NULL);
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"bscale") == 0)
371dbdd0e35efc03c9bccda644f5407db38b7c17eeccristy        fits_info.scale=StringToDouble(p,(char **) NULL);
3723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"comment") == 0)
3733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (comment == (char *) NULL)
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            comment=ConstantString(p);
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            (void) ConcatenateString(&comment,p);
3783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (LocaleCompare(keyword,"xendian") == 0)
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
3813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (LocaleNCompare(p,"big",3) == 0)
3823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            fits_info.endian=MSBEndian;
3833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          else
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            fits_info.endian=LSBEndian;
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
386151b66dffc9e3c2e8c4f8cdaca37ff987ca0f497cristy      (void) FormatLocaleString(property,MagickPathExtent,"fits:%s",keyword);
387d15e65928aec551b7388c2863de3e3e628e2e0ddcristy      (void) SetImageProperty(image,property,p,exception);
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    c=0;
3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    while (((TellBlob(image) % FITSBlocksize) != 0) && (c != EOF))
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      c=ReadBlobByte(image);
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (fits_info.extend == MagickFalse)
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
39411dc2b8f83c2e99ee6e80724c9ec83985bcf4123cristy    if ((fits_info.bits_per_pixel != 8) && (fits_info.bits_per_pixel != 16) &&
39511dc2b8f83c2e99ee6e80724c9ec83985bcf4123cristy        (fits_info.bits_per_pixel != 32) && (fits_info.bits_per_pixel != 64) &&
39611dc2b8f83c2e99ee6e80724c9ec83985bcf4123cristy        (fits_info.bits_per_pixel != -32) && (fits_info.bits_per_pixel != -64))
39711dc2b8f83c2e99ee6e80724c9ec83985bcf4123cristy      ThrowReaderException(CorruptImageError,"ImproperImageHeader");
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    number_pixels=(MagickSizeType) fits_info.columns*fits_info.rows;
3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if ((fits_info.simple != MagickFalse) && (fits_info.number_axes >= 1) &&
4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (fits_info.number_axes <= 4) && (number_pixels != 0))
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
4043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Verify that required image information is defined.
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (comment != (char *) NULL)
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
408d15e65928aec551b7388c2863de3e3e628e2e0ddcristy      (void) SetImageProperty(image,"comment",comment,exception);
4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      comment=DestroyString(comment);
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (EOFBlob(image) != MagickFalse)
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->filename);
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  number_pixels=(MagickSizeType) fits_info.columns*fits_info.rows;
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((fits_info.simple == MagickFalse) || (fits_info.number_axes < 1) ||
4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (fits_info.number_axes > 4) || (number_pixels == 0))
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowReaderException(CorruptImageError,"ImageTypeNotSupported");
418bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for (scene=0; scene < (ssize_t) fits_info.number_planes; scene++)
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
420bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    image->columns=(size_t) fits_info.columns;
421bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    image->rows=(size_t) fits_info.rows;
422bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    image->depth=(size_t) (fits_info.bits_per_pixel < 0 ? -1 : 1)*
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      fits_info.bits_per_pixel;
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image->endian=fits_info.endian;
425bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    image->scene=(size_t) scene;
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
429acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    status=SetImageExtent(image,image->columns,image->rows,exception);
430acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    if (status == MagickFalse)
431acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy      return(DestroyImageList(image));
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Initialize image structure.
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
435d8b3981c6999bf911461b349e15e704bec7018e8cristy    (void) SetImageColorspace(image,GRAYColorspace,exception);
436d8b3981c6999bf911461b349e15e704bec7018e8cristy    if ((fits_info.min_data == 0.0) && (fits_info.max_data == 0.0))
4373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4383f6782c0dc3e6887aa0aefc50b3af64dca8bd56fcristy        if (fits_info.zero == 0.0)
4394d0ca34912f861b25e5ed95e3f624048cb180358cristy          (void) GetFITSPixelExtrema(image,fits_info.bits_per_pixel,
440d8b3981c6999bf911461b349e15e704bec7018e8cristy            &fits_info.min_data,&fits_info.max_data);
441d8b3981c6999bf911461b349e15e704bec7018e8cristy        else
442bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy          fits_info.max_data=GetFITSPixelRange((size_t)
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            fits_info.bits_per_pixel);
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else
446d8b3981c6999bf911461b349e15e704bec7018e8cristy      fits_info.max_data=GetFITSPixelRange((size_t) fits_info.bits_per_pixel);
4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Convert FITS pixels to pixel packets.
4493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
450d8b3981c6999bf911461b349e15e704bec7018e8cristy    scale=QuantumRange/(fits_info.max_data-fits_info.min_data);
451bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for (y=(ssize_t) image->rows-1; y >= 0; y--)
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
4533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
454acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy      if (q == (Quantum *) NULL)
4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
456bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for (x=0; x < (ssize_t) image->columns; x++)
4573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        pixel=GetFITSPixel(image,fits_info.bits_per_pixel);
459163d678c009fa8c11235958390ee6d4ae72e6bb0cristy        if ((image->depth == 16) || (image->depth == 32) ||
4609dcadc5f0faf65fa11d5c936820bf3d29b251e73cristy            (image->depth == 64))
461f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(1,image->depth,image->endian,
462f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            (unsigned char *) &pixel);
46312142880208887a1ad6de5b954b2ec18e5d8ebb1cristy        SetPixelGray(image,ClampToQuantum(scale*(fits_info.scale*(pixel-
46412142880208887a1ad6de5b954b2ec18e5d8ebb1cristy          fits_info.min_data)+fits_info.zero)),q);
465ed2315769b26818ed9d0c1291dc0457f0d8da0a4cristy        q+=GetPixelChannels(image);
4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (SyncAuthenticPixels(image,exception) == MagickFalse)
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->previous == (Image *) NULL)
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
471cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy          status=SetImageProgress(image,LoadImageTag,(MagickOffsetType) y,
4724c08aed51c5899665ade97263692328eea4af106cristy            image->rows);
4733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (status == MagickFalse)
4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            break;
4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
4763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (EOFBlob(image) != MagickFalse)
4783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
4803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          image->filename);
4813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
4843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      Proceed to next image.
4853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    */
4863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (image_info->number_scenes != 0)
4873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
4883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
489bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    if (scene < (ssize_t) (fits_info.number_planes-1))
4903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        /*
4923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          Allocate next image structure.
4933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        */
4949950d57e1124b73f684fb5946e206994cefda628cristy        AcquireNextImage(image_info,image,exception);
4953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (GetNextImageInList(image) == (Image *) NULL)
4963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          {
4973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            image=DestroyImageList(image);
4983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            return((Image *) NULL);
4993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          }
5003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        image=SyncNextImageInList(image);
5013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
5023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GetBlobSize(image));
5033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (status == MagickFalse)
5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
5053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
5063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
5073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) CloseBlob(image);
5083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(GetFirstImageInList(image));
5093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
5123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   R e g i s t e r F I T S I m a g e                                         %
5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  RegisterFITSImage() adds attributes for the FITS image format to
5233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  the list of supported formats.  The attributes include the image format
5243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  tag, a method to read and/or write the format, whether the format
5253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  supports the saving of more than one frame to the same file or blob,
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  whether the format supports native in-memory I/O, and a brief
5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  description of the format.
5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the RegisterFITSImage method is:
5303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
531bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy%      size_t RegisterFITSImage(void)
5323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
534bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristyModuleExport size_t RegisterFITSImage(void)
5353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
5363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickInfo
5373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *entry;
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
53906b627a07ff44e1ff93ef1288c9f428066ded10ddirk  entry=AcquireMagickInfo("FITS","FITS","Flexible Image Transport System");
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->decoder=(DecodeImageHandler *) ReadFITSImage;
5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->encoder=(EncodeImageHandler *) WriteFITSImage;
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->magick=(IsImageFormatHandler *) IsFITS;
54308e9a113db499034abb5ad8d59b42f8eca3c641cdirk  entry->flags^=CoderAdjoinFlag;
54408e9a113db499034abb5ad8d59b42f8eca3c641cdirk  entry->flags|=CoderSeekableStreamFlag;
5453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) RegisterMagickInfo(entry);
546cbab2d169229a0a8f2509ebff047bb9ada533348dirk  entry=AcquireMagickInfo("FITS","FTS","Flexible Image Transport System");
5473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->decoder=(DecodeImageHandler *) ReadFITSImage;
5483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->encoder=(EncodeImageHandler *) WriteFITSImage;
5493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->magick=(IsImageFormatHandler *) IsFITS;
55008e9a113db499034abb5ad8d59b42f8eca3c641cdirk  entry->flags^=CoderAdjoinFlag;
55108e9a113db499034abb5ad8d59b42f8eca3c641cdirk  entry->flags|=CoderSeekableStreamFlag;
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) RegisterMagickInfo(entry);
5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickImageCoderSignature);
5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   U n r e g i s t e r F I T S I m a g e                                     %
5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  UnregisterFITSImage() removes format registrations made by the
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  FITS module from the list of supported formats.
5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the UnregisterFITSImage method is:
5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      UnregisterFITSImage(void)
5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
5753ed852eea50f9d4cd633efb8c2b054b8e33c253cristyModuleExport void UnregisterFITSImage(void)
5763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
5773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) UnregisterMagickInfo("FITS");
5783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) UnregisterMagickInfo("FTS");
5793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
5803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
5823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%   W r i t e F I T S I m a g e                                               %
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%                                                                             %
5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  WriteFITSImage() writes a Flexible Image Transport System image to a
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  file as gray scale intensities [0..255].
5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  The format of the WriteFITSImage method is:
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%      MagickBooleanType WriteFITSImage(const ImageInfo *image_info,
5981e178e70fb3c956f9fc1e30c3ba863e882666465cristy%        Image *image,ExceptionInfo *exception)
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%  A description of each parameter follows.
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image_info: the image info.
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%    o image:  The image.
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy%
6061e178e70fb3c956f9fc1e30c3ba863e882666465cristy%    o exception: return any errors or warnings in this structure.
6071e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType WriteFITSImage(const ImageInfo *image_info,
6101e178e70fb3c956f9fc1e30c3ba863e882666465cristy  Image *image,ExceptionInfo *exception)
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  char
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    header[FITSBlocksize],
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *fits_info;
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantumInfo
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *quantum_info;
6213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6224c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
6243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t
6263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    length;
6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ssize_t
6293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    count,
6302692d59654732a12061a218a8bc7d969b03061eccristy    offset,
6312692d59654732a12061a218a8bc7d969b03061eccristy    y;
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  unsigned char
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *pixels;
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
6373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Open output image file.
6383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image_info != (const ImageInfo *) NULL);
640e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image_info->signature == MagickCoreSignature);
6413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
642e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
6443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
6453a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy  assert(exception != (ExceptionInfo *) NULL);
646e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
6471e178e70fb3c956f9fc1e30c3ba863e882666465cristy  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
6483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
650af8d391906d11f0a1f2bbf4e2adbc4995c852d33cristy  (void) TransformImageColorspace(image,sRGBColorspace,exception);
6513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Allocate image memory.
6533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
6543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info=(char *) AcquireQuantumMemory(FITSBlocksize,sizeof(*fits_info));
6553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (fits_info == (char *) NULL)
6563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
6573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) ResetMagickMemory(fits_info,' ',FITSBlocksize*sizeof(*fits_info));
6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
6593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Initialize image header.
6603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  image->depth=GetImageQuantumDepth(image,MagickFalse);
6626ea44a9922b30e9f2a54f567ab04bb763ccd7125cristy  image->endian=MSBEndian;
6635f766ef8b0cd9906c2c3a56d845828380a251073cristy  quantum_info=AcquireQuantumInfo(image_info,image);
6643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (quantum_info == (QuantumInfo *) NULL)
6653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowWriterException(ResourceLimitError,"MemoryAllocationFailed");
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset=0;
667b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    "SIMPLE  =                    T");
6693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
671b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"BITPIX  =           %10ld",
67267e3eab96621f8650c8e73994eba161cea0fd9e6cristy    (long) ((quantum_info->format == FloatingPointQuantumFormat ? -1 : 1)*
67367e3eab96621f8650c8e73994eba161cea0fd9e6cristy    image->depth));
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
676b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"NAXIS   =           %10lu",
677f1d8548abecaf5ca89d453fd9fc0cde77d20672bdirk    SetImageGray(image,exception) != MagickFalse ? 2UL : 3UL);
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
680b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"NAXIS1  =           %10lu",
681f2faecf9facdbbb14fcba373365f9f691a9658e0cristy    (unsigned long) image->columns);
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
684b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"NAXIS2  =           %10lu",
685f2faecf9facdbbb14fcba373365f9f691a9658e0cristy    (unsigned long) image->rows);
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
6873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
688f1d8548abecaf5ca89d453fd9fc0cde77d20672bdirk  if (SetImageGray(image,exception) == MagickFalse)
689fcbcae8c995398624afd038a1b8e327031b11e47cristy    {
690b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy      (void) FormatLocaleString(header,FITSBlocksize,
691fcbcae8c995398624afd038a1b8e327031b11e47cristy        "NAXIS3  =           %10lu",3UL);
692fcbcae8c995398624afd038a1b8e327031b11e47cristy      (void) strncpy(fits_info+offset,header,strlen(header));
693fcbcae8c995398624afd038a1b8e327031b11e47cristy      offset+=80;
694fcbcae8c995398624afd038a1b8e327031b11e47cristy    }
695b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"BSCALE  =         %E",1.0);
6963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
6973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
698b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"BZERO   =         %E",
6993ec9e8d654d290b2d60137f2afe438773016eb61cristy    image->depth > 8 ? GetFITSPixelRange(image->depth)/2.0 : 0.0);
7003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
7013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
702b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"DATAMAX =         %E",
7033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    1.0*((MagickOffsetType) GetQuantumRange(image->depth)));
7043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
7053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
706b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"DATAMIN =         %E",0.0);
7073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
7083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
7093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->endian == LSBEndian)
7103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
711b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy      (void) FormatLocaleString(header,FITSBlocksize,"XENDIAN = 'SMALL'");
7123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) strncpy(fits_info+offset,header,strlen(header));
7133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      offset+=80;
7143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
715b51dff5c0d16a4c1b69ff683e786cb3b4c467694cristy  (void) FormatLocaleString(header,FITSBlocksize,"HISTORY %.72s",
716bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    GetMagickVersion((size_t *) NULL));
7173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
7183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
7193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(header,"END",FITSBlocksize);
7203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) strncpy(fits_info+offset,header,strlen(header));
7213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  offset+=80;
7223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlob(image,FITSBlocksize,(unsigned char *) fits_info);
7233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
7243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Convert image to fits scale PseudoColor class.
7253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
726b3f97ae45019a91b30792a6fa42d81a2689a7025cristy  pixels=(unsigned char *) GetQuantumPixels(quantum_info);
727f1d8548abecaf5ca89d453fd9fc0cde77d20672bdirk  if (SetImageGray(image,exception) != MagickFalse)
728fcbcae8c995398624afd038a1b8e327031b11e47cristy    {
729fcbcae8c995398624afd038a1b8e327031b11e47cristy      length=GetQuantumExtent(image,quantum_info,GrayQuantum);
730fcbcae8c995398624afd038a1b8e327031b11e47cristy      for (y=(ssize_t) image->rows-1; y >= 0; y--)
731fcbcae8c995398624afd038a1b8e327031b11e47cristy      {
7321e178e70fb3c956f9fc1e30c3ba863e882666465cristy        p=GetVirtualPixels(image,0,y,image->columns,1,exception);
7334c08aed51c5899665ade97263692328eea4af106cristy        if (p == (const Quantum *) NULL)
734fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
7354c08aed51c5899665ade97263692328eea4af106cristy        length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
7361e178e70fb3c956f9fc1e30c3ba863e882666465cristy          GrayQuantum,pixels,exception);
737fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (image->depth == 16)
738f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
739f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
740fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (((image->depth == 32) || (image->depth == 64)) &&
741fcbcae8c995398624afd038a1b8e327031b11e47cristy            (quantum_info->format != FloatingPointQuantumFormat))
742f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
743f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
744fcbcae8c995398624afd038a1b8e327031b11e47cristy        count=WriteBlob(image,length,pixels);
745fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (count != (ssize_t) length)
746fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
747fcbcae8c995398624afd038a1b8e327031b11e47cristy        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
748fcbcae8c995398624afd038a1b8e327031b11e47cristy          image->rows);
749fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (status == MagickFalse)
750fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
751fcbcae8c995398624afd038a1b8e327031b11e47cristy      }
752fcbcae8c995398624afd038a1b8e327031b11e47cristy    }
753fcbcae8c995398624afd038a1b8e327031b11e47cristy  else
754fcbcae8c995398624afd038a1b8e327031b11e47cristy    {
755fcbcae8c995398624afd038a1b8e327031b11e47cristy      length=GetQuantumExtent(image,quantum_info,RedQuantum);
756fcbcae8c995398624afd038a1b8e327031b11e47cristy      for (y=(ssize_t) image->rows-1; y >= 0; y--)
757fcbcae8c995398624afd038a1b8e327031b11e47cristy      {
7581e178e70fb3c956f9fc1e30c3ba863e882666465cristy        p=GetVirtualPixels(image,0,y,image->columns,1,exception);
7594c08aed51c5899665ade97263692328eea4af106cristy        if (p == (const Quantum *) NULL)
760fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
7614c08aed51c5899665ade97263692328eea4af106cristy        length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
7621e178e70fb3c956f9fc1e30c3ba863e882666465cristy          RedQuantum,pixels,exception);
763fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (image->depth == 16)
764f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
765f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
766fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (((image->depth == 32) || (image->depth == 64)) &&
767fcbcae8c995398624afd038a1b8e327031b11e47cristy            (quantum_info->format != FloatingPointQuantumFormat))
768f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
769f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
770fcbcae8c995398624afd038a1b8e327031b11e47cristy        count=WriteBlob(image,length,pixels);
771fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (count != (ssize_t) length)
772fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
773fcbcae8c995398624afd038a1b8e327031b11e47cristy        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
774fcbcae8c995398624afd038a1b8e327031b11e47cristy          image->rows);
775fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (status == MagickFalse)
776fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
777fcbcae8c995398624afd038a1b8e327031b11e47cristy      }
778fcbcae8c995398624afd038a1b8e327031b11e47cristy      length=GetQuantumExtent(image,quantum_info,GreenQuantum);
779fcbcae8c995398624afd038a1b8e327031b11e47cristy      for (y=(ssize_t) image->rows-1; y >= 0; y--)
780fcbcae8c995398624afd038a1b8e327031b11e47cristy      {
7811e178e70fb3c956f9fc1e30c3ba863e882666465cristy        p=GetVirtualPixels(image,0,y,image->columns,1,exception);
7824c08aed51c5899665ade97263692328eea4af106cristy        if (p == (const Quantum *) NULL)
783fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
7844c08aed51c5899665ade97263692328eea4af106cristy        length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
7851e178e70fb3c956f9fc1e30c3ba863e882666465cristy          GreenQuantum,pixels,exception);
786fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (image->depth == 16)
787f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
788f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
789fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (((image->depth == 32) || (image->depth == 64)) &&
790fcbcae8c995398624afd038a1b8e327031b11e47cristy            (quantum_info->format != FloatingPointQuantumFormat))
791f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
792f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
793fcbcae8c995398624afd038a1b8e327031b11e47cristy        count=WriteBlob(image,length,pixels);
794fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (count != (ssize_t) length)
795fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
796fcbcae8c995398624afd038a1b8e327031b11e47cristy        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
797fcbcae8c995398624afd038a1b8e327031b11e47cristy          image->rows);
798fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (status == MagickFalse)
799fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
800fcbcae8c995398624afd038a1b8e327031b11e47cristy      }
801fcbcae8c995398624afd038a1b8e327031b11e47cristy      length=GetQuantumExtent(image,quantum_info,BlueQuantum);
802fcbcae8c995398624afd038a1b8e327031b11e47cristy      for (y=(ssize_t) image->rows-1; y >= 0; y--)
803fcbcae8c995398624afd038a1b8e327031b11e47cristy      {
8041e178e70fb3c956f9fc1e30c3ba863e882666465cristy        p=GetVirtualPixels(image,0,y,image->columns,1,exception);
8054c08aed51c5899665ade97263692328eea4af106cristy        if (p == (const Quantum *) NULL)
806fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
8074c08aed51c5899665ade97263692328eea4af106cristy        length=ExportQuantumPixels(image,(CacheView *) NULL,quantum_info,
8081e178e70fb3c956f9fc1e30c3ba863e882666465cristy          BlueQuantum,pixels,exception);
809fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (image->depth == 16)
810f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
811f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
812fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (((image->depth == 32) || (image->depth == 64)) &&
813fcbcae8c995398624afd038a1b8e327031b11e47cristy            (quantum_info->format != FloatingPointQuantumFormat))
814f84dc8edf517e117a2c1481d841b37cde852a6e9cristy          SetFITSUnsignedPixels(image->columns,image->depth,image->endian,
815f84dc8edf517e117a2c1481d841b37cde852a6e9cristy            pixels);
816fcbcae8c995398624afd038a1b8e327031b11e47cristy        count=WriteBlob(image,length,pixels);
817fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (count != (ssize_t) length)
818fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
819fcbcae8c995398624afd038a1b8e327031b11e47cristy        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
820fcbcae8c995398624afd038a1b8e327031b11e47cristy          image->rows);
821fcbcae8c995398624afd038a1b8e327031b11e47cristy        if (status == MagickFalse)
822fcbcae8c995398624afd038a1b8e327031b11e47cristy          break;
823fcbcae8c995398624afd038a1b8e327031b11e47cristy      }
824fcbcae8c995398624afd038a1b8e327031b11e47cristy    }
8253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantum_info=DestroyQuantumInfo(quantum_info);
8263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  length=(size_t) (FITSBlocksize-TellBlob(image) % FITSBlocksize);
8273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length != 0)
8283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
8293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) ResetMagickMemory(fits_info,0,length*sizeof(*fits_info));
8303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) WriteBlob(image,length,(unsigned char *) fits_info);
8313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
8323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  fits_info=DestroyString(fits_info);
8333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) CloseBlob(image);
8343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickTrue);
8353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
836