13ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
2ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
4ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
5ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
6ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                     IIIIIIIIII    PPPPPPPP      LL                          %
7ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                         II        PP      PP    LL                          %
8ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                         II        PP       PP   LL                          %
9ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                         II        PP      PP    LL                          %
10ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                         II        PPPPPPPP      LL                          %
11ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                         II        PP            LL                          %
12ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                         II        PP            LL                          %
13ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                     IIIIIIIIII    PP            LLLLLLLL                    %
14ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
15ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
16ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
17ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                   Read/Write Scanalytics IPLab Image Format                 %
18ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                  Sean Burke                                 %
19ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                  2008.05.07                                 %
20ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                     v 0.9                                   %
21ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
227ce65e7125a4e1df1a274ce373c537a9df9c16cdCristy%  Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization      %
23ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  dedicated to making software imaging solutions freely available.           %
24ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
25ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  You may not use this file except in compliance with the License.  You may  %
26ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  obtain a copy of the License at                                            %
27ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
28ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%    http://www.imagemagick.org/script/license.php                            %
29ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
30ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  Unless required by applicable law or agreed to in writing, software        %
31ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  distributed under the License is distributed on an "AS IS" BASIS,          %
32ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
33ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  See the License for the specific language governing permissions and        %
34ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%  limitations under the License.                                             %
35ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%                                                                             %
36ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%
38ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy%
39ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy*/
403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy Include declarations.
433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */
444c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/studio.h"
454c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob.h"
464c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/blob-private.h"
474c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/cache.h"
484c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/colorspace.h"
49510d06a3f7063e91993e13d546d5685048248074cristy#include "MagickCore/colorspace-private.h"
504c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception.h"
514c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/exception-private.h"
524c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image.h"
534c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/image-private.h"
544c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/list.h"
554c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/magick.h"
564c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/memory_.h"
574c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor.h"
584c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/monitor-private.h"
594c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/option.h"
604c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/property.h"
614c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/quantum-private.h"
624c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/static.h"
634c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/string_.h"
644c08aed51c5899665ade97263692328eea4af106cristy#include "MagickCore/module.h"
653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
673ed852eea50f9d4cd633efb8c2b054b8e33c253cristyTyedef declarations
683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */
693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
703ed852eea50f9d4cd633efb8c2b054b8e33c253cristytypedef struct _IPLInfo
713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
72eaedf06777741da32408da72c1e512975c600c48cristy  unsigned int
73eaedf06777741da32408da72c1e512975c600c48cristy    tag,
74eaedf06777741da32408da72c1e512975c600c48cristy    size,
75eaedf06777741da32408da72c1e512975c600c48cristy    time,
76eaedf06777741da32408da72c1e512975c600c48cristy    z,
77eaedf06777741da32408da72c1e512975c600c48cristy    width,
78eaedf06777741da32408da72c1e512975c600c48cristy    height,
79eaedf06777741da32408da72c1e512975c600c48cristy    colors,
80eaedf06777741da32408da72c1e512975c600c48cristy    depth,
81eaedf06777741da32408da72c1e512975c600c48cristy    byteType;
823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy} IPLInfo;
833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
843ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType
851e178e70fb3c956f9fc1e30c3ba863e882666465cristy  WriteIPLImage(const ImageInfo *,Image *,ExceptionInfo *);
863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
8758b6d8309a42cf49008776eca7f0044ee06b0890cristy/*
884189984c711febcbd1a99f01663b62cadee43a5acristystatic void increase (void *pixel, int byteType){
893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch(byteType){
903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 0:(*((unsigned char *) pixel))++; break;
913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 1:(*((signed int *) pixel))++; break;
923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 2:(*((unsigned int *) pixel))++; break;
933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 3:(*((signed long *) pixel))++; break;
943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    default:(*((unsigned int *) pixel))++; break;
953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
9758b6d8309a42cf49008776eca7f0044ee06b0890cristy*/
983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %   I s I P L                                                                 %
1053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  IsIPL() returns MagickTrue if the image format type, identified by the
1113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  magick string, is IPL.
1123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  The format of the IsIPL method is:
1143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %      MagickBooleanType IsIPL(const unsigned char *magick,const size_t length)
1163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  A description of each parameter follows:
1183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %    o magick: compare image format pattern against these bytes.
1203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %    o length: Specifies the length of the magick string.
1223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */
1243ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic MagickBooleanType IsIPL(const unsigned char *magick,const size_t length)
1253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (length < 4)
1273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickFalse);
1283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (LocaleNCompare((const char *) magick,"data",4) == 0)
1293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(MagickTrue);
1303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickFalse);
1313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
1343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %    R e a d I P L I m a g e                                                  %
1393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
1423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  ReadIPLImage() reads a Scanalytics IPLab image file and returns it.  It
1453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  allocates the memory necessary for the new Image structure and returns a
1463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  pointer to the new image.
1473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  According to the IPLab spec, the data is blocked out in five dimensions:
1493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  { t, z, c, y, x }.  When we return the image, the latter three are folded
1503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  into the standard "Image" structure.  The "scenes" (image_info->scene)
1513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  correspond to the order: { {t0,z0}, {t0, z1}, ..., {t1,z0}, {t1,z1}... }
1523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  The number of scenes is t*z.
1533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  The format of the ReadIPLImage method is:
1553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %      Image *ReadIPLImage(const ImageInfo *image_info,ExceptionInfo *exception)
1573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  A description of each parameter follows:
1593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %    o image_info: The image info.
1613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %    o exception: return any errors or warnings in this structure.
1633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
1643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */
1653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1664189984c711febcbd1a99f01663b62cadee43a5acristystatic void SetHeaderFromIPL(Image *image, IPLInfo *ipl){
167c5de69967ea7758f3204962a84c780c82d824ca7cristy  image->columns = ipl->width;
168c5de69967ea7758f3204962a84c780c82d824ca7cristy  image->rows = ipl->height;
169c5de69967ea7758f3204962a84c780c82d824ca7cristy  image->depth = ipl->depth;
1702a11befa48257796843468409d77bb8cfb129cdccristy  image->resolution.x = 1;
1712a11befa48257796843468409d77bb8cfb129cdccristy  image->resolution.y = 1;
1723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
1733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1753ed852eea50f9d4cd633efb8c2b054b8e33c253cristystatic Image *ReadIPLImage(const ImageInfo *image_info,ExceptionInfo *exception)
1763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
1773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
1793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Declare variables
1803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   */
1813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Image *image;
1823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType status;
1844c08aed51c5899665ade97263692328eea4af106cristy  register Quantum *q;
1853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  unsigned char magick[12], *pixels;
1863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ssize_t count;
187bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  ssize_t y;
188bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  size_t t_count=0;
1893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  size_t length;
1903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  IPLInfo
1913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ipl_info;
1923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantumFormatType
1933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    quantum_format;
1943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantumInfo
1953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *quantum_info;
1963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantumType
1973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    quantum_type;
1983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
1993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   Open Image
2013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   */
2023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image_info != (const ImageInfo *) NULL);
204e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image_info->signature == MagickCoreSignature);
2053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ( image_info->debug != MagickFalse)
2063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent, GetMagickModule(), "%s",
2073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                image_info->filename);
2083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(exception != (ExceptionInfo *) NULL);
209e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
2109950d57e1124b73f684fb5946e206994cefda628cristy  image=AcquireImage(image_info,exception);
2113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
2133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
2143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image=DestroyImageList(image);
2153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return((Image *) NULL);
2163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
2173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   Read IPL image
2203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   */
2213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Determine endianness
2243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   If we get back "iiii", we have LSB,"mmmm", MSB
2253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   */
2263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  count=ReadBlob(image,4,magick);
227da16f16767eb31921af855f17bda465fffc4e000cristy  (void) count;
2283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if((LocaleNCompare((char *) magick,"iiii",4) == 0))
2293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image->endian=LSBEndian;
2303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else{
2313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if((LocaleNCompare((char *) magick,"mmmm",4) == 0))
2323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image->endian=MSBEndian;
2333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else{
2343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
2363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
2373ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Skip o'er the next 8 bytes (garbage) */
2383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  count=ReadBlob(image, 8, magick);
2393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
2403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   Excellent, now we read the header unimpeded.
2413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   */
2423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  count=ReadBlob(image,4,magick);
2433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if((LocaleNCompare((char *) magick,"data",4) != 0))
2443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowReaderException(CorruptImageError, "ImproperImageHeader");
2453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.size=ReadBlobLong(image);
2463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.width=ReadBlobLong(image);
2473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.height=ReadBlobLong(image);
2483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if((ipl_info.width == 0UL) || (ipl_info.height == 0UL))
2493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
2503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.colors=ReadBlobLong(image);
251e2c4f18a7274c0c5c6231a2f3d73741a87d583facristy  if(ipl_info.colors == 3){ SetImageColorspace(image,sRGBColorspace,exception);}
2523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else { image->colorspace = GRAYColorspace; }
2533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.z=ReadBlobLong(image);
2543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.time=ReadBlobLong(image);
2553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.byteType=ReadBlobLong(image);
2573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Initialize Quantum Info */
2603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch (ipl_info.byteType) {
2623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 0:
2633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=8;
2643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = UnsignedQuantumFormat;
2653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 1:
2673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=16;
2683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = SignedQuantumFormat;
2693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 2:
2713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=16;
2723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = UnsignedQuantumFormat;
2733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 3:
2753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=32;
2763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = SignedQuantumFormat;
2773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 4: ipl_info.depth=32;
2793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = FloatingPointQuantumFormat;
2803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 5:
2823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=8;
2833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = UnsignedQuantumFormat;
2843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 6:
2863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=16;
2873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = UnsignedQuantumFormat;
2883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    case 10:
2903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=64;
2913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = FloatingPointQuantumFormat;
2923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    default:
2943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.depth=16;
2953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      quantum_format = UnsignedQuantumFormat;
2963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
2973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
2983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
2993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
3003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Set number of scenes of image
3013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
3023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  SetHeaderFromIPL(image, &ipl_info);
3043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Thats all we need if we are pinging. */
3063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image_info->ping != MagickFalse)
307acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    {
308acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy      (void) CloseBlob(image);
309acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy      return(GetFirstImageInList(image));
310acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    }
3113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  length=image->columns;
3123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantum_type=GetQuantumType(image,exception);
3133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy do
3143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  {
3153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    SetHeaderFromIPL(image, &ipl_info);
3163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
317acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    if ((image_info->ping != MagickFalse) && (image_info->number_scenes != 0))
3183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->scene >= (image_info->scene+image_info->number_scenes-1))
3193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
320acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    status=SetImageExtent(image,image->columns,image->rows,exception);
321acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy    if (status == MagickFalse)
322acabb847a592ca5e430c1c0949d03acfc0b78bb9cristy      return(DestroyImageList(image));
3233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
324e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy   printf("Length: %.20g, Memory size: %.20g\n", (double) length,(double)
325e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy     image->depth);
3263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3275f766ef8b0cd9906c2c3a56d845828380a251073cristy     quantum_info=AcquireQuantumInfo(image_info,image);
3283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     if (quantum_info == (QuantumInfo *) NULL)
3293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
3303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     status=SetQuantumFormat(image,quantum_info,quantum_format);
3313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     if (status == MagickFalse)
3323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy       ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
333b3f97ae45019a91b30792a6fa42d81a2689a7025cristy     pixels=(unsigned char *) GetQuantumPixels(quantum_info);
3343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     if(image->columns != ipl_info.width){
3353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
336e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy     printf("Columns not set correctly!  Wanted: %.20g, got: %.20g\n",
337e8c25f9b4c9fb72cad6db08eeda58c7c5784014ecristy       (double) ipl_info.width, (double) image->columns);
3383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy*/
3393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     }
3403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /*
3423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Covert IPL binary to pixel packets
3433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy     */
3443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if(ipl_info.colors == 1){
346bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for(y = 0; y < (ssize_t) image->rows; y++){
3473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) ReadBlob(image, length*image->depth/8, pixels);
3483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
349acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy        if (q == (Quantum *) NULL)
3503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                break;
351c5de69967ea7758f3204962a84c780c82d824ca7cristy        (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GrayQuantum,pixels,exception);
3533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (SyncAuthenticPixels(image,exception) == MagickFalse)
3543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
355c5de69967ea7758f3204962a84c780c82d824ca7cristy    }
3563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
3573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else{
358bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for(y = 0; y < (ssize_t) image->rows; y++){
3593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) ReadBlob(image, length*image->depth/8, pixels);
3603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
361acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy        if (q == (Quantum *) NULL)
3623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                break;
363c5de69967ea7758f3204962a84c780c82d824ca7cristy        (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
364c5de69967ea7758f3204962a84c780c82d824ca7cristy          RedQuantum,pixels,exception);
3653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (SyncAuthenticPixels(image,exception) == MagickFalse)
3663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
3673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
368bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for(y = 0; y < (ssize_t) image->rows; y++){
3693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) ReadBlob(image, length*image->depth/8, pixels);
3703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
371acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy        if (q == (Quantum *) NULL)
372ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy          break;
373c5de69967ea7758f3204962a84c780c82d824ca7cristy        (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          GreenQuantum,pixels,exception);
3753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (SyncAuthenticPixels(image,exception) == MagickFalse)
3763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
3773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
378bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy      for(y = 0; y < (ssize_t) image->rows; y++){
3793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) ReadBlob(image, length*image->depth/8, pixels);
3803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
381acd2ed254c18c254a0ab5aafa06d1645e5d079d8cristy        if (q == (Quantum *) NULL)
382ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy          break;
383c5de69967ea7758f3204962a84c780c82d824ca7cristy        (void) ImportQuantumPixels(image,(CacheView *) NULL,quantum_info,
3843ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          BlueQuantum,pixels,exception);
3853ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        if (SyncAuthenticPixels(image,exception) == MagickFalse)
3863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          break;
3873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
3883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   }
3893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   SetQuantumImageType(image,quantum_type);
3903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    t_count++;
3923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantum_info = DestroyQuantumInfo(quantum_info);
3933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
3943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if (EOFBlob(image) != MagickFalse)
3953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
3963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ThrowFileException(exception,CorruptImageError,"UnexpectedEndOfFile",
3973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy                 image->filename);
3983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
3993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   if(t_count < ipl_info.z * ipl_info.time){
4013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
4023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy       Proceed to next image.
4033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy       */
4049950d57e1124b73f684fb5946e206994cefda628cristy      AcquireNextImage(image_info,image,exception);
4053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (GetNextImageInList(image) == (Image *) NULL)
4063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      {
4073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        image=DestroyImageList(image);
4083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        return((Image *) NULL);
4093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      }
4103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image=SyncNextImageInList(image);
4113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=SetImageProgress(image,LoadImagesTag,TellBlob(image),
4123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetBlobSize(image));
4133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (status == MagickFalse)
4143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
4153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
4163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  } while (t_count < ipl_info.z*ipl_info.time);
4173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  CloseBlob(image);
4183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(GetFirstImageInList(image));
4193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4213ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
4223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4243ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4253ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %   R e g i s t e r I P L I m a g e                                           %
4273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
4323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy % RegisterIPLImage() add attributes for the Scanalytics IPL image format to the
4333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy % list of supported formats.
4343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
4353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
4363ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */
437bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristyModuleExport size_t RegisterIPLImage(void)
4383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickInfo
4403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *entry;
4413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
44206b627a07ff44e1ff93ef1288c9f428066ded10ddirk  entry=AcquireMagickInfo("IPL","IPL","IPL Image Sequence");
4433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->decoder=(DecodeImageHandler *) ReadIPLImage;
4443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->encoder=(EncodeImageHandler *) WriteIPLImage;
4453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  entry->magick=(IsImageFormatHandler *) IsIPL;
44608e9a113db499034abb5ad8d59b42f8eca3c641cdirk  entry->flags|=CoderEndianSupportFlag;
4473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) RegisterMagickInfo(entry);
4483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  return(MagickImageCoderSignature);
4493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
4523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %   U n r e g i s t e r I P L I m a g e                                       %
4573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %                                                                             %
4603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
4623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  UnregisterIPLImage() removes format registrations made by the
4633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  IPL module from the list of supported formats.
4643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
4653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %  The format of the UnregisterIPLImage method is:
4663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
4673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %      UnregisterIPLImage(void)
4683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy %
4693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy */
4703ed852eea50f9d4cd633efb8c2b054b8e33c253cristyModuleExport void UnregisterIPLImage(void)
4713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
4723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) UnregisterMagickInfo("IPL");
4733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
4743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
4753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy/*
4761e178e70fb3c956f9fc1e30c3ba863e882666465cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4771e178e70fb3c956f9fc1e30c3ba863e882666465cristy%                                                                             %
4781e178e70fb3c956f9fc1e30c3ba863e882666465cristy%                                                                             %
4791e178e70fb3c956f9fc1e30c3ba863e882666465cristy%                                                                             %
4801e178e70fb3c956f9fc1e30c3ba863e882666465cristy%   W r i t e I P L I m a g e                                                 %
4811e178e70fb3c956f9fc1e30c3ba863e882666465cristy%                                                                             %
4821e178e70fb3c956f9fc1e30c3ba863e882666465cristy%                                                                             %
4831e178e70fb3c956f9fc1e30c3ba863e882666465cristy%                                                                             %
4841e178e70fb3c956f9fc1e30c3ba863e882666465cristy%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4851e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
4861e178e70fb3c956f9fc1e30c3ba863e882666465cristy%  WriteIPLImage() writes an image to a file in Scanalytics IPLabimage format.
4871e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
4881e178e70fb3c956f9fc1e30c3ba863e882666465cristy%  The format of the WriteIPLImage method is:
4891e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
4901e178e70fb3c956f9fc1e30c3ba863e882666465cristy%      MagickBooleanType WriteIPLImage(const ImageInfo *image_info,Image *image)
4911e178e70fb3c956f9fc1e30c3ba863e882666465cristy%       Image *image,ExceptionInfo *exception)
4921e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
4931e178e70fb3c956f9fc1e30c3ba863e882666465cristy%  A description of each parameter follows.
4941e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
4951e178e70fb3c956f9fc1e30c3ba863e882666465cristy%    o image_info: The image info.
4961e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
4971e178e70fb3c956f9fc1e30c3ba863e882666465cristy%    o image:  The image.
4981e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
4991e178e70fb3c956f9fc1e30c3ba863e882666465cristy%    o exception: return any errors or warnings in this structure.
5001e178e70fb3c956f9fc1e30c3ba863e882666465cristy%
5011e178e70fb3c956f9fc1e30c3ba863e882666465cristy*/
5021e178e70fb3c956f9fc1e30c3ba863e882666465cristystatic MagickBooleanType WriteIPLImage(const ImageInfo *image_info,Image *image,
5031e178e70fb3c956f9fc1e30c3ba863e882666465cristy  ExceptionInfo *exception)
5043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy{
505ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy  IPLInfo
506ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy    ipl_info;
507ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy
5083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickBooleanType
5093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    status;
5103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  MagickOffsetType
5123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    scene;
5133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5144c08aed51c5899665ade97263692328eea4af106cristy  register const Quantum
5153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *p;
5163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  QuantumInfo
5183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    *quantum_info;
5193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
520ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy  ssize_t
521ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy    y;
522ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy
523ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy  unsigned char
524ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy    *pixels;
525ebc891a1d9621a19c509200d7bf3470ca18dde7fcristy
5263ed852eea50f9d4cd633efb8c2b054b8e33c253cristy   /*
5273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Open output image file.
5283ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5293ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image_info != (const ImageInfo *) NULL);
530e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image_info->signature == MagickCoreSignature);
5313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  assert(image != (Image *) NULL);
532e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(image->signature == MagickCoreSignature);
5333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (image->debug != MagickFalse)
5343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
5353a37efd7ece979e9c63dc8f2f2d3816bab8b1156cristy  assert(exception != (ExceptionInfo *) NULL);
536e1c94d9d25db6b0dd7a5028ffee31d1057855d73cristy  assert(exception->signature == MagickCoreSignature);
5371e178e70fb3c956f9fc1e30c3ba863e882666465cristy  status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
5383ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if (status == MagickFalse)
5393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    return(status);
5403ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  scene=0;
5413ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5435f766ef8b0cd9906c2c3a56d845828380a251073cristy  quantum_info=AcquireQuantumInfo(image_info,image);
5443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if ((quantum_info->format == UndefinedQuantumFormat) &&
5451e178e70fb3c956f9fc1e30c3ba863e882666465cristy      (IsHighDynamicRangeImage(image,exception) != MagickFalse))
5463ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    SetQuantumFormat(image,quantum_info,FloatingPointQuantumFormat);
5473ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  switch(quantum_info->depth){
5483ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  case 8:
5493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ipl_info.byteType = 0;
5503ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    break;
5513ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  case 16:
5523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if(quantum_info->format == SignedQuantumFormat){
5533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.byteType = 2;
5543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5553ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else{
5563ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.byteType = 1;
5573ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    break;
5593ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  case 32:
5603ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    if(quantum_info->format == FloatingPointQuantumFormat){
5613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.byteType = 3;
5623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    else{
5643ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      ipl_info.byteType = 4;
5653ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
5663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    break;
5673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  case 64:
5683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ipl_info.byteType = 10;
5693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    break;
5703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  default:
5713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    ipl_info.byteType = 2;
5723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    break;
5733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
5750b29b25525c4612c77b1b3c8abcc40685d0aa33fcristy  ipl_info.z = (unsigned int) GetImageListLength(image);
5763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* There is no current method for detecting whether we have T or Z stacks */
5773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  ipl_info.time = 1;
5780b29b25525c4612c77b1b3c8abcc40685d0aa33fcristy  ipl_info.width = (unsigned int) image->columns;
5790b29b25525c4612c77b1b3c8abcc40685d0aa33fcristy  ipl_info.height = (unsigned int) image->rows;
580af8d391906d11f0a1f2bbf4e2adbc4995c852d33cristy  (void) TransformImageColorspace(image,sRGBColorspace,exception);
581cd8b331760407523f2a59cc65c1cd9c3d4422bafcristy  if(IssRGBCompatibleColorspace(image->colorspace) != MagickFalse) { ipl_info.colors = 3; }
5823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else{ ipl_info.colors = 1; }
5833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5840b29b25525c4612c77b1b3c8abcc40685d0aa33fcristy  ipl_info.size = (unsigned int) (28 +
5850b29b25525c4612c77b1b3c8abcc40685d0aa33fcristy    ((image->depth)/8)*ipl_info.height*ipl_info.width*ipl_info.colors*ipl_info.z);
5863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5873ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Ok!  Calculations are done.  Lets write this puppy down! */
5883ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5893ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /*
5903ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    Write IPL header.
5913ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  */
5923ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Shockingly (maybe not if you have used IPLab),  IPLab itself CANNOT read MSBEndian
5933ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  files!   The reader above can, but they cannot.  For compatability reasons, I will leave
5943ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  the code in here, but it is all but useless if you want to use IPLab. */
5953ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
5963ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if(image_info->endian == MSBEndian)
5973ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) WriteBlob(image, 4, (const unsigned char *) "mmmm");
5983ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else{
5993ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    image->endian = LSBEndian;
6003ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    (void) WriteBlob(image, 4, (const unsigned char *) "iiii");
6013ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
6023ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, 4);
6033ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlob(image, 4, (const unsigned char *) "100f");
6043ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlob(image, 4, (const unsigned char *) "data");
6053ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, ipl_info.size);
6063ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, ipl_info.width);
6073ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, ipl_info.height);
6083ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, ipl_info.colors);
6093ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if(image_info->adjoin == MagickFalse)
6103ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, 1);
6113ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  else
6123ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, ipl_info.z);
6133ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, ipl_info.time);
6143ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, ipl_info.byteType);
6153ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6163ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  do
6173ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    {
6183ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      /*
6193ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  Convert MIFF to IPL raster pixels.
6203ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      */
621b3f97ae45019a91b30792a6fa42d81a2689a7025cristy      pixels=(unsigned char *) GetQuantumPixels(quantum_info);
6223ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if(ipl_info.colors == 1){
6233ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Red frame */
624bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for(y = 0; y < (ssize_t) ipl_info.height; y++){
6254c08aed51c5899665ade97263692328eea4af106cristy    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
6264c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
6273ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6284c08aed51c5899665ade97263692328eea4af106cristy      (void) ExportQuantumPixels(image,(CacheView *) NULL, quantum_info,
6291e178e70fb3c956f9fc1e30c3ba863e882666465cristy        GrayQuantum, pixels,exception);
6303ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) WriteBlob(image, image->columns*image->depth/8, pixels);
6313ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
6323ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6333ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
6343ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  if(ipl_info.colors == 3){
6353ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  /* Red frame */
636bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy  for(y = 0; y < (ssize_t) ipl_info.height; y++){
6374c08aed51c5899665ade97263692328eea4af106cristy    p=GetVirtualPixels(image,0,y,image->columns,1,exception);
6384c08aed51c5899665ade97263692328eea4af106cristy    if (p == (const Quantum *) NULL)
6393ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      break;
6404c08aed51c5899665ade97263692328eea4af106cristy      (void) ExportQuantumPixels(image,(CacheView *) NULL, quantum_info,
6411e178e70fb3c956f9fc1e30c3ba863e882666465cristy        RedQuantum, pixels,exception);
6423ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) WriteBlob(image, image->columns*image->depth/8, pixels);
6433ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
6443ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6453ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* Green frame */
646bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for(y = 0; y < (ssize_t) ipl_info.height; y++){
6471e178e70fb3c956f9fc1e30c3ba863e882666465cristy      p=GetVirtualPixels(image,0,y,image->columns,1,exception);
6484c08aed51c5899665ade97263692328eea4af106cristy      if (p == (const Quantum *) NULL)
6493ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
6504c08aed51c5899665ade97263692328eea4af106cristy        (void) ExportQuantumPixels(image,(CacheView *) NULL, quantum_info,
6511e178e70fb3c956f9fc1e30c3ba863e882666465cristy          GreenQuantum, pixels,exception);
6523ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        (void) WriteBlob(image, image->columns*image->depth/8, pixels);
6533ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6543ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    /* Blue frame */
655bb50337b2a8a16ca7e903cc04ab195ff0fd47ae6cristy    for(y = 0; y < (ssize_t) ipl_info.height; y++){
6561e178e70fb3c956f9fc1e30c3ba863e882666465cristy      p=GetVirtualPixels(image,0,y,image->columns,1,exception);
6574c08aed51c5899665ade97263692328eea4af106cristy      if (p == (const Quantum *) NULL)
6583ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
6594c08aed51c5899665ade97263692328eea4af106cristy      (void) ExportQuantumPixels(image,(CacheView *) NULL, quantum_info,
6601e178e70fb3c956f9fc1e30c3ba863e882666465cristy        BlueQuantum, pixels,exception);
6613ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      (void) WriteBlob(image, image->columns*image->depth/8, pixels);
6623ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (image->previous == (Image *) NULL)
6633ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        {
664cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy          status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
665cee9711bbc334b5677d5ec4ea1cc70340d35ee35cristy                image->rows);
6663ed852eea50f9d4cd633efb8c2b054b8e33c253cristy          if (status == MagickFalse)
6673ed852eea50f9d4cd633efb8c2b054b8e33c253cristy            break;
6683ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        }
6693ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }
6703ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  }
6713ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  quantum_info=DestroyQuantumInfo(quantum_info);
6723ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (GetNextImageInList(image) == (Image *) NULL)
6733ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  break;
6743ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      image=SyncNextImageInList(image);
6753ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      status=SetImageProgress(image,SaveImagesTag,scene++,
6763ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        GetImageListLength(image));
6773ed852eea50f9d4cd633efb8c2b054b8e33c253cristy      if (status == MagickFalse)
6783ed852eea50f9d4cd633efb8c2b054b8e33c253cristy        break;
6793ed852eea50f9d4cd633efb8c2b054b8e33c253cristy    }while (image_info->adjoin != MagickFalse);
6803ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6813ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlob(image, 4, (const unsigned char *) "fini");
6823ed852eea50f9d4cd633efb8c2b054b8e33c253cristy  (void) WriteBlobLong(image, 0);
6833ed852eea50f9d4cd633efb8c2b054b8e33c253cristy
6843ed852eea50f9d4cd633efb8c2b054b8e33c253cristyCloseBlob(image);
6853ed852eea50f9d4cd633efb8c2b054b8e33c253cristyreturn(MagickTrue);
6863ed852eea50f9d4cd633efb8c2b054b8e33c253cristy}
687