home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / ImageMagick / magick / image.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  149.7 KB  |  5,551 lines

  1. /*
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. %                                                                             %
  4. %                                                                             %
  5. %                                                                             %
  6. %                       IIIII  M   M   AAA   GGGG  EEEEE                      %
  7. %                         I    MM MM  A   A G      E                          %
  8. %                         I    M M M  AAAAA G  GG  EEE                        %
  9. %                         I    M   M  A   A G   G  E                          %
  10. %                       IIIII  M   M  A   A  GGGG  EEEEE                      %
  11. %                                                                             %
  12. %                                                                             %
  13. %                          ImageMagick Image Routines                         %
  14. %                                                                             %
  15. %                                                                             %
  16. %                                                                             %
  17. %                               Software Design                               %
  18. %                                 John Cristy                                 %
  19. %                                  July 1992                                  %
  20. %                                                                             %
  21. %                                                                             %
  22. %  Copyright 1994 E. I. du Pont de Nemours & Company                          %
  23. %                                                                             %
  24. %  Permission to use, copy, modify, distribute, and sell this software and    %
  25. %  its documentation for any purpose is hereby granted without fee,           %
  26. %  provided that the above Copyright notice appear in all copies and that     %
  27. %  both that Copyright notice and this permission notice appear in            %
  28. %  supporting documentation, and that the name of E. I. du Pont de Nemours    %
  29. %  & Company not be used in advertising or publicity pertaining to            %
  30. %  distribution of the software without specific, written prior               %
  31. %  permission.  E. I. du Pont de Nemours & Company makes no representations   %
  32. %  about the suitability of this software for any purpose.  It is provided    %
  33. %  "as is" without express or implied warranty.                               %
  34. %                                                                             %
  35. %  E. I. du Pont de Nemours & Company disclaims all warranties with regard    %
  36. %  to this software, including all implied warranties of merchantability      %
  37. %  and fitness, in no event shall E. I. du Pont de Nemours & Company be       %
  38. %  liable for any special, indirect or consequential damages or any           %
  39. %  damages whatsoever resulting from loss of use, data or profits, whether    %
  40. %  in an action of contract, negligence or other tortuous action, arising     %
  41. %  out of or in connection with the use or performance of this software.      %
  42. %                                                                             %
  43. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  44. %
  45. %
  46. %
  47. */
  48.  
  49. /*
  50.   Include declarations.
  51. */
  52. #include "magick.h"
  53. #include "image.h"
  54. #include "compress.h"
  55. #include "utility.h"
  56. #include "X.h"
  57.  
  58. /*
  59.   Forward declarations.
  60. */
  61. static Image
  62.   *ZoomImage _Declare((Image *));
  63.  
  64. /*
  65. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  66. %                                                                             %
  67. %                                                                             %
  68. %                                                                             %
  69. %   A l l o c a t e I m a g e                                                 %
  70. %                                                                             %
  71. %                                                                             %
  72. %                                                                             %
  73. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  74. %
  75. %  Function AllocateImage allocates an Image structure and initializes each
  76. %  field to a default value.
  77. %
  78. %  The format of the AllocateImage routine is:
  79. %
  80. %      allocated_image=AllocateImage(image_info)
  81. %
  82. %  A description of each parameter follows:
  83. %
  84. %    o allocated_image: Function AllocateImage returns a pointer to an image
  85. %      structure initialized to default values.  A null image is returned if
  86. %      there is a memory shortage.
  87. %
  88. %    o image_info: Specifies a pointer to a ImageInfo structure.
  89. %
  90. %
  91. */
  92. Image *AllocateImage(image_info)
  93. ImageInfo
  94.   *image_info;
  95. {
  96.   Image
  97.     *allocated_image;
  98.  
  99.   /*
  100.     Allocate image structure.
  101.   */
  102.   allocated_image=(Image *) malloc(sizeof(Image));
  103.   if (allocated_image == (Image *) NULL)
  104.     {
  105.       Warning("Unable to allocate image","Memory allocation failed");
  106.       return((Image *) NULL);
  107.     }
  108.   /*
  109.     Initialize Image structure.
  110.   */
  111.   allocated_image->file=(FILE *) NULL;
  112.   allocated_image->status=False;
  113.   *allocated_image->filename='\0';
  114.   allocated_image->pipe=False;
  115.   (void) strcpy(allocated_image->magick,"MIFF");
  116.   allocated_image->comments=(char *) NULL;
  117.   allocated_image->label=(char *) NULL;
  118.   allocated_image->id=UndefinedId;
  119.   allocated_image->class=DirectClass;
  120.   allocated_image->alpha=False;
  121.   allocated_image->compression=RunlengthEncodedCompression;
  122.   allocated_image->columns=0;
  123.   allocated_image->rows=0;
  124.   allocated_image->colors=0;
  125.   allocated_image->scene=0;
  126.   allocated_image->montage=(char *) NULL;
  127.   allocated_image->directory=(char *) NULL;
  128.   allocated_image->colormap=(ColorPacket *) NULL;
  129.   allocated_image->signature=(char *) NULL;
  130.   allocated_image->pixels=(RunlengthPacket *) NULL;
  131.   allocated_image->packet=(RunlengthPacket *) NULL;
  132.   allocated_image->packets=0;
  133.   allocated_image->packet_size=0;
  134.   allocated_image->packed_pixels=(unsigned char *) NULL;
  135.   allocated_image->orphan=False;
  136.   allocated_image->previous=(Image *) NULL;
  137.   allocated_image->next=(Image *) NULL;
  138.   if (image_info != (ImageInfo *) NULL)
  139.     {
  140.       if (image_info->filename != (char *) NULL)
  141.         (void) strcpy(allocated_image->filename,image_info->filename);
  142.       if (image_info->magick != (char *) NULL)
  143.         if (strlen(image_info->magick) < sizeof(allocated_image->magick))
  144.           (void) strcpy(allocated_image->magick,image_info->magick);
  145.     }
  146.   return(allocated_image);
  147. }
  148.  
  149. /*
  150. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  151. %                                                                             %
  152. %                                                                             %
  153. %                                                                             %
  154. %   B o r d e r I m a g e                                                     %
  155. %                                                                             %
  156. %                                                                             %
  157. %                                                                             %
  158. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  159. %
  160. %  Function BorderImage takes an image and puts a border around it of a
  161. %  particular color.  It allocates the memory necessary for the new Image
  162. %  structure and returns a pointer to the new image.  Set the border and
  163. %  highlight to the same color to get a solid border.
  164. %
  165. %  The format of the BorderImage routine is:
  166. %
  167. %      bordered_image=BorderImage(image,border_info,shadow_color,
  168. %        highlight_color)
  169. %
  170. %  A description of each parameter follows:
  171. %
  172. %    o bordered_image: Function BorderImage returns a pointer to the bordered
  173. %      image.  A null image is returned if there is a a memory shortage.
  174. %
  175. %    o image: The address of a structure of type Image.
  176. %
  177. %    o border_info: Specifies a pointer to a XRectangle which defines the
  178. %      border region.
  179. %
  180. %    o shadow_color: A pointer to a ColorPacket which contains the red,
  181. %      green, and blue components of the border color.
  182. %
  183. %    o highlight_color: A pointer to a ColorPacket which contains the red,
  184. %      green, and blue components of the highlight color.
  185. %
  186. %
  187. */
  188. Image *BorderImage(image,border_info,shadow_color,highlight_color)
  189. Image
  190.   *image;
  191.  
  192. RectangleInfo
  193.   *border_info;
  194.  
  195. ColorPacket
  196.   *shadow_color,
  197.   *highlight_color;
  198. {
  199.   Image
  200.     *bordered_image;
  201.  
  202.   register int
  203.     x,
  204.     y;
  205.  
  206.   register RunlengthPacket
  207.     *p,
  208.     *q;
  209.  
  210.   RunlengthPacket
  211.     highlight,
  212.     shadow;
  213.  
  214.   /*
  215.     Check border geometry.
  216.   */
  217.   if ((((int) border_info->width-border_info->x) < image->columns) ||
  218.       (((int) border_info->height-border_info->y) < image->rows))
  219.     {
  220.       Warning("Unable to border image","border is less than image size");
  221.       return((Image *) NULL);
  222.     }
  223.   /*
  224.     Initialize bordered image attributes.
  225.   */
  226.   bordered_image=CopyImage(image,border_info->width,border_info->height,False);
  227.   if (bordered_image == (Image *) NULL)
  228.     {
  229.       Warning("Unable to border image","Memory allocation failed");
  230.       return((Image *) NULL);
  231.     }
  232.   /*
  233.     Initialize border colors.
  234.   */
  235.   shadow.red=shadow_color->red;
  236.   shadow.green=shadow_color->green;
  237.   shadow.blue=shadow_color->blue;
  238.   shadow.index=shadow_color->index;
  239.   shadow.length=0;
  240.   highlight.red=highlight_color->red;
  241.   highlight.green=highlight_color->green;
  242.   highlight.blue=highlight_color->blue;
  243.   highlight.index=highlight_color->index;
  244.   highlight.length=0;
  245.   /*
  246.     Copy image and put border around it.
  247.   */
  248.   q=bordered_image->pixels;
  249.   for (y=0; y < border_info->y; y++)
  250.   {
  251.     for (x=0; x < (bordered_image->columns-y); x++)
  252.       *q++=highlight;
  253.     for ( ; x < bordered_image->columns; x++)
  254.       *q++=shadow;
  255.   }
  256.   p=image->pixels;
  257.   image->runlength=p->length+1;
  258.   for (y=0; y < image->rows; y++)
  259.   {
  260.     /*
  261.       Initialize scanline with border color.
  262.     */
  263.     for (x=0; x < border_info->x; x++)
  264.       *q++=highlight;
  265.     /*
  266.       Transfer scanline.
  267.     */
  268.     for (x=0; x < image->columns; x++)
  269.     {
  270.       if (image->runlength != 0)
  271.         image->runlength--;
  272.       else
  273.         {
  274.           p++;
  275.           image->runlength=p->length;
  276.         }
  277.       *q=(*p);
  278.       q->length=0;
  279.       q++;
  280.     }
  281.     for (x=0; x < (border_info->width-image->columns-border_info->x); x++)
  282.       *q++=shadow;
  283.   }
  284.   for (y=(border_info->height-image->rows-border_info->y-1); y >= 0; y--)
  285.   {
  286.     for (x=0; x < y; x++)
  287.       *q++=highlight;
  288.     for ( ; x < bordered_image->columns; x++)
  289.       *q++=shadow;
  290.   }
  291.   return(bordered_image);
  292. }
  293.  
  294. /*
  295. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  296. %                                                                             %
  297. %                                                                             %
  298. %                                                                             %
  299. %   C l i p I m a g e                                                         %
  300. %                                                                             %
  301. %                                                                             %
  302. %                                                                             %
  303. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  304. %
  305. %  Function ClipImage creates a new image that is a subregion of an existing
  306. %  one.  It allocates the memory necessary for the new Image structure and
  307. %  returns a pointer to the new image.  The pixels are copied from the source
  308. %  image as defined by the region formed from x_offset, y_offset, width, and
  309. %  height.
  310. %
  311. %  The format of the ClipImage routine is:
  312. %
  313. %      clipped_image=ClipImage(image,clip_info)
  314. %
  315. %  A description of each parameter follows:
  316. %
  317. %    o clipped_image: Function ClipImage returns a pointer to the clipped
  318. %      image.  A null image is returned if there is a a memory shortage or
  319. %      if the image width or height is zero.
  320. %
  321. %    o image: The address of a structure of type Image.
  322. %
  323. %    o clip_info: Specifies a pointer to a RectangleInfo which defines the
  324. %      region of the image to crop.
  325. %
  326. %
  327. */
  328. Image *ClipImage(image,clip_info)
  329. Image
  330.   *image;
  331.  
  332. RectangleInfo
  333.   *clip_info;
  334. {
  335.   Image
  336.     *clipped_image;
  337.  
  338.   register int
  339.     x,
  340.     y;
  341.  
  342.   register RunlengthPacket
  343.     *p,
  344.     *q;
  345.  
  346.   RunlengthPacket
  347.     background;
  348.  
  349.   /*
  350.     Check clip geometry.
  351.   */
  352.   if (((clip_info->x+(int) clip_info->width) < 0) ||
  353.       ((clip_info->y+(int) clip_info->height) < 0) ||
  354.       (clip_info->x > (int) image->columns) ||
  355.       (clip_info->y > (int) image->rows))
  356.     {
  357.       Warning("Unable to clip image","geometry does not contain image");
  358.       return((Image *) NULL);
  359.     }
  360.   if ((clip_info->x+(int) clip_info->width) > (int) image->columns)
  361.     clip_info->width=(unsigned int) ((int) image->columns-clip_info->x);
  362.   if ((clip_info->y+(int) clip_info->height) > (int) image->rows)
  363.     clip_info->height=(unsigned int) ((int) image->rows-clip_info->y);
  364.   if (clip_info->x < 0)
  365.     {
  366.       clip_info->width-=(unsigned int) (-clip_info->x);
  367.       clip_info->x=0;
  368.     }
  369.   if (clip_info->y < 0)
  370.     {
  371.       clip_info->height-=(unsigned int) (-clip_info->y);
  372.       clip_info->y=0;
  373.     }
  374.   if ((clip_info->width == 0) && (clip_info->height == 0))
  375.     {
  376.       /*
  377.         Remove vertical edges that are the background color.
  378.       */
  379.       if (!UncompressImage(image))
  380.         return((Image *) NULL);
  381.       clip_info->width=image->columns;
  382.       background=image->pixels[0];
  383.       for (x=0; x < image->columns; x++)
  384.       {
  385.         p=image->pixels+x;
  386.         for (y=0; y < image->rows; y++)
  387.         {
  388.           if ((p->red != background.red) || (p->green != background.green) ||
  389.               (p->blue != background.blue))
  390.             break;
  391.           p+=image->columns;
  392.         }
  393.         if (y < image->rows)
  394.           break;
  395.       }
  396.       clip_info->x=x;
  397.       if (clip_info->x == (int) image->columns)
  398.         {
  399.           Warning("Unable to clip image","geometry does not contain image");
  400.           return((Image *) NULL);
  401.         }
  402.       for (x=image->columns-1; x > 0; x--)
  403.       {
  404.         p=image->pixels+x;
  405.         for (y=0; y < image->rows; y++)
  406.         {
  407.           if ((p->red != background.red) || (p->green != background.green) ||
  408.               (p->blue != background.blue))
  409.             break;
  410.           p+=image->columns;
  411.         }
  412.         if (y < image->rows)
  413.           break;
  414.       }
  415.       clip_info->width=x-clip_info->x+1;
  416.       /*
  417.         Remove horizonal edges that are the background color.
  418.       */
  419.       clip_info->height=image->rows;
  420.       p=image->pixels;
  421.       background=(*p);
  422.       for (y=0; y < image->rows; y++)
  423.       {
  424.         for (x=0; x < image->columns; x++)
  425.         {
  426.           if ((p->red != background.red) || (p->green != background.green) ||
  427.               (p->blue != background.blue))
  428.             break;
  429.           p++;
  430.         }
  431.         if (x < image->columns)
  432.           break;
  433.       }
  434.       clip_info->y=y;
  435.       p=image->pixels+(image->columns*image->rows)-1;
  436.       for (y=image->rows-1; y > 0; y--)
  437.       {
  438.         for (x=0; x < image->columns; x++)
  439.         {
  440.           if ((p->red != background.red) || (p->green != background.green) ||
  441.               (p->blue != background.blue))
  442.             break;
  443.           p--;
  444.         }
  445.         if (x < image->columns)
  446.           break;
  447.       }
  448.       clip_info->height=y-clip_info->y+1;
  449.     }
  450.   /*
  451.     Initialize clipped image attributes.
  452.   */
  453.   clipped_image=CopyImage(image,clip_info->width,clip_info->height,False);
  454.   if (clipped_image == (Image *) NULL)
  455.     {
  456.       Warning("Unable to clip image","Memory allocation failed");
  457.       return((Image *) NULL);
  458.     }
  459.   /*
  460.     Skip pixels up to the clipped image.
  461.   */
  462.   p=image->pixels;
  463.   image->runlength=p->length+1;
  464.   for (x=0; x < (clip_info->y*image->columns+clip_info->x); x++)
  465.     if (image->runlength != 0)
  466.       image->runlength--;
  467.     else
  468.       {
  469.         p++;
  470.         image->runlength=p->length;
  471.       }
  472.   /*
  473.     Extract clipped image.
  474.   */
  475.   q=clipped_image->pixels;
  476.   for (y=0; y < (clipped_image->rows-1); y++)
  477.   {
  478.     /*
  479.       Transfer scanline.
  480.     */
  481.     for (x=0; x < clipped_image->columns; x++)
  482.     {
  483.       if (image->runlength != 0)
  484.         image->runlength--;
  485.       else
  486.         {
  487.           p++;
  488.           image->runlength=p->length;
  489.         }
  490.       *q=(*p);
  491.       q->length=0;
  492.       q++;
  493.     }
  494.     /*
  495.       Skip to next scanline.
  496.     */
  497.     for (x=0; x < (image->columns-clipped_image->columns); x++)
  498.       if (image->runlength != 0)
  499.         image->runlength--;
  500.       else
  501.         {
  502.           p++;
  503.           image->runlength=p->length;
  504.         }
  505.   }
  506.   /*
  507.     Transfer last scanline.
  508.   */
  509.   for (x=0; x < clipped_image->columns; x++)
  510.   {
  511.     if (image->runlength != 0)
  512.       image->runlength--;
  513.     else
  514.       {
  515.         p++;
  516.         image->runlength=p->length;
  517.       }
  518.     *q=(*p);
  519.     q->length=0;
  520.     q++;
  521.   }
  522.   return(clipped_image);
  523. }
  524.  
  525. /*
  526. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  527. %                                                                             %
  528. %                                                                             %
  529. %                                                                             %
  530. %   C l o s e I m a g e                                                       %
  531. %                                                                             %
  532. %                                                                             %
  533. %                                                                             %
  534. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  535. %
  536. %  Function CloseImage closes a file associated with the image.  If the
  537. %  filename prefix is '|', the file is a pipe and is closed with pclose.
  538. %
  539. %  The format of the CloseImage routine is:
  540. %
  541. %      CloseImage(image)
  542. %
  543. %  A description of each parameter follows:
  544. %
  545. %    o image: The address of a structure of type Image.
  546. %
  547. %
  548. */
  549. void CloseImage(image)
  550. Image
  551.   *image;
  552. {
  553.   /*
  554.     Close image file.
  555.   */
  556.   if (image->file == (FILE *) NULL)
  557.     return;
  558.   image->status=ferror(image->file);
  559.   if (image->pipe)
  560.     (void) pclose(image->file);
  561.   else
  562.     if ((image->file != stdin) && (image->file != stdout))
  563.       (void) fclose(image->file);
  564.   image->file=(FILE *) NULL;
  565. }
  566.  
  567. /*
  568. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  569. %                                                                             %
  570. %                                                                             %
  571. %                                                                             %
  572. %   C o m m e n t I m a g e                                                   %
  573. %                                                                             %
  574. %                                                                             %
  575. %                                                                             %
  576. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  577. %
  578. %  Function CommentImage initializes an image comment.  Optionally the
  579. %  comment can include the image filename, type, width, height, or scene
  580. %  number by embedding special format characters.  Embed %f for filename,
  581. %  %m for magick, %w for width, %h for height, %s for scene number, or \n
  582. %  for newline.  For example,
  583. %
  584. %     %f  %wx%h
  585. %
  586. %  produces an image comment of
  587. %
  588. %     bird.miff  512x480
  589. %
  590. %  for an image titled bird.miff and whose width is 512 and height is 480.
  591. %
  592. %  The format of the CommentImage routine is:
  593. %
  594. %      CommentImage(image,comment)
  595. %
  596. %  A description of each parameter follows:
  597. %
  598. %    o image: The address of a structure of type Image.
  599. %
  600. %    o comment: The address of a character string containing the comment format.
  601. %
  602. %
  603. */
  604. void CommentImage(image,comment)
  605. Image
  606.   *image;
  607.  
  608. char
  609.   *comment;
  610. {
  611.   register char
  612.     *p,
  613.     *q;
  614.  
  615.   unsigned int
  616.     length;
  617.  
  618.   if (image->comments != (char *) NULL)
  619.     (void) free((char *) image->comments);
  620.   image->comments=(char *) NULL;
  621.   if (comment == (char *) NULL)
  622.     return;
  623.   if (*comment == '@')
  624.     {
  625.       FILE
  626.         *file;
  627.  
  628.       int
  629.         c;
  630.  
  631.       /*
  632.         Read comment from a file.
  633.       */
  634.       file=(FILE *) fopen(comment+1,"r");
  635.       if (file == (FILE *) NULL)
  636.         {
  637.           Warning("Unable to read comment file",comment+1);
  638.           return;
  639.         }
  640.       length=MaxTextLength;
  641.       comment=(char *) malloc(length*sizeof(char));
  642.       for (q=comment ; comment != (char *) NULL; q++)
  643.       {
  644.         c=fgetc(file);
  645.         if (c == EOF)
  646.           break;
  647.         if ((q-comment+1) >= length)
  648.           {
  649.             length<<=1;
  650.             comment=(char *) realloc((char *) comment,length*sizeof(char));
  651.             if (comment == (char *) NULL)
  652.               break;
  653.             q=comment+strlen(comment);
  654.           }
  655.         *q=(unsigned char) c;
  656.       }
  657.       (void) fclose(file);
  658.       if (comment == (char *) NULL)
  659.         {
  660.           Warning("Unable to comment image","Memory allocation failed");
  661.           return;
  662.         }
  663.       *q='\0';
  664.     }
  665.   /*
  666.     Allocate and initialize image comment.
  667.   */
  668.   p=comment;
  669.   length=strlen(comment)+MaxTextLength;
  670.   image->comments=(char *) malloc(length*sizeof(char));
  671.   for (q=image->comments; image->comments != (char *) NULL; q++)
  672.   {
  673.     if (*p == '\0')
  674.       break;
  675.     *q='\0';
  676.     if ((q-image->comments+MaxTextLength) >= length)
  677.       {
  678.         length<<=1;
  679.         image->comments=(char *)
  680.           realloc((char *) image->comments,length*sizeof(char));
  681.         if (image->comments == (char *) NULL)
  682.           break;
  683.         q=image->comments+strlen(image->comments)-1;
  684.       }
  685.     /*
  686.       Process formatting characters in comment.
  687.     */
  688.     if ((*p == '\\') && (*(p+1) == 'n'))
  689.       {
  690.         *q='\n';
  691.         p+=2;
  692.         continue;
  693.       }
  694.     if (*p != '%')
  695.       {
  696.         *q=(*p++);
  697.         continue;
  698.       }
  699.     p++;
  700.     switch (*p)
  701.     {
  702.       case 'f':
  703.       {
  704.         register char
  705.           *p;
  706.  
  707.         /*
  708.           Comment segment is the base of the filename.
  709.         */
  710.         p=image->filename+strlen(image->filename)-1;
  711.         while ((p > image->filename) && (*(p-1) != '/'))
  712.           p--;
  713.         (void) strcpy(q,p);
  714.         break;
  715.       }
  716.       case 'h':
  717.       {
  718.         (void) sprintf(q,"%u",image->rows);
  719.         break;
  720.       }
  721.       case 'm':
  722.       {
  723.         (void) strcpy(q,image->magick);
  724.         break;
  725.       }
  726.       case 's':
  727.       {
  728.         (void) sprintf(q,"%u",image->scene);
  729.         break;
  730.       }
  731.       case 'w':
  732.       {
  733.         (void) sprintf(q,"%u",image->columns);
  734.         break;
  735.       }
  736.       default:
  737.       {
  738.         *q++='%';
  739.         *q++=(*p);
  740.         *q++='\0';
  741.         break;
  742.       }
  743.     }
  744.     p++;
  745.     q=image->comments+strlen(image->comments)-1;
  746.   }
  747.   if (image->comments == (char *) NULL)
  748.     {
  749.       Warning("Unable to comment image","Memory allocation failed");
  750.       return;
  751.     }
  752.   *q='\0';
  753. }
  754.  
  755. /*
  756. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  757. %                                                                             %
  758. %                                                                             %
  759. %                                                                             %
  760. %   C o m p r e s s C o l o r m a p                                           %
  761. %                                                                             %
  762. %                                                                             %
  763. %                                                                             %
  764. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  765. %
  766. %  Function CompressColormap compresses an image colormap removing any
  767. %  unused color entries.
  768. %
  769. %  The format of the CompressColormap routine is:
  770. %
  771. %      CompressColormap(image)
  772. %
  773. %  A description of each parameter follows:
  774. %
  775. %    o image: The address of a structure of type Image.
  776. %
  777. %
  778. */
  779. void CompressColormap(image)
  780. Image
  781.   *image;
  782. {
  783.   ColorPacket
  784.     *colormap;
  785.  
  786.   int
  787.     number_colors;
  788.  
  789.   register int
  790.     i;
  791.  
  792.   register RunlengthPacket
  793.     *p;
  794.  
  795.   register unsigned short
  796.     index;
  797.  
  798.   /*
  799.     Determine if colormap can be compressed.
  800.   */
  801.   if (image->class != PseudoClass)
  802.     return;
  803.   number_colors=image->colors;
  804.   for (i=0; i < image->colors; i++)
  805.     image->colormap[i].flags=False;
  806.   image->colors=0;
  807.   p=image->pixels;
  808.   for (i=0; i < image->packets; i++)
  809.   {
  810.     if (!image->colormap[p->index].flags)
  811.       {
  812.         image->colormap[p->index].index=image->colors;
  813.         image->colormap[p->index].flags=True;
  814.         image->colors++;
  815.       }
  816.     p++;
  817.   }
  818.   if (image->colors == number_colors)
  819.     return;  /* no unused entries */
  820.   /*
  821.     Compress colormap.
  822.   */
  823.   colormap=(ColorPacket *) malloc(image->colors*sizeof(ColorPacket));
  824.   if (colormap == (ColorPacket *) NULL)
  825.     {
  826.       Warning("Unable to compress colormap","Memory allocation failed");
  827.       image->colors=number_colors;
  828.       return;
  829.     }
  830.   for (i=0; i < number_colors; i++)
  831.     if (image->colormap[i].flags)
  832.       {
  833.         index=image->colormap[i].index;
  834.         colormap[index].red=image->colormap[i].red;
  835.         colormap[index].green=image->colormap[i].green;
  836.         colormap[index].blue=image->colormap[i].blue;
  837.       }
  838.   /*
  839.     Remap pixels.
  840.   */
  841.   p=image->pixels;
  842.   for (i=0; i < image->packets; i++)
  843.   {
  844.     p->index=image->colormap[p->index].index;
  845.     p++;
  846.   }
  847.   (void) free((char *) image->colormap);
  848.   image->colormap=colormap;
  849. }
  850.  
  851. /*
  852. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  853. %                                                                             %
  854. %                                                                             %
  855. %                                                                             %
  856. %   C o m p r e s s I m a g e                                                 %
  857. %                                                                             %
  858. %                                                                             %
  859. %                                                                             %
  860. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  861. %
  862. %  Function CompressImage compresses an image to the minimum number of
  863. %  runlength-encoded packets.
  864. %
  865. %  The format of the CompressImage routine is:
  866. %
  867. %      CompressImage(image)
  868. %
  869. %  A description of each parameter follows:
  870. %
  871. %    o image: The address of a structure of type Image.
  872. %
  873. %
  874. */
  875. void CompressImage(image)
  876. Image
  877.   *image;
  878. {
  879.   register int
  880.     i;
  881.  
  882.   register RunlengthPacket
  883.     *p,
  884.     *q;
  885.  
  886.   /*
  887.     Compress image.
  888.   */
  889.   p=image->pixels;
  890.   image->runlength=p->length+1;
  891.   image->packets=0;
  892.   q=image->pixels;
  893.   q->length=MaxRunlength;
  894.   if (image->alpha)
  895.     for (i=0; i < (image->columns*image->rows); i++)
  896.     {
  897.       if (image->runlength != 0)
  898.         image->runlength--;
  899.       else
  900.         {
  901.           p++;
  902.           image->runlength=p->length;
  903.         }
  904.       if ((p->red == q->red) && (p->green == q->green) &&
  905.           (p->blue == q->blue) && (p->index == q->index) &&
  906.           (q->length < MaxRunlength))
  907.         q->length++;
  908.       else
  909.         {
  910.           if (image->packets > 0)
  911.             q++;
  912.           image->packets++;
  913.           *q=(*p);
  914.           q->length=0;
  915.         }
  916.     }
  917.   else
  918.     for (i=0; i < (image->columns*image->rows); i++)
  919.     {
  920.       if (image->runlength != 0)
  921.         image->runlength--;
  922.       else
  923.         {
  924.           p++;
  925.           image->runlength=p->length;
  926.         }
  927.       if ((p->red == q->red) && (p->green == q->green) &&
  928.           (p->blue == q->blue) && (q->length < MaxRunlength))
  929.         q->length++;
  930.       else
  931.         {
  932.           if (image->packets > 0)
  933.             q++;
  934.           image->packets++;
  935.           *q=(*p);
  936.           q->length=0;
  937.         }
  938.     }
  939.   image->pixels=(RunlengthPacket *) realloc((char *) image->pixels,
  940.     image->packets*sizeof(RunlengthPacket));
  941.   /*
  942.     Runlength-encode only if it consumes less memory than no compression.
  943.   */
  944.   if (image->compression == RunlengthEncodedCompression)
  945.     if (image->class == DirectClass)
  946.       {
  947.         if (image->packets >= ((image->columns*image->rows*3) >> 2))
  948.           image->compression=NoCompression;
  949.       }
  950.     else
  951.       if (image->packets >= ((image->columns*image->rows) >> 1))
  952.         image->compression=NoCompression;
  953. }
  954.  
  955. /*
  956. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  957. %                                                                             %
  958. %                                                                             %
  959. %                                                                             %
  960. %   C o m p o s i t e I m a g e                                               %
  961. %                                                                             %
  962. %                                                                             %
  963. %                                                                             %
  964. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  965. %
  966. %  Function CompositeImage returns the second image composited onto the
  967. %  first at the specified offsets.
  968. %
  969. %  The format of the CompositeImage routine is:
  970. %
  971. %      CompositeImage(image,compose,composite_image,x_offset,y_offset)
  972. %
  973. %  A description of each parameter follows:
  974. %
  975. %    o image: The address of a structure of type Image.
  976. %
  977. %    o compose: Specifies an image composite operator.
  978. %
  979. %    o composite_image: The address of a structure of type Image.
  980. %
  981. %    o x_offset: An integer that specifies the column offset of the composited
  982. %      image.
  983. %
  984. %    o y_offset: An integer that specifies the row offset of the composited
  985. %      image.
  986. %
  987. %
  988. */
  989. void CompositeImage(image,compose,composite_image,x_offset,y_offset)
  990. Image
  991.   *image;
  992.  
  993. unsigned int
  994.   compose;
  995.  
  996. Image
  997.   *composite_image;
  998.  
  999. int
  1000.   x_offset,
  1001.   y_offset;
  1002. {
  1003.   int
  1004.     blue,
  1005.     green,
  1006.     red;
  1007.  
  1008.   register int
  1009.     i,
  1010.     x,
  1011.     y;
  1012.  
  1013.   register RunlengthPacket
  1014.     *p,
  1015.     *q;
  1016.  
  1017.   register short
  1018.     index;
  1019.  
  1020.   /*
  1021.     Check composite geometry.
  1022.   */
  1023.   if (((x_offset+(int) image->columns) < 0) ||
  1024.       ((y_offset+(int) image->rows) < 0) ||
  1025.       (x_offset > (int) image->columns) || (y_offset > (int) image->rows))
  1026.     {
  1027.       Warning("Unable to composite image","geometry does not contain image");
  1028.       return;
  1029.     }
  1030.   /*
  1031.     Image must be uncompressed.
  1032.   */
  1033.   if (!UncompressImage(image))
  1034.     return;
  1035.   if (compose == ReplaceCompositeOp)
  1036.     {
  1037.       /*
  1038.         Promote image to DirectClass if colormaps differ.
  1039.       */
  1040.       if (image->class == PseudoClass)
  1041.         if (composite_image->class == DirectClass)
  1042.           image->class=DirectClass;
  1043.         else
  1044.           {
  1045.             if (image->signature == (char *) NULL)
  1046.               ColormapSignature(image);
  1047.             if (composite_image->signature == (char *) NULL)
  1048.               ColormapSignature(composite_image);
  1049.             if (strcmp(image->signature,composite_image->signature) != 0)
  1050.               image->class=DirectClass;
  1051.           }
  1052.     }
  1053.   else
  1054.     {
  1055.       /*
  1056.         Initialize image alpha data.
  1057.       */
  1058.       if (!image->alpha)
  1059.         {
  1060.           q=image->pixels;
  1061.           red=q->red;
  1062.           green=q->green;
  1063.           blue=q->blue;
  1064.           for (i=0; i < image->packets; i++)
  1065.           {
  1066.             q->index=MaxRGB;
  1067.             if ((q->red == red) && (q->green == green) && (q->blue == blue))
  1068.               q->index=0;
  1069.             q++;
  1070.           }
  1071.           image->class=DirectClass;
  1072.           image->alpha=True;
  1073.         }
  1074.       if (!composite_image->alpha)
  1075.         {
  1076.           p=composite_image->pixels;
  1077.           red=p->red;
  1078.           green=p->green;
  1079.           blue=p->blue;
  1080.           for (i=0; i < composite_image->packets; i++)
  1081.           {
  1082.             p->index=MaxRGB;
  1083.             if ((p->red == red) && (p->green == green) && (p->blue == blue))
  1084.               p->index=0;
  1085.             p++;
  1086.           }
  1087.           composite_image->class=DirectClass;
  1088.           composite_image->alpha=True;
  1089.         }
  1090.     }
  1091.   /*
  1092.     Initialize composited image.
  1093.   */
  1094.   p=composite_image->pixels;
  1095.   composite_image->runlength=p->length+1;
  1096.   for (y=0; y < composite_image->rows; y++)
  1097.   {
  1098.     if (((y_offset+y) < 0) || ((y_offset+y) >= image->rows))
  1099.       continue;
  1100.     q=image->pixels+(y_offset+y)*image->columns+x_offset;
  1101.     for (x=0; x < composite_image->columns; x++)
  1102.     {
  1103.       if (composite_image->runlength != 0)
  1104.         composite_image->runlength--;
  1105.       else
  1106.         {
  1107.           p++;
  1108.           composite_image->runlength=p->length;
  1109.         }
  1110.       if (((x_offset+x) < 0) || ((x_offset+x) >= image->columns))
  1111.         {
  1112.           q++;
  1113.           continue;
  1114.         }
  1115.       switch (compose)
  1116.       {
  1117.         case OverCompositeOp:
  1118.         default:
  1119.         {
  1120.           if (p->index == 0)
  1121.             {
  1122.               red=q->red;
  1123.               green=q->green;
  1124.               blue=q->blue;
  1125.               index=q->index;
  1126.             }
  1127.           else
  1128.             if (p->index == MaxRGB)
  1129.               {
  1130.                 red=p->red;
  1131.                 green=p->green;
  1132.                 blue=p->blue;
  1133.                 index=p->index;
  1134.               }
  1135.             else
  1136.               {
  1137.                 red=(int) (p->red*MaxRGB+q->red*(MaxRGB-p->index))/MaxRGB;
  1138.                 green=(int) (p->green*MaxRGB+q->green*(MaxRGB-p->index))/MaxRGB;
  1139.                 blue=(int) (p->blue*MaxRGB+q->blue*(MaxRGB-p->index))/MaxRGB;
  1140.                 index=(int) (p->index*MaxRGB+q->index*(MaxRGB-p->index))/MaxRGB;
  1141.               }
  1142.           break;
  1143.         }
  1144.         case InCompositeOp:
  1145.         {
  1146.           red=(int) (p->red*q->index)/MaxRGB;
  1147.           green=(int) (p->green*q->index)/MaxRGB;
  1148.           blue=(int) (p->blue*q->index)/MaxRGB;
  1149.           index=(int) (p->index*q->index)/MaxRGB;
  1150.           break;
  1151.         }
  1152.         case OutCompositeOp:
  1153.         {
  1154.           red=(int) (p->red*(MaxRGB-q->index))/MaxRGB;
  1155.           green=(int) (p->green*(MaxRGB-q->index))/MaxRGB;
  1156.           blue=(int) (p->blue*(MaxRGB-q->index))/MaxRGB;
  1157.           index=(int) (p->index*(MaxRGB-q->index))/MaxRGB;
  1158.           break;
  1159.         }
  1160.         case AtopCompositeOp:
  1161.         {
  1162.           red=(int) (p->red*q->index+q->red*(MaxRGB-p->index))/MaxRGB;
  1163.           green=(int) (p->green*q->index+q->green*(MaxRGB-p->index))/MaxRGB;
  1164.           blue=(int) (p->blue*q->index+q->blue*(MaxRGB-p->index))/MaxRGB;
  1165.           index=(int) (p->index*q->index+q->index*(MaxRGB-p->index))/MaxRGB;
  1166.           break;
  1167.         }
  1168.         case XorCompositeOp:
  1169.         {
  1170.           red=(int) (p->red*(MaxRGB-q->index)+q->red*(MaxRGB-p->index))/MaxRGB;
  1171.           green=(int) (p->green*(MaxRGB-q->index)+q->green*(MaxRGB-p->index))/
  1172.             MaxRGB;
  1173.           blue=(int) (p->blue*(MaxRGB-q->index)+q->blue*(MaxRGB-p->index))/
  1174.             MaxRGB;
  1175.           index=(int) (p->index*(MaxRGB-q->index)+q->index*(MaxRGB-p->index))/
  1176.             MaxRGB;
  1177.           break;
  1178.         }
  1179.         case PlusCompositeOp:
  1180.         {
  1181.           red=(int) p->red+(int) q->red;
  1182.           green=(int) p->green+(int) q->green;
  1183.           blue=(int) p->blue+(int) q->blue;
  1184.           index=(int) p->index+(int) q->index;
  1185.           break;
  1186.         }
  1187.         case MinusCompositeOp:
  1188.         {
  1189.           red=(int) p->red-(int) q->red;
  1190.           green=(int) p->green-(int) q->green;
  1191.           blue=(int) p->blue-(int) q->blue;
  1192.           index=255;
  1193.           break;
  1194.         }
  1195.         case AddCompositeOp:
  1196.         {
  1197.           red=(int) p->red+(int) q->red;
  1198.           if (red > MaxRGB)
  1199.             red-=(MaxRGB+1);
  1200.           green=(int) p->green+(int) q->green;
  1201.           if (green > MaxRGB)
  1202.             green-=(MaxRGB+1);
  1203.           blue=(int) p->blue+(int) q->blue;
  1204.           if (blue > MaxRGB)
  1205.             blue-=(MaxRGB+1);
  1206.           index=(int) p->index+(int) q->index;
  1207.           if (index > MaxRGB)
  1208.             index-=(MaxRGB+1);
  1209.           break;
  1210.         }
  1211.         case SubtractCompositeOp:
  1212.         {
  1213.           red=(int) p->red-(int) q->red;
  1214.           if (red < 0)
  1215.             red+=(MaxRGB+1);
  1216.           green=(int) p->green-(int) q->green;
  1217.           if (green < 0)
  1218.             green+=(MaxRGB+1);
  1219.           blue=(int) p->blue-(int) q->blue;
  1220.           if (blue < 0)
  1221.             blue+=(MaxRGB+1);
  1222.           index=(int) p->index-(int) q->index;
  1223.           if (index < 0)
  1224.             index+=(MaxRGB+1);
  1225.           break;
  1226.         }
  1227.         case DifferenceCompositeOp:
  1228.         {
  1229.           red=AbsoluteValue((int) p->red-(int) q->red);
  1230.           green=AbsoluteValue((int) p->green-(int) q->green);
  1231.           blue=AbsoluteValue((int) p->blue-(int) q->blue);
  1232.           index=AbsoluteValue((int) p->index-(int) q->index);
  1233.           break;
  1234.         }
  1235.         case ReplaceCompositeOp:
  1236.         {
  1237.           red=p->red;
  1238.           green=p->green;
  1239.           blue=p->blue;
  1240.           index=p->index;
  1241.           break;
  1242.         }
  1243.       }
  1244.       if (red > MaxRGB)
  1245.         q->red=MaxRGB;
  1246.       else
  1247.         if (red < 0)
  1248.           q->red=0;
  1249.         else
  1250.           q->red=red;
  1251.       if (green > MaxRGB)
  1252.         q->green=MaxRGB;
  1253.       else
  1254.         if (green < 0)
  1255.           q->green=0;
  1256.         else
  1257.           q->green=green;
  1258.       if (blue > MaxRGB)
  1259.         q->blue=MaxRGB;
  1260.       else
  1261.         if (blue < 0)
  1262.           q->blue=0;
  1263.         else
  1264.           q->blue=blue;
  1265.       if (index > 255)
  1266.         q->index=255;
  1267.       else
  1268.         if (index < 0)
  1269.           q->index=0;
  1270.         else
  1271.           q->index=index;
  1272.       q->length=0;
  1273.       q++;
  1274.     }
  1275.   }
  1276. }
  1277.  
  1278. /*
  1279. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1280. %                                                                             %
  1281. %                                                                             %
  1282. %                                                                             %
  1283. %   C o p y I m a g e                                                         %
  1284. %                                                                             %
  1285. %                                                                             %
  1286. %                                                                             %
  1287. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1288. %
  1289. %  Function CopyImage returns a copy of all fields of the input image.  The
  1290. %  the pixel memory is allocated but the pixel data is not copied.
  1291. %
  1292. %  The format of the CopyImage routine is:
  1293. %
  1294. %      copy_image=CopyImage(image,columns,rows,copy_pixels)
  1295. %
  1296. %  A description of each parameter follows:
  1297. %
  1298. %    o copy_image: Function CopyImage returns a pointer to the image after
  1299. %      copying.  A null image is returned if there is a memory shortage.
  1300. %
  1301. %    o image: The address of a structure of type Image.
  1302. %
  1303. %    o columns: An integer that specifies the number of columns in the copied
  1304. %      image.
  1305. %
  1306. %    o rows: An integer that specifies the number of rows in the copied
  1307. %      image.
  1308. %
  1309. %    o copy_pixels: Specifies whether the pixel data is copied.  Must be
  1310. %      either True or False;
  1311. %
  1312. %
  1313. */
  1314. Image *CopyImage(image,columns,rows,copy_pixels)
  1315. Image
  1316.   *image;
  1317.  
  1318. unsigned int
  1319.   columns,
  1320.   rows,
  1321.   copy_pixels;
  1322. {
  1323.   Image
  1324.     *copy_image;
  1325.  
  1326.   register int
  1327.     i;
  1328.  
  1329.   /*
  1330.     Allocate image structure.
  1331.   */
  1332.   copy_image=(Image *) malloc(sizeof(Image));
  1333.   if (copy_image == (Image *) NULL)
  1334.     return((Image *) NULL);
  1335.   *copy_image=(*image);
  1336.   if (image->comments != (char *) NULL)
  1337.     {
  1338.       /*
  1339.         Allocate and copy the image comments.
  1340.       */
  1341.       copy_image->comments=(char *)
  1342.         malloc(((strlen(image->comments)+1)*sizeof(char)));
  1343.       if (copy_image->comments == (char *) NULL)
  1344.         return((Image *) NULL);
  1345.       (void) strcpy(copy_image->comments,image->comments);
  1346.     }
  1347.   if (image->label != (char *) NULL)
  1348.     {
  1349.       /*
  1350.         Allocate and copy the image label.
  1351.       */
  1352.       copy_image->label=(char *)
  1353.         malloc(((strlen(image->label)+1)*sizeof(char)));
  1354.       if (copy_image->label == (char *) NULL)
  1355.         return((Image *) NULL);
  1356.       (void) strcpy(copy_image->label,image->label);
  1357.     }
  1358.   copy_image->columns=columns;
  1359.   copy_image->rows=rows;
  1360.   copy_image->montage=(char *) NULL;
  1361.   copy_image->directory=(char *) NULL;
  1362.   if (image->colormap != (ColorPacket *) NULL)
  1363.     {
  1364.       /*
  1365.         Allocate and copy the image colormap.
  1366.       */
  1367.       copy_image->colormap=(ColorPacket *)
  1368.         malloc(image->colors*sizeof(ColorPacket));
  1369.       if (copy_image->colormap == (ColorPacket *) NULL)
  1370.         return((Image *) NULL);
  1371.       for (i=0; i < image->colors; i++)
  1372.         copy_image->colormap[i]=image->colormap[i];
  1373.     }
  1374.   if (image->signature != (char *) NULL)
  1375.     {
  1376.       /*
  1377.         Allocate and copy the image signature.
  1378.       */
  1379.       copy_image->signature=(char *)
  1380.         malloc(((strlen(image->signature)+1)*sizeof(char)));
  1381.       if (copy_image->signature == (char *) NULL)
  1382.         return((Image *) NULL);
  1383.       (void) strcpy(copy_image->signature,image->signature);
  1384.     }
  1385.   /*
  1386.     Allocate the image pixels.
  1387.   */
  1388.   if (!copy_pixels)
  1389.     copy_image->packets=copy_image->columns*copy_image->rows;
  1390.   copy_image->pixels=(RunlengthPacket *)
  1391.     malloc((unsigned int) copy_image->packets*sizeof(RunlengthPacket));
  1392.   if (copy_image->pixels == (RunlengthPacket *) NULL)
  1393.     return((Image *) NULL);
  1394.   if (copy_pixels)
  1395.     {
  1396.       register RunlengthPacket
  1397.         *p,
  1398.         *q;
  1399.  
  1400.       if ((image->columns != columns) || (image->rows != rows))
  1401.         return((Image *) NULL);
  1402.       /*
  1403.         Copy the image pixels.
  1404.       */
  1405.       p=image->pixels;
  1406.       q=copy_image->pixels;
  1407.       for (i=0; i < image->packets; i++)
  1408.       {
  1409.         *q=(*p);
  1410.         p++;
  1411.         q++;
  1412.       }
  1413.     }
  1414.   if (image->orphan)
  1415.     copy_image->file=(FILE *) NULL;
  1416.   else
  1417.     {
  1418.       /*
  1419.         Link image into image list.
  1420.       */
  1421.       if (copy_image->previous != (Image *) NULL)
  1422.         copy_image->previous->next=copy_image;
  1423.       if (copy_image->next != (Image *) NULL)
  1424.         copy_image->next->previous=copy_image;
  1425.     }
  1426.   return(copy_image);
  1427. }
  1428.  
  1429. /*
  1430. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1431. %                                                                             %
  1432. %                                                                             %
  1433. %                                                                             %
  1434. %   D e s t r o y I m a g e                                                   %
  1435. %                                                                             %
  1436. %                                                                             %
  1437. %                                                                             %
  1438. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1439. %
  1440. %  Function DestroyImage deallocates memory associated with an image.
  1441. %
  1442. %  The format of the DestroyImage routine is:
  1443. %
  1444. %      DestroyImage(image)
  1445. %
  1446. %  A description of each parameter follows:
  1447. %
  1448. %    o image: The address of a structure of type Image.
  1449. %
  1450. %
  1451. */
  1452. void DestroyImage(image)
  1453. Image
  1454.   *image;
  1455. {
  1456.   /*
  1457.     Close image.
  1458.   */
  1459.   CloseImage(image);
  1460.   /*
  1461.     Deallocate the image comments.
  1462.   */
  1463.   if (image->comments != (char *) NULL)
  1464.     (void) free((char *) image->comments);
  1465.   /*
  1466.     Deallocate the image label.
  1467.   */
  1468.   if (image->label != (char *) NULL)
  1469.     (void) free((char *) image->label);
  1470.   /*
  1471.     Deallocate the image montage directory.
  1472.   */
  1473.   if (image->montage != (char *) NULL)
  1474.     (void) free((char *) image->montage);
  1475.   if (image->directory != (char *) NULL)
  1476.     (void) free((char *) image->directory);
  1477.   /*
  1478.     Deallocate the image colormap.
  1479.   */
  1480.   if (image->colormap != (ColorPacket *) NULL)
  1481.     (void) free((char *) image->colormap);
  1482.   /*
  1483.     Deallocate the image signature.
  1484.   */
  1485.   if (image->signature != (char *) NULL)
  1486.     (void) free((char *) image->signature);
  1487.   /*
  1488.     Deallocate the image pixels.
  1489.   */
  1490.   if (image->pixels != (RunlengthPacket *) NULL)
  1491.     (void) free((char *) image->pixels);
  1492.   if (image->packed_pixels != (unsigned char *) NULL)
  1493.     (void) free((char *) image->packed_pixels);
  1494.   /*
  1495.     Deallocate the image structure.
  1496.   */
  1497.   (void) free((char *) image);
  1498.   image=(Image *) NULL;
  1499. }
  1500.  
  1501. /*
  1502. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1503. %                                                                             %
  1504. %                                                                             %
  1505. %                                                                             %
  1506. %   D e s t r o y I m a g e s                                                 %
  1507. %                                                                             %
  1508. %                                                                             %
  1509. %                                                                             %
  1510. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1511. %
  1512. %  Function DestroyImages deallocates memory associated with a linked list
  1513. %  of images.
  1514. %
  1515. %  The format of the DestroyImages routine is:
  1516. %
  1517. %      DestroyImages(image)
  1518. %
  1519. %  A description of each parameter follows:
  1520. %
  1521. %    o image: The address of a structure of type Image.
  1522. %
  1523. %
  1524. */
  1525. void DestroyImages(image)
  1526. Image
  1527.   *image;
  1528. {
  1529.   Image
  1530.     *next_image;
  1531.  
  1532.   /*
  1533.     Proceed to the top of the image list.
  1534.   */
  1535.   while (image->previous != (Image *) NULL)
  1536.     image=image->previous;
  1537.   do
  1538.   {
  1539.     /*
  1540.       Destroy this image.
  1541.     */
  1542.     next_image=image->next;
  1543.     DestroyImage(image);
  1544.     image=next_image;
  1545.   } while (image != (Image *) NULL);
  1546. }
  1547.  
  1548. /*
  1549. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1550. %                                                                             %
  1551. %                                                                             %
  1552. %     E n h a n c e I m a g e                                                 %
  1553. %                                                                             %
  1554. %                                                                             %
  1555. %                                                                             %
  1556. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1557. %
  1558. %  Function EnhanceImage creates a new image that is a copy of an existing
  1559. %  one with the noise reduced.  It allocates the memory necessary for the new
  1560. %  Image structure and returns a pointer to the new image.
  1561. %
  1562. %  EnhanceImage does a weighted average of pixels in a 5x5 cell around each
  1563. %  target pixel.  Only pixels in the 5x5 cell that are within a RGB distance
  1564. %  threshold of the target pixel are averaged.
  1565. %
  1566. %  Weights assume that the importance of neighboring pixels is inversely
  1567. %  proportional to the square of their distance from the target pixel.
  1568. %
  1569. %  The scan only processes pixels that have a full set of neighbors.  Pixels
  1570. %  in the top, bottom, left, and right pairs of rows and columns are omitted
  1571. %  from the scan.
  1572. %
  1573. %  The format of the EnhanceImage routine is:
  1574. %
  1575. %      enhanced_image=EnhanceImage(image)
  1576. %
  1577. %  A description of each parameter follows:
  1578. %
  1579. %    o enhanced_image: Function EnhanceImage returns a pointer to the image
  1580. %      after it is enhanced.  A null image is returned if there is a memory
  1581. %      shortage.
  1582. %
  1583. %    o image: The address of a structure of type Image;  returned from
  1584. %      ReadImage.
  1585. %
  1586. %
  1587. */
  1588. Image *EnhanceImage(image)
  1589. Image
  1590.   *image;
  1591. {
  1592. #define Esum(weight) \
  1593.   red_distance=s->red-red; \
  1594.   green_distance=s->green-green; \
  1595.   blue_distance=s->blue-blue; \
  1596.   distance=red_distance*red_distance+green_distance*green_distance+ \
  1597.     blue_distance*blue_distance; \
  1598.   if (distance < Threshold) \
  1599.     { \
  1600.       total_red+=weight*(s->red); \
  1601.       total_green+=weight*(s->green); \
  1602.       total_blue+=weight*(s->blue); \
  1603.       total_weight+=weight; \
  1604.     } \
  1605.   s++;
  1606. #define Threshold  2500
  1607.  
  1608.   Image
  1609.     *enhanced_image;
  1610.  
  1611.   int
  1612.     blue_distance,
  1613.     green_distance,
  1614.     red_distance;
  1615.  
  1616.   register RunlengthPacket
  1617.     *p,
  1618.     *q,
  1619.     *s,
  1620.     *s0,
  1621.     *s1,
  1622.     *s2,
  1623.     *s3,
  1624.     *s4;
  1625.  
  1626.   register unsigned int
  1627.     x;
  1628.  
  1629.   RunlengthPacket
  1630.     *scanline;
  1631.  
  1632.   unsigned char
  1633.     blue,
  1634.     green,
  1635.     red;
  1636.  
  1637.   unsigned int
  1638.     y;
  1639.  
  1640.   unsigned long
  1641.     distance,
  1642.     total_blue,
  1643.     total_green,
  1644.     total_red,
  1645.     total_weight;
  1646.  
  1647.   if ((image->columns < 5) || (image->rows < 5))
  1648.     {
  1649.       Warning("Unable to enhance image","image size must exceed 4x4");
  1650.       return((Image *) NULL);
  1651.     }
  1652.   /*
  1653.     Initialize enhanced image attributes.
  1654.   */
  1655.   enhanced_image=CopyImage(image,image->columns,image->rows,False);
  1656.   if (enhanced_image == (Image *) NULL)
  1657.     {
  1658.       Warning("Unable to enhance image","Memory allocation failed");
  1659.       return((Image *) NULL);
  1660.     }
  1661.   enhanced_image->class=DirectClass;
  1662.   /*
  1663.     Allocate scan line buffer for 5 rows of the image.
  1664.   */
  1665.   scanline=(RunlengthPacket *) malloc(5*image->columns*sizeof(RunlengthPacket));
  1666.   if (scanline == (RunlengthPacket *) NULL)
  1667.     {
  1668.       Warning("Unable to enhance image","Memory allocation failed");
  1669.       DestroyImage(enhanced_image);
  1670.       return((Image *) NULL);
  1671.     }
  1672.   /*
  1673.     Read the first 4 rows of the image.
  1674.   */
  1675.   p=image->pixels;
  1676.   image->runlength=p->length+1;
  1677.   s=scanline;
  1678.   for (x=0; x < (image->columns*4); x++)
  1679.   {
  1680.     if (image->runlength != 0)
  1681.       image->runlength--;
  1682.     else
  1683.       {
  1684.         p++;
  1685.         image->runlength=p->length;
  1686.       }
  1687.     *s=(*p);
  1688.     s++;
  1689.   }
  1690.   /*
  1691.     Dump first 2 scanlines of image.
  1692.   */
  1693.   q=enhanced_image->pixels;
  1694.   s=scanline;
  1695.   for (x=0; x < (image->columns << 1); x++)
  1696.   {
  1697.     *q=(*s);
  1698.     q->length=0;
  1699.     q++;
  1700.     s++;
  1701.   }
  1702.   /*
  1703.     Enhance each row.
  1704.   */
  1705.   for (y=2; y < (image->rows-2); y++)
  1706.   {
  1707.     /*
  1708.       Initialize sliding window pointers.
  1709.     */
  1710.     s0=scanline+image->columns*((y-2) % 5);
  1711.     s1=scanline+image->columns*((y-1) % 5);
  1712.     s2=scanline+image->columns*(y % 5);
  1713.     s3=scanline+image->columns*((y+1) % 5);
  1714.     s4=scanline+image->columns*((y+2) % 5);
  1715.     /*
  1716.       Read another scan line.
  1717.     */
  1718.     s=s4;
  1719.     for (x=0; x < image->columns; x++)
  1720.     {
  1721.       if (image->runlength != 0)
  1722.         image->runlength--;
  1723.       else
  1724.         {
  1725.           p++;
  1726.           image->runlength=p->length;
  1727.         }
  1728.       *s=(*p);
  1729.       s++;
  1730.     }
  1731.     /*
  1732.       Transfer first 2 pixels of the scanline.
  1733.     */
  1734.     s=s2;
  1735.     for (x=0; x < 2; x++)
  1736.     {
  1737.       *q=(*s);
  1738.       q->length=0;
  1739.       q++;
  1740.       s++;
  1741.     }
  1742.     for (x=2; x < (image->columns-2); x++)
  1743.     {
  1744.       /*
  1745.         Compute weighted average of target pixel color components.
  1746.       */
  1747.       total_red=0;
  1748.       total_green=0;
  1749.       total_blue=0;
  1750.       total_weight=0;
  1751.       s=s2+2;
  1752.       red=s->red;
  1753.       green=s->green;
  1754.       blue=s->blue;
  1755.       s=s0;
  1756.       Esum(5);  Esum(8);  Esum(10); Esum(8);  Esum(5);
  1757.       s=s1;
  1758.       Esum(8);  Esum(20); Esum(40); Esum(20); Esum(8);
  1759.       s=s2;
  1760.       Esum(10); Esum(40); Esum(80); Esum(40); Esum(10);
  1761.       s=s3;
  1762.       Esum(8);  Esum(20); Esum(40); Esum(20); Esum(8);
  1763.       s=s4;
  1764.       Esum(5);  Esum(8);  Esum(10); Esum(8);  Esum(5);
  1765.       q->red=(unsigned char) ((total_red+(total_weight >> 1)-1)/total_weight);
  1766.       q->green=
  1767.         (unsigned char) ((total_green+(total_weight >> 1)-1)/total_weight);
  1768.       q->blue=(unsigned char) ((total_blue+(total_weight >> 1)-1)/total_weight);
  1769.       q->index=0;
  1770.       q->length=0;
  1771.       q++;
  1772.       s0++;
  1773.       s1++;
  1774.       s2++;
  1775.       s3++;
  1776.       s4++;
  1777.     }
  1778.     /*
  1779.       Transfer last 2 pixels of the scanline.
  1780.     */
  1781.     s=s2;
  1782.     for (x=0; x < 2; x++)
  1783.     {
  1784.       *q=(*s);
  1785.       q->length=0;
  1786.       q++;
  1787.       s++;
  1788.     }
  1789.   }
  1790.   /*
  1791.     Dump last 2 scanlines of pixels.
  1792.   */
  1793.   s=scanline+image->columns*(y % 3);
  1794.   for (x=0; x < (image->columns << 1); x++)
  1795.   {
  1796.     *q=(*s);
  1797.     q->length=0;
  1798.     q++;
  1799.     s++;
  1800.   }
  1801.   (void) free((char *) scanline);
  1802.   return(enhanced_image);
  1803. }
  1804.  
  1805. /*
  1806. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1807. %                                                                             %
  1808. %                                                                             %
  1809. %                                                                             %
  1810. %   F r a m e I m a g e                                                       %
  1811. %                                                                             %
  1812. %                                                                             %
  1813. %                                                                             %
  1814. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  1815. %
  1816. %  Function FrameImage takes an image and puts a frame around it of a
  1817. %  particular color.  It allocates the memory necessary for the new Image
  1818. %  structure and returns a pointer to the new image.
  1819. %
  1820. %  The format of the FrameImage routine is:
  1821. %
  1822. %      framed_image=FrameImage(image,frame_info,bevel_width,matte_color,
  1823. %        highlight_color,shadow_color)
  1824. %
  1825. %  A description of each parameter follows:
  1826. %
  1827. %    o framed_image: Function FrameImage returns a pointer to the framed
  1828. %      image.  A null image is returned if there is a a memory shortage.
  1829. %
  1830. %    o image: The address of a structure of type Image.
  1831. %
  1832. %    o frame_info: Specifies a pointer to a XRectangle which defines the
  1833. %      framed region.
  1834. %
  1835. %    o bevel_width: An unsigned integer that is the width of the border of
  1836. %      the frame.
  1837. %
  1838. %    o matte_color: A pointer to a ColorPacket which contains the red,
  1839. %      green, and blue components of the border color.
  1840. %
  1841. %    o highlight_color: A pointer to a ColorPacket which contains the red,
  1842. %      green, and blue components of the highlight color.
  1843. %
  1844. %    o shadow_color: A pointer to a ColorPacket which contains the red,
  1845. %      green, and blue components of the shadow color.
  1846. %
  1847. %
  1848. */
  1849. Image *FrameImage(image,frame_info,bevel_width,matte_color,highlight_color,
  1850.   shadow_color)
  1851. Image
  1852.   *image;
  1853.  
  1854. RectangleInfo
  1855.   *frame_info;
  1856.  
  1857. unsigned int
  1858.   bevel_width;
  1859.  
  1860. ColorPacket
  1861.   *matte_color,
  1862.   *highlight_color,
  1863.   *shadow_color;
  1864. {
  1865.   Image
  1866.     *framed_image;
  1867.  
  1868.   int
  1869.     height,
  1870.     width;
  1871.  
  1872.   register int
  1873.     x,
  1874.     y;
  1875.  
  1876.   register RunlengthPacket
  1877.     *p,
  1878.     *q;
  1879.  
  1880.   RunlengthPacket
  1881.     black,
  1882.     highlight,
  1883.     matte,
  1884.     shadow;
  1885.  
  1886.   /*
  1887.     Check frame geometry.
  1888.   */
  1889.   width=(int) frame_info->width-frame_info->x-(bevel_width << 1);
  1890.   height=(int) frame_info->height-frame_info->y-(bevel_width << 1);
  1891.   if ((width < image->columns) || (height < image->rows))
  1892.     {
  1893.       Warning("Unable to frame image","frame is less than image size");
  1894.       return((Image *) NULL);
  1895.     }
  1896.   /*
  1897.     Initialize framed image attributes.
  1898.   */
  1899.   framed_image=CopyImage(image,frame_info->width,frame_info->height,False);
  1900.   if (framed_image == (Image *) NULL)
  1901.     {
  1902.       Warning("Unable to border image","Memory allocation failed");
  1903.       return((Image *) NULL);
  1904.     }
  1905.   image->class=DirectClass;
  1906.   /*
  1907.     Initialize frame colors.
  1908.   */
  1909.   black.red=0;
  1910.   black.green=0;
  1911.   black.blue=0;
  1912.   black.index=0;
  1913.   black.length=0;
  1914.   matte.red=matte_color->red;
  1915.   matte.green=matte_color->green;
  1916.   matte.blue=matte_color->blue;
  1917.   matte.index=0;
  1918.   matte.length=0;
  1919.   highlight.red=highlight_color->red;
  1920.   highlight.green=highlight_color->green;
  1921.   highlight.blue=highlight_color->blue;
  1922.   highlight.index=0;
  1923.   highlight.length=0;
  1924.   shadow.red=shadow_color->red;
  1925.   shadow.green=shadow_color->green;
  1926.   shadow.blue=shadow_color->blue;
  1927.   shadow.index=0;
  1928.   shadow.length=0;
  1929.   /*
  1930.     Copy image and put an ornamental border around it.
  1931.   */
  1932.   q=framed_image->pixels;
  1933.   for (x=0; x < framed_image->columns; x++)
  1934.     *q++=black;
  1935.   for (y=0; y < (bevel_width-1); y++)
  1936.   {
  1937.     *q++=black;
  1938.     for (x=0; x < (framed_image->columns-y-2); x++)
  1939.       *q++=highlight;
  1940.     for ( ; x < (framed_image->columns-2); x++)
  1941.       *q++=shadow;
  1942.     *q++=black;
  1943.   }
  1944.   for (y=0; y < (frame_info->y-(bevel_width << 1)); y++)
  1945.   {
  1946.     *q++=black;
  1947.     for (x=0; x < (bevel_width-1); x++)
  1948.       *q++=highlight;
  1949.     for (x=0; x < (framed_image->columns-(bevel_width << 1)); x++)
  1950.       *q++=matte;
  1951.     for (x=0; x < (bevel_width-1); x++)
  1952.       *q++=shadow;
  1953.     *q++=black;
  1954.   }
  1955.   for (y=0; y < (bevel_width-1); y++)
  1956.   {
  1957.     *q++=black;
  1958.     for (x=0; x < (bevel_width-1); x++)
  1959.       *q++=highlight;
  1960.     for (x=0; x < (frame_info->x-(bevel_width << 1)); x++)
  1961.       *q++=matte;
  1962.     for (x=0; x < (image->columns+(bevel_width << 1)-y); x++)
  1963.       *q++=shadow;
  1964.     for ( ; x < (image->columns+(bevel_width << 1)); x++)
  1965.       *q++=highlight;
  1966.     width=frame_info->width-frame_info->x-image->columns-(bevel_width << 1);
  1967.     for (x=0; x < width; x++)
  1968.       *q++=matte;
  1969.     for (x=0; x < (bevel_width-1); x++)
  1970.       *q++=shadow;
  1971.     *q++=black;
  1972.   }
  1973.   *q++=black;
  1974.   for (x=0; x < (bevel_width-1); x++)
  1975.     *q++=highlight;
  1976.   for (x=0; x < (frame_info->x-(bevel_width << 1)); x++)
  1977.     *q++=matte;
  1978.   for (x=0; x < (bevel_width-1); x++)
  1979.     *q++=shadow;
  1980.   for (x=0; x < (image->columns+2); x++)
  1981.     *q++=black;
  1982.   for (x=0; x < (bevel_width-1); x++)
  1983.     *q++=highlight;
  1984.   width=frame_info->width-frame_info->x-image->columns-(bevel_width << 1);
  1985.   for (x=0; x < width; x++)
  1986.     *q++=matte;
  1987.   for (x=0; x < (bevel_width-1); x++)
  1988.     *q++=shadow;
  1989.   *q++=black;
  1990.   p=image->pixels;
  1991.   image->runlength=p->length+1;
  1992.   for (y=0; y < image->rows; y++)
  1993.   {
  1994.     /*
  1995.       Initialize scanline with border color.
  1996.     */
  1997.     *q++=black;
  1998.     for (x=0; x < (bevel_width-1); x++)
  1999.       *q++=highlight;
  2000.     for (x=0; x < (frame_info->x-(bevel_width << 1)); x++)
  2001.       *q++=matte;
  2002.     for (x=0; x < (bevel_width-1); x++)
  2003.       *q++=shadow;
  2004.     *q++=black;
  2005.     /*
  2006.       Transfer scanline.
  2007.     */
  2008.     for (x=0; x < image->columns; x++)
  2009.     {
  2010.       if (image->runlength != 0)
  2011.         image->runlength--;
  2012.       else
  2013.         {
  2014.           p++;
  2015.           image->runlength=p->length;
  2016.         }
  2017.       *q=(*p);
  2018.       q->length=0;
  2019.       q++;
  2020.     }
  2021.     *q++=black;
  2022.     for (x=0; x < (bevel_width-1); x++)
  2023.       *q++=highlight;
  2024.     width=frame_info->width-frame_info->x-image->columns-(bevel_width << 1);
  2025.     for (x=0; x < width; x++)
  2026.       *q++=matte;
  2027.     for (x=0; x < (bevel_width-1); x++)
  2028.       *q++=shadow;
  2029.     *q++=black;
  2030.   }
  2031.   *q++=black;
  2032.   for (x=0; x < (bevel_width-1); x++)
  2033.     *q++=highlight;
  2034.   for (x=0; x < (frame_info->x-(bevel_width << 1)); x++)
  2035.     *q++=matte;
  2036.   for (x=0; x < (bevel_width-1); x++)
  2037.     *q++=shadow;
  2038.   for (x=0; x < (image->columns+2); x++)
  2039.     *q++=black;
  2040.   for (x=0; x < (bevel_width-1); x++)
  2041.     *q++=highlight;
  2042.   width=frame_info->width-frame_info->x-image->columns-(bevel_width << 1);
  2043.   for (x=0; x < width; x++)
  2044.     *q++=matte;
  2045.   for (x=0; x < (bevel_width-1); x++)
  2046.     *q++=shadow;
  2047.   *q++=black;
  2048.   for (y=bevel_width-2; y >= 0; y--)
  2049.   {
  2050.     *q++=black;
  2051.     for (x=0; x < (bevel_width-1); x++)
  2052.       *q++=highlight;
  2053.     for (x=0; x < (frame_info->x-(bevel_width << 1)); x++)
  2054.       *q++=matte;
  2055.     for (x=0; x < y; x++)
  2056.       *q++=shadow;
  2057.     for ( ; x < (image->columns+(bevel_width << 1)); x++)
  2058.       *q++=highlight;
  2059.     width=frame_info->width-frame_info->x-image->columns-(bevel_width << 1);
  2060.     for (x=0; x < width; x++)
  2061.       *q++=matte;
  2062.     for (x=0; x < (bevel_width-1); x++)
  2063.       *q++=shadow;
  2064.     *q++=black;
  2065.   }
  2066.   height=frame_info->height-frame_info->y-image->rows-(bevel_width << 1);
  2067.   for (y=0; y < height; y++)
  2068.   {
  2069.     *q++=black;
  2070.     for (x=0; x < (bevel_width-1); x++)
  2071.       *q++=highlight;
  2072.     for (x=0; x < (framed_image->columns-(bevel_width << 1)); x++)
  2073.       *q++=matte;
  2074.     for (x=0; x < (bevel_width-1); x++)
  2075.       *q++=shadow;
  2076.     *q++=black;
  2077.   }
  2078.   for (y=bevel_width-2; y >= 0; y--)
  2079.   {
  2080.     *q++=black;
  2081.     for (x=0; x < y; x++)
  2082.       *q++=highlight;
  2083.     for ( ; x < (framed_image->columns-2); x++)
  2084.       *q++=shadow;
  2085.     *q++=black;
  2086.   }
  2087.   for (x=0; x < framed_image->columns; x++)
  2088.     *q++=black;
  2089.   return(framed_image);
  2090. }
  2091.  
  2092. /*
  2093. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2094. %                                                                             %
  2095. %                                                                             %
  2096. %     G a m m a I m a g e                                                     %
  2097. %                                                                             %
  2098. %                                                                             %
  2099. %                                                                             %
  2100. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2101. %
  2102. %  Procedure GammaImage converts the reference image to gamma corrected colors.
  2103. %
  2104. %  The format of the GammaImage routine is:
  2105. %
  2106. %      GammaImage(image,gamma)
  2107. %
  2108. %  A description of each parameter follows:
  2109. %
  2110. %    o image: The address of a structure of type Image;  returned from
  2111. %      ReadImage.
  2112. %
  2113. %    o gamma: A character string indicating the level of gamma correction.
  2114. %
  2115. %
  2116. */
  2117. void GammaImage(image,gamma)
  2118. Image
  2119.   *image;
  2120.  
  2121. char
  2122.   *gamma;
  2123. {
  2124.   float
  2125.     blue_gamma,
  2126.     green_gamma,
  2127.     red_gamma;
  2128.  
  2129.   int
  2130.     count;
  2131.  
  2132.   register int
  2133.     i;
  2134.  
  2135.   register RunlengthPacket
  2136.     *p;
  2137.  
  2138.   unsigned char
  2139.     *red_map,
  2140.     *green_map,
  2141.     *blue_map;
  2142.  
  2143.   /*
  2144.     Allocate and initialize image label.
  2145.   */
  2146.   red_map=(unsigned char *) malloc((MaxRGB+1)*sizeof(unsigned char));
  2147.   green_map=(unsigned char *) malloc((MaxRGB+1)*sizeof(unsigned char));
  2148.   blue_map=(unsigned char *) malloc((MaxRGB+1)*sizeof(unsigned char));
  2149.   if ((red_map == (unsigned char *) NULL) ||
  2150.       (green_map == (unsigned char *) NULL) ||
  2151.       (blue_map == (unsigned char *) NULL))
  2152.     {
  2153.       Warning("Unable to gamma image","Memory allocation failed");
  2154.       return;
  2155.     }
  2156.   for (i=0; i <= MaxRGB; i++)
  2157.   {
  2158.     red_map[i]=0;
  2159.     green_map[i]=0;
  2160.     blue_map[i]=0;
  2161.   }
  2162.   /*
  2163.     Initialize gamma table.
  2164.   */
  2165.   red_gamma=1.0;
  2166.   green_gamma=1.0;
  2167.   blue_gamma=1.0;
  2168.   count=sscanf(gamma,"%f,%f,%f",&red_gamma,&green_gamma,&blue_gamma);
  2169.   if (count == 1)
  2170.     {
  2171.       green_gamma=red_gamma;
  2172.       blue_gamma=red_gamma;
  2173.     }
  2174.   for (i=0; i <= MaxRGB; i++)
  2175.   {
  2176.     if (red_gamma != 0.0)
  2177.       red_map[i]=(unsigned char)
  2178.         ((pow((double) i/MaxRGB,(double) 1.0/red_gamma)*MaxRGB)+0.5);
  2179.     if (green_gamma != 0.0)
  2180.       green_map[i]=(unsigned char)
  2181.         ((pow((double) i/MaxRGB,(double) 1.0/green_gamma)*MaxRGB)+0.5);
  2182.     if (blue_gamma != 0.0)
  2183.       blue_map[i]=(unsigned char)
  2184.         ((pow((double) i/MaxRGB,(double) 1.0/blue_gamma)*MaxRGB)+0.5);
  2185.   }
  2186.   switch (image->class)
  2187.   {
  2188.     case DirectClass:
  2189.     {
  2190.       /*
  2191.         Gamma-correct DirectClass image.
  2192.       */
  2193.       p=image->pixels;
  2194.       for (i=0; i < image->packets; i++)
  2195.       {
  2196.         p->red=red_map[p->red];
  2197.         p->green=green_map[p->green];
  2198.         p->blue=blue_map[p->blue];
  2199.         p++;
  2200.       }
  2201.       break;
  2202.     }
  2203.     case PseudoClass:
  2204.     {
  2205.       /*
  2206.         Gamma-correct PseudoClass image.
  2207.       */
  2208.       for (i=0; i < image->colors; i++)
  2209.       {
  2210.         image->colormap[i].red=red_map[image->colormap[i].red];
  2211.         image->colormap[i].green=green_map[image->colormap[i].green];
  2212.         image->colormap[i].blue=blue_map[image->colormap[i].blue];
  2213.       }
  2214.       SyncImage(image);
  2215.       break;
  2216.     }
  2217.   }
  2218.   (void) free((char *) blue_map);
  2219.   (void) free((char *) green_map);
  2220.   (void) free((char *) red_map);
  2221. }
  2222.  
  2223. /*
  2224. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2225. %                                                                             %
  2226. %                                                                             %
  2227. %                                                                             %
  2228. %   G e t I m a g e I n f o                                                   %
  2229. %                                                                             %
  2230. %                                                                             %
  2231. %                                                                             %
  2232. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2233. %
  2234. %  Function GetImageInfo initializes the ImageInfo structure.
  2235. %
  2236. %  The format of the GetImageInfo routine is:
  2237. %
  2238. %      GetImageInfo(filename,image_info)
  2239. %
  2240. %  A description of each parameter follows:
  2241. %
  2242. %    o filename: A character string containing a name of the file to
  2243. %      associate with the ImageInfo structure.
  2244. %
  2245. %    o image_info: Specifies a pointer to a ImageInfo structure.
  2246. %
  2247. %
  2248. */
  2249. void GetImageInfo(filename,image_info)
  2250. char
  2251.   *filename;
  2252.  
  2253. ImageInfo
  2254.   *image_info;
  2255. {
  2256.   *image_info->filename='\0';
  2257.   if (filename != (char *) NULL)
  2258.     (void) strcpy(image_info->filename,filename);
  2259.   image_info->assert=False;
  2260.   image_info->server_name=(char *) NULL;
  2261.   image_info->font=(char *) NULL;
  2262.   image_info->geometry=(char *) NULL;
  2263.   image_info->density=(char *) NULL;
  2264.   image_info->page=(char *) NULL;
  2265.   image_info->interlace=NoneInterlace;
  2266.   image_info->monochrome=False;
  2267.   image_info->quality=85;
  2268.   image_info->verbose=False;
  2269.   image_info->undercolor=(char *) NULL;
  2270. }
  2271.  
  2272. /*
  2273. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2274. %                                                                             %
  2275. %                                                                             %
  2276. %     I n v e r s e I m a g e                                                 %
  2277. %                                                                             %
  2278. %                                                                             %
  2279. %                                                                             %
  2280. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2281. %
  2282. %  Procedure InverseImage inverses the colors in the reference image.
  2283. %
  2284. %  The format of the InverseImage routine is:
  2285. %
  2286. %      InverseImage(image)
  2287. %
  2288. %  A description of each parameter follows:
  2289. %
  2290. %    o image: The address of a structure of type Image;  returned from
  2291. %      ReadImage.
  2292. %
  2293. %
  2294. */
  2295. void InverseImage(image)
  2296. Image
  2297.   *image;
  2298. {
  2299.   register int
  2300.     i;
  2301.  
  2302.   register RunlengthPacket
  2303.     *p;
  2304.  
  2305.   switch (image->class)
  2306.   {
  2307.     case DirectClass:
  2308.     {
  2309.       /*
  2310.         Inverse DirectClass packets.
  2311.       */
  2312.       p=image->pixels;
  2313.       for (i=0; i < image->packets; i++)
  2314.       {
  2315.         p->red=(~p->red);
  2316.         p->green=(~p->green);
  2317.         p->blue=(~p->blue);
  2318.         p++;
  2319.       }
  2320.       break;
  2321.     }
  2322.     case PseudoClass:
  2323.     {
  2324.       /*
  2325.         Inverse PseudoClass packets.
  2326.       */
  2327.       for (i=0; i < image->colors; i++)
  2328.       {
  2329.         image->colormap[i].red=(~image->colormap[i].red);
  2330.         image->colormap[i].green=(~image->colormap[i].green);
  2331.         image->colormap[i].blue=(~image->colormap[i].blue);
  2332.       }
  2333.       SyncImage(image);
  2334.       break;
  2335.     }
  2336.   }
  2337. }
  2338.  
  2339. /*
  2340. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2341. %                                                                             %
  2342. %                                                                             %
  2343. %     I s G r a y I m a g e                                                   %
  2344. %                                                                             %
  2345. %                                                                             %
  2346. %                                                                             %
  2347. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2348. %
  2349. %  Function IsGrayImage returns True if the image is grayscale otherwise
  2350. %  False is returned.
  2351. %
  2352. %  The format of the IsGrayImage routine is:
  2353. %
  2354. %      status=IsGrayImage(image)
  2355. %
  2356. %  A description of each parameter follows:
  2357. %
  2358. %    o status: Function IsGrayImage returns True if the image is grayscale
  2359. %      otherwise False is returned.
  2360. %
  2361. %    o image: The address of a structure of type Image;  returned from
  2362. %      ReadImage.
  2363. %
  2364. %
  2365. */
  2366. unsigned int IsGrayImage(image)
  2367. Image
  2368.   *image;
  2369. {
  2370.   register int
  2371.     i;
  2372.  
  2373.   unsigned int
  2374.     grayscale;
  2375.  
  2376.   if ((image->class == DirectClass) || (image->colors > 256))
  2377.     return(False);
  2378.   else
  2379.     {
  2380.       /*
  2381.         Determine if image is grayscale.
  2382.       */
  2383.       grayscale=True;
  2384.       for (i=0; i < image->colors; i++)
  2385.         if ((image->colormap[i].red != image->colormap[i].green) ||
  2386.             (image->colormap[i].green != image->colormap[i].blue))
  2387.           {
  2388.             grayscale=False;
  2389.             break;
  2390.           }
  2391.       return(grayscale);
  2392.     }
  2393. }
  2394.  
  2395. /*
  2396. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2397. %                                                                             %
  2398. %                                                                             %
  2399. %                                                                             %
  2400. %   L a b e l I m a g e                                                       %
  2401. %                                                                             %
  2402. %                                                                             %
  2403. %                                                                             %
  2404. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2405. %
  2406. %  Function LabelImage initializes an image label.  Optionally the label
  2407. %  can include the image filename, type, width, height, or scene number by
  2408. %  embedding special format characters.  Embed %f for filename, %m for
  2409. %  magick, %w for width, %h for height, or %s for scene number.  For
  2410. %  example,
  2411. %
  2412. %     %f  %wx%h
  2413. %
  2414. %  produces an image label of
  2415. %
  2416. %     bird.miff  512x480
  2417. %
  2418. %  for an image titled bird.miff and whose width is 512 and height is 480.
  2419. %
  2420. %  The format of the LabelImage routine is:
  2421. %
  2422. %      LabelImage(image,label)
  2423. %
  2424. %  A description of each parameter follows:
  2425. %
  2426. %    o image: The address of a structure of type Image.
  2427. %
  2428. %    o label: The address of a character string containing the label format.
  2429. %
  2430. %
  2431. */
  2432. void LabelImage(image,label)
  2433. Image
  2434.   *image;
  2435.  
  2436. char
  2437.   *label;
  2438. {
  2439.   register char
  2440.     *p,
  2441.     *q;
  2442.  
  2443.   unsigned int
  2444.     length;
  2445.  
  2446.   if (image->label != (char *) NULL)
  2447.     (void) free((char *) image->label);
  2448.   image->label=(char *) NULL;
  2449.   if (label == (char *) NULL)
  2450.     return;
  2451.   if (*label == '@')
  2452.     {
  2453.       FILE
  2454.         *file;
  2455.  
  2456.       int
  2457.         c;
  2458.  
  2459.       /*
  2460.         Read label from a file.
  2461.       */
  2462.       file=(FILE *) fopen(label+1,"r");
  2463.       if (file == (FILE *) NULL)
  2464.         {
  2465.           Warning("Unable to read label file",label+1);
  2466.           return;
  2467.         }
  2468.       length=MaxTextLength;
  2469.       label=(char *) malloc(length*sizeof(char));
  2470.       for (q=label ; label != (char *) NULL; q++)
  2471.       {
  2472.         c=fgetc(file);
  2473.         if (c == EOF)
  2474.           break;
  2475.         if ((q-label+1) >= length)
  2476.           {
  2477.             length<<=1;
  2478.             label=(char *) realloc((char *) label,length*sizeof(char));
  2479.             if (label == (char *) NULL)
  2480.               break;
  2481.             q=label+strlen(label);
  2482.           }
  2483.         *q=(unsigned char) c;
  2484.       }
  2485.       (void) fclose(file);
  2486.       if (label == (char *) NULL)
  2487.         {
  2488.           Warning("Unable to label image","Memory allocation failed");
  2489.           return;
  2490.         }
  2491.       *q='\0';
  2492.     }
  2493.   /*
  2494.     Allocate and initialize image label.
  2495.   */
  2496.   p=label;
  2497.   length=strlen(label)+MaxTextLength;
  2498.   image->label=(char *) malloc(length*sizeof(char));
  2499.   for (q=image->label; image->label != (char *) NULL; q++)
  2500.   {
  2501.     if (*p == '\0')
  2502.       break;
  2503.     *q='\0';
  2504.     if ((q-image->label+MaxTextLength) >= length)
  2505.       {
  2506.         length<<=1;
  2507.         image->label=(char *)
  2508.           realloc((char *) image->label,length*sizeof(char));
  2509.         if (image->label == (char *) NULL)
  2510.           break;
  2511.         q=image->label+strlen(image->label)-1;
  2512.       }
  2513.     /*
  2514.       Process formatting characters in label.
  2515.     */
  2516.     if (*p != '%')
  2517.       {
  2518.         *q=(*p++);
  2519.         continue;
  2520.       }
  2521.     p++;
  2522.     switch (*p)
  2523.     {
  2524.       case 'f':
  2525.       {
  2526.         register char
  2527.           *p;
  2528.  
  2529.         /*
  2530.           Label segment is the base of the filename.
  2531.         */
  2532.         p=image->filename+strlen(image->filename)-1;
  2533.         while ((p > image->filename) && (*(p-1) != '/'))
  2534.           p--;
  2535.         (void) strcpy(q,p);
  2536.         break;
  2537.       }
  2538.       case 'h':
  2539.       {
  2540.         (void) sprintf(q,"%u",image->rows);
  2541.         break;
  2542.       }
  2543.       case 'm':
  2544.       {
  2545.         (void) strcpy(q,image->magick);
  2546.         break;
  2547.       }
  2548.       case 's':
  2549.       {
  2550.         (void) sprintf(q,"%u",image->scene);
  2551.         break;
  2552.       }
  2553.       case 'w':
  2554.       {
  2555.         (void) sprintf(q,"%u",image->columns);
  2556.         break;
  2557.       }
  2558.       default:
  2559.       {
  2560.         *q++='%';
  2561.         *q++=(*p);
  2562.         *q++='\0';
  2563.         break;
  2564.       }
  2565.     }
  2566.     p++;
  2567.     q=image->label+strlen(image->label)-1;
  2568.   }
  2569.   if (image->label == (char *) NULL)
  2570.     {
  2571.       Warning("Unable to label image","Memory allocation failed");
  2572.       return;
  2573.     }
  2574.   *q='\0';
  2575. }
  2576.  
  2577. /*
  2578. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2579. %                                                                             %
  2580. %                                                                             %
  2581. %     N o i s y I m a g e                                                     %
  2582. %                                                                             %
  2583. %                                                                             %
  2584. %                                                                             %
  2585. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2586. %
  2587. %  Function NoisyImage creates a new image that is a copy of an existing
  2588. %  one with the noise reduced with a noise peak elimination filter.  It
  2589. %  allocates the memory necessary for the new Image structure and returns a
  2590. %  pointer to the new image.
  2591. %
  2592. %  The principal function of noise peak elimination filter is to smooth the
  2593. %  objects within an image without losing edge information and without
  2594. %  creating undesired structures.  The central idea of the algorithm is to
  2595. %  replace a pixel with its next neighbor in value within a 3 x 3 window,
  2596. %  if this pixel has been found to be noise.  A pixel is defined as noise
  2597. %  if and only if this pixel is a maximum or minimum within the 3 x 3
  2598. %  window.
  2599. %
  2600. %  The format of the NoisyImage routine is:
  2601. %
  2602. %      noisy_image=NoisyImage(image)
  2603. %
  2604. %  A description of each parameter follows:
  2605. %
  2606. %    o noisy_image: Function NoisyImage returns a pointer to the image after
  2607. %      the noise is reduced.  A null image is returned if there is a memory
  2608. %      shortage.
  2609. %
  2610. %    o image: The address of a structure of type Image;  returned from
  2611. %      ReadImage.
  2612. %
  2613. %
  2614. */
  2615. static int NoisyCompare(x,y)
  2616. const void
  2617.   *x,
  2618.   *y;
  2619. {
  2620.   ColorPacket
  2621.     *color_1,
  2622.     *color_2;
  2623.  
  2624.   color_1=(ColorPacket *) x;
  2625.   color_2=(ColorPacket *) y;
  2626.   return((int) Intensity(*color_1)-(int) Intensity(*color_2));
  2627. }
  2628.  
  2629. Image *NoisyImage(image)
  2630. Image
  2631.   *image;
  2632. {
  2633.   Image
  2634.     *noisy_image;
  2635.  
  2636.   int
  2637.     i;
  2638.  
  2639.   register RunlengthPacket
  2640.     *p,
  2641.     *q,
  2642.     *s,
  2643.     *s0,
  2644.     *s1,
  2645.     *s2;
  2646.  
  2647.   register unsigned int
  2648.     x;
  2649.  
  2650.   RunlengthPacket
  2651.     pixel,
  2652.     *scanline,
  2653.     window[9];
  2654.  
  2655.   unsigned int
  2656.     y;
  2657.  
  2658.   if ((image->columns < 3) || (image->rows < 3))
  2659.     {
  2660.       Warning("Unable to reduce noise","the image size must exceed 2x2");
  2661.       return((Image *) NULL);
  2662.     }
  2663.   /*
  2664.     Initialize noisy image attributes.
  2665.   */
  2666.   noisy_image=CopyImage(image,image->columns,image->rows,False);
  2667.   if (noisy_image == (Image *) NULL)
  2668.     {
  2669.       Warning("Unable to reduce noise","Memory allocation failed");
  2670.       return((Image *) NULL);
  2671.     }
  2672.   /*
  2673.     Allocate scanline buffer for 3 rows of the image.
  2674.   */
  2675.   scanline=(RunlengthPacket *) malloc(3*image->columns*sizeof(RunlengthPacket));
  2676.   if (scanline == (RunlengthPacket *) NULL)
  2677.     {
  2678.       Warning("Unable to reduce noise","Memory allocation failed");
  2679.       DestroyImage(noisy_image);
  2680.       return((Image *) NULL);
  2681.     }
  2682.   /*
  2683.     Preload the first 2 rows of the image.
  2684.   */
  2685.   p=image->pixels;
  2686.   image->runlength=p->length+1;
  2687.   s=scanline;
  2688.   for (x=0; x < (image->columns << 1); x++)
  2689.   {
  2690.     if (image->runlength != 0)
  2691.       image->runlength--;
  2692.     else
  2693.       {
  2694.         p++;
  2695.         image->runlength=p->length;
  2696.       }
  2697.     *s=(*p);
  2698.     s++;
  2699.   }
  2700.   /*
  2701.     Dump first scanline of image.
  2702.   */
  2703.   q=noisy_image->pixels;
  2704.   s=scanline;
  2705.   for (x=0; x < image->columns; x++)
  2706.   {
  2707.     *q=(*s);
  2708.     q->length=0;
  2709.     q++;
  2710.     s++;
  2711.   }
  2712.   /*
  2713.     Reduce noise in each row.
  2714.   */
  2715.   for (y=1; y < (image->rows-1); y++)
  2716.   {
  2717.     /*
  2718.       Initialize sliding window pointers.
  2719.     */
  2720.     s0=scanline+image->columns*((y-1) % 3);
  2721.     s1=scanline+image->columns*(y % 3);
  2722.     s2=scanline+image->columns*((y+1) % 3);
  2723.     /*
  2724.       Read another scan line.
  2725.     */
  2726.     s=s2;
  2727.     for (x=0; x < image->columns; x++)
  2728.     {
  2729.       if (image->runlength != 0)
  2730.         image->runlength--;
  2731.       else
  2732.         {
  2733.           p++;
  2734.           image->runlength=p->length;
  2735.         }
  2736.       *s=(*p);
  2737.       s++;
  2738.     }
  2739.     /*
  2740.       Transfer first pixel of the scanline.
  2741.     */
  2742.     s=s1;
  2743.     *q=(*s);
  2744.     q->length=0;
  2745.     q++;
  2746.     for (x=1; x < (image->columns-1); x++)
  2747.     {
  2748.       /*
  2749.         Sort window pixels by increasing intensity.
  2750.       */
  2751.       s=s0;
  2752.       window[0]=(*s++);
  2753.       window[1]=(*s++);
  2754.       window[2]=(*s++);
  2755.       s=s1;
  2756.       window[3]=(*s++);
  2757.       window[4]=(*s++);
  2758.       window[5]=(*s++);
  2759.       s=s2;
  2760.       window[6]=(*s++);
  2761.       window[7]=(*s++);
  2762.       window[8]=(*s++);
  2763.       pixel=window[4];
  2764.       (void) qsort((void *) window,9,sizeof(RunlengthPacket),NoisyCompare);
  2765.       if (Intensity(pixel) == Intensity(window[0]))
  2766.         {
  2767.           /*
  2768.             Pixel is minimum noise; replace with next neighbor in value.
  2769.           */
  2770.           for (i=1; i < 8; i++)
  2771.             if (Intensity(window[i]) != Intensity(window[0]))
  2772.               break;
  2773.           pixel=window[i];
  2774.         }
  2775.       else
  2776.         if (Intensity(pixel) == Intensity(window[8]))
  2777.           {
  2778.             /*
  2779.               Pixel is maximum noise; replace with next neighbor in value.
  2780.             */
  2781.             for (i=7; i > 0; i--)
  2782.               if (Intensity(window[i]) != Intensity(window[8]))
  2783.                 break;
  2784.             pixel=window[i];
  2785.           }
  2786.       *q=pixel;
  2787.       q->length=0;
  2788.       q++;
  2789.       s0++;
  2790.       s1++;
  2791.       s2++;
  2792.     }
  2793.     /*
  2794.       Transfer last pixel of the scanline.
  2795.     */
  2796.     s=s1;
  2797.     *q=(*s);
  2798.     q->length=0;
  2799.     q++;
  2800.   }
  2801.   /*
  2802.     Dump last scanline of pixels.
  2803.   */
  2804.   s=scanline+image->columns*(y % 3);
  2805.   for (x=0; x < image->columns; x++)
  2806.   {
  2807.     *q=(*s);
  2808.     q->length=0;
  2809.     q++;
  2810.     s++;
  2811.   }
  2812.   (void) free((char *) scanline);
  2813.   return(noisy_image);
  2814. }
  2815.  
  2816. /*
  2817. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2818. %                                                                             %
  2819. %                                                                             %
  2820. %     N o r m a l i z e I m a g e                                             %
  2821. %                                                                             %
  2822. %                                                                             %
  2823. %                                                                             %
  2824. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2825. %
  2826. %  Procedure NormalizeImage normalizes the pixel values to span the full
  2827. %  range of color values.  This is a contrast enhancement technique.
  2828. %
  2829. %  The format of the NormalizeImage routine is:
  2830. %
  2831. %      NormalizeImage(image)
  2832. %
  2833. %  A description of each parameter follows:
  2834. %
  2835. %    o image: The address of a structure of type Image;  returned from
  2836. %      ReadImage.
  2837. %
  2838. %
  2839. */
  2840. void NormalizeImage(image)
  2841. Image
  2842.   *image;
  2843. {
  2844.   int
  2845.     histogram[MaxRGB+1],
  2846.     threshold_intensity;
  2847.  
  2848.   register int
  2849.     i,
  2850.     intensity;
  2851.  
  2852.   register RunlengthPacket
  2853.     *p;
  2854.  
  2855.   unsigned char
  2856.     gray_value,
  2857.     high,
  2858.     low,
  2859.     normalize_map[MaxRGB+1];
  2860.  
  2861.   /*
  2862.     Form histogram.
  2863.   */
  2864.   for (i=0; i <= MaxRGB; i++)
  2865.     histogram[i]=0;
  2866.   p=image->pixels;
  2867.   for (i=0; i < image->packets; i++)
  2868.   {
  2869.     gray_value=Intensity(*p);
  2870.     histogram[gray_value]+=p->length+1;
  2871.     p++;
  2872.   }
  2873.   /*
  2874.     Find the histogram boundaries by locating the 1 percent levels.
  2875.   */
  2876.   threshold_intensity=(image->columns*image->rows)/100;
  2877.   intensity=0;
  2878.   for (low=0; low < MaxRGB; low++)
  2879.   {
  2880.     intensity+=histogram[low];
  2881.     if (intensity > threshold_intensity)
  2882.       break;
  2883.   }
  2884.   intensity=0;
  2885.   for (high=MaxRGB; high != 0; high--)
  2886.   {
  2887.     intensity+=histogram[high];
  2888.     if (intensity > threshold_intensity)
  2889.       break;
  2890.   }
  2891.   if (low == high)
  2892.     {
  2893.       /*
  2894.         Unreasonable contrast;  use zero threshold to determine boundaries.
  2895.       */
  2896.       threshold_intensity=0;
  2897.       intensity=0;
  2898.       for (low=0; low < MaxRGB; low++)
  2899.       {
  2900.         intensity+=histogram[low];
  2901.         if (intensity > threshold_intensity)
  2902.           break;
  2903.       }
  2904.       intensity=0;
  2905.       for (high=MaxRGB; high != 0; high--)
  2906.       {
  2907.         intensity+=histogram[high];
  2908.         if (intensity > threshold_intensity)
  2909.           break;
  2910.       }
  2911.       if (low == high)
  2912.         return;  /* zero span bound */
  2913.     }
  2914.   /*
  2915.     Stretch the histogram to create the normalized image mapping.
  2916.   */
  2917.   for (i=0; i <= MaxRGB; i++)
  2918.     if (i < (int) low)
  2919.       normalize_map[i]=0;
  2920.     else
  2921.       if (i > (int) high)
  2922.         normalize_map[i]=MaxRGB-1;
  2923.       else
  2924.         normalize_map[i]=(MaxRGB-1)*(i-(int) low)/(int) (high-low);
  2925.   /*
  2926.     Normalize the image.
  2927.   */
  2928.   switch (image->class)
  2929.   {
  2930.     case DirectClass:
  2931.     {
  2932.       /*
  2933.         Normalize DirectClass image.
  2934.       */
  2935.       p=image->pixels;
  2936.       for (i=0; i < image->packets; i++)
  2937.       {
  2938.         p->red=normalize_map[p->red];
  2939.         p->green=normalize_map[p->green];
  2940.         p->blue=normalize_map[p->blue];
  2941.         p++;
  2942.       }
  2943.       break;
  2944.     }
  2945.     case PseudoClass:
  2946.     {
  2947.       /*
  2948.         Normalize PseudoClass image.
  2949.       */
  2950.       for (i=0; i < image->colors; i++)
  2951.       {
  2952.         image->colormap[i].red=normalize_map[image->colormap[i].red];
  2953.         image->colormap[i].green=normalize_map[image->colormap[i].green];
  2954.         image->colormap[i].blue=normalize_map[image->colormap[i].blue];
  2955.       }
  2956.       SyncImage(image);
  2957.       break;
  2958.     }
  2959.   }
  2960. }
  2961.  
  2962. /*
  2963. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2964. %                                                                             %
  2965. %                                                                             %
  2966. %                                                                             %
  2967. %   O p e n I m a g e                                                         %
  2968. %                                                                             %
  2969. %                                                                             %
  2970. %                                                                             %
  2971. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  2972. %
  2973. %  Function OpenImage open a file associated with the image.  A file name of
  2974. %  '-' sets the file to stdin for type 'r' and stdout for type 'w'.  If the
  2975. %  filename suffix is '.gz' or '.Z', the image is decompressed for type 'r'
  2976. %  and compressed for type 'w'.  If the filename prefix is '|', it is piped
  2977. %  to or from a system command.
  2978. %
  2979. %  The format of the OpenImage routine is:
  2980. %
  2981. %      OpenImage(image,type)
  2982. %
  2983. %  A description of each parameter follows:
  2984. %
  2985. %    o image: The address of a structure of type Image.
  2986. %
  2987. %    o type: 'r' for reading; 'w' for writing.
  2988. %
  2989. */
  2990. void OpenImage(image,type)
  2991. Image
  2992.   *image;
  2993.  
  2994. char
  2995.   *type;
  2996. {
  2997.   char
  2998.     filename[MaxTextLength];
  2999.  
  3000.   (void) strcpy(filename,image->filename);
  3001.   if (*filename != '|')
  3002.     if (strcmp(filename+strlen(filename)-3,".gz") == 0)
  3003.       {
  3004.         /*
  3005.           Uncompress/compress image file with GNU compress utilities.
  3006.         */
  3007.         if (*type == 'r')
  3008.           (void) sprintf(filename,"|gunzip -f -c %s",image->filename);
  3009.         else
  3010.           (void) sprintf(filename,"|gzip -f -c > %s",image->filename);
  3011.       }
  3012.     else
  3013.       if (strcmp(filename+strlen(filename)-2,".Z") == 0)
  3014.         {
  3015.           /*
  3016.             Uncompress/compress image file with UNIX compress utilities.
  3017.           */
  3018.           if (*type == 'r')
  3019.             (void) sprintf(filename,"|uncompress -c %s",image->filename);
  3020.           else
  3021.             (void) sprintf(filename,"|compress -c > %s",image->filename);
  3022.         }
  3023.   /*
  3024.     Open image file.
  3025.   */
  3026.   image->pipe=False;
  3027.   if (strcmp(filename,"-") == 0)
  3028.     image->file=(*type == 'r') ? stdin : stdout;
  3029.   else
  3030.     if (*filename != '|')
  3031.       {
  3032.         if (*type == 'w')
  3033.           if ((image->previous != (Image *) NULL) ||
  3034.               (image->next != (Image *) NULL))
  3035.             {
  3036.               /*
  3037.                 Form filename for multi-part images.
  3038.               */
  3039.               (void) sprintf(filename,image->filename,image->scene);
  3040.               if (strcmp(filename,image->filename) == 0)
  3041.                 (void) sprintf(filename,"%s.%u",image->filename,image->scene);
  3042.               if (image->next != (Image *) NULL)
  3043.                 (void) strcpy(image->next->magick,image->magick);
  3044.               (void) strcpy(image->filename,filename);
  3045.             }
  3046.         image->file=(FILE *) fopen(filename,type);
  3047.       }
  3048.     else
  3049.       {
  3050.         /*
  3051.           Pipe image to or from a system command.
  3052.         */
  3053.         if (*type == 'w')
  3054.           (void) signal(SIGPIPE,SIG_IGN);
  3055.         image->file=(FILE *) popen(filename+1,type);
  3056.         image->pipe=True;
  3057.       }
  3058.   image->status=False;
  3059. }
  3060.  
  3061. /*
  3062. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3063. %                                                                             %
  3064. %                                                                             %
  3065. %                                                                             %
  3066. %   P a r s e I m a g e G e o m e t r y                                       %
  3067. %                                                                             %
  3068. %                                                                             %
  3069. %                                                                             %
  3070. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3071. %
  3072. %  Function ParseImageGeometry parse a geometry specification and returns the
  3073. %  width and height values.
  3074. %
  3075. %  The format of the ParseImageGeometry routine is:
  3076. %
  3077. %      ParseImageGeometry(image_geometry,width,height)
  3078. %
  3079. %  A description of each parameter follows:
  3080. %
  3081. %    o image_geometry:  Specifies a character string representing the geometry
  3082. %      specification.
  3083. %
  3084. %    o width:  A pointer to an unsigned integer.  The width as determined by
  3085. %      the geometry specification is returned here.
  3086. %
  3087. %    o height:  A pointer to an unsigned integer.  The height as determined by
  3088. %      the geometry specification is returned here.
  3089. %
  3090. %
  3091. */
  3092. void ParseImageGeometry(image_geometry,width,height)
  3093. char
  3094.   *image_geometry;
  3095.  
  3096. unsigned int
  3097.   *width,
  3098.   *height;
  3099. {
  3100.   char
  3101.     geometry[MaxTextLength];
  3102.  
  3103.   int
  3104.     flags,
  3105.     x,
  3106.     y;
  3107.  
  3108.   register char
  3109.     *p;
  3110.  
  3111.   unsigned int
  3112.     aspect_ratio,
  3113.     former_height,
  3114.     former_width,
  3115.     percentage;
  3116.  
  3117.   unsigned long
  3118.     scale_factor;
  3119.  
  3120.   if (image_geometry == (char *) NULL)
  3121.     return;
  3122.   /*
  3123.     Remove whitespaces and % and ~ characters from geometry specification.
  3124.   */
  3125.   (void) strcpy(geometry,image_geometry);
  3126.   aspect_ratio=True;
  3127.   percentage=False;
  3128.   p=geometry;
  3129.   while ((int) strlen(p) > 0)
  3130.   {
  3131.     if (isspace(*p))
  3132.       (void) strcpy(p,p+1);
  3133.     else
  3134.       if (*p == '%')
  3135.         {
  3136.           percentage=True;
  3137.           (void) strcpy(p,p+1);
  3138.         }
  3139.       else
  3140.         if (*p == '!')
  3141.           {
  3142.             aspect_ratio=False;
  3143.             (void) strcpy(p,p+1);
  3144.           }
  3145.         else
  3146.           p++;
  3147.   }
  3148.   /*
  3149.     Parse geometry using XParseGeometry.
  3150.   */
  3151.   former_width=(*width);
  3152.   former_height=(*height);
  3153.   flags=XParseGeometry(geometry,&x,&y,width,height);
  3154.   if (((flags & WidthValue) != 0) && (flags & HeightValue) == 0)
  3155.     *height=(*width);
  3156.   if (percentage)
  3157.     {
  3158.       /*
  3159.         Geometry is a percentage of the image size.
  3160.       */
  3161.       *width=(former_width*(*width))/100;
  3162.       *height=(former_height*(*height))/100;
  3163.       former_width=(*width);
  3164.       former_height=(*height);
  3165.     }
  3166.   if (aspect_ratio)
  3167.     {
  3168.       /*
  3169.         Respect aspect ratio of the image.
  3170.       */
  3171.       scale_factor=UpShift(*width)/former_width;
  3172.       if (scale_factor > (UpShift(*height)/former_height))
  3173.         scale_factor=UpShift(*height)/former_height;
  3174.       *width=DownShift(former_width*scale_factor);
  3175.       *height=DownShift(former_height*scale_factor);
  3176.     }
  3177. }
  3178.  
  3179. /*
  3180. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3181. %                                                                             %
  3182. %                                                                             %
  3183. %                                                                             %
  3184. %   R e d u c e I m a g e                                                     %
  3185. %                                                                             %
  3186. %                                                                             %
  3187. %                                                                             %
  3188. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3189. %
  3190. %  Function ReduceImage creates a new image that is a integral size less than
  3191. %  an existing one.  It allocates the memory necessary for the new Image
  3192. %  structure and returns a pointer to the new image.
  3193. %
  3194. %  ReduceImage scans the reference image to create a reduced image by computing
  3195. %  the weighted average of a 4x4 cell centered at each reference pixel.  The
  3196. %  target pixel requires two columns and two rows of the reference pixels.
  3197. %  Therefore the reduced image columns and rows become:
  3198. %
  3199. %    number_columns/2
  3200. %    number_rows/2
  3201. %
  3202. %  Weights assume that the importance of neighboring pixels is inversely
  3203. %  proportional to the square of their distance from the target pixel.
  3204. %
  3205. %  The scan only processes pixels that have a full set of neighbors.  Pixels
  3206. %  in the top, bottom, left, and right pairs of rows and columns are omitted
  3207. %  from the scan.
  3208. %
  3209. %  The format of the ReduceImage routine is:
  3210. %
  3211. %      reduced_image=ReduceImage(image)
  3212. %
  3213. %  A description of each parameter follows:
  3214. %
  3215. %    o reduced_image: Function ReduceImage returns a pointer to the image
  3216. %      after reducing.  A null image is returned if there is a a memory
  3217. %      shortage or if the image size is less than IconSize*2.
  3218. %
  3219. %    o image: The address of a structure of type Image.
  3220. %
  3221. %
  3222. */
  3223. static Image *ReduceImage(image)
  3224. Image
  3225.   *image;
  3226. {
  3227. #define Rsum(weight) \
  3228.   total_red+=weight*(s->red); \
  3229.   total_green+=weight*(s->green); \
  3230.   total_blue+=weight*(s->blue); \
  3231.   total_alpha+=weight*(s->index); \
  3232.   s++;
  3233.  
  3234.   Image
  3235.     *reduced_image;
  3236.  
  3237.   register RunlengthPacket
  3238.     *p,
  3239.     *q,
  3240.     *s,
  3241.     *s0,
  3242.     *s1,
  3243.     *s2,
  3244.     *s3;
  3245.  
  3246.   register unsigned int
  3247.     x;
  3248.  
  3249.   RunlengthPacket
  3250.     *scanline;
  3251.  
  3252.   unsigned int
  3253.     y;
  3254.  
  3255.   unsigned long
  3256.     total_alpha,
  3257.     total_blue,
  3258.     total_green,
  3259.     total_red;
  3260.  
  3261.   if ((image->columns < 4) || (image->rows < 4))
  3262.     {
  3263.       Warning("Unable to reduce image","image size must exceed 3x3");
  3264.       return((Image *) NULL);
  3265.     }
  3266.   /*
  3267.     Initialize reduced image attributes.
  3268.   */
  3269.   reduced_image=CopyImage(image,image->columns >> 1,image->rows >> 1,False);
  3270.   if (reduced_image == (Image *) NULL)
  3271.     {
  3272.       Warning("Unable to reduce image","Memory allocation failed");
  3273.       return((Image *) NULL);
  3274.     }
  3275.   reduced_image->class=DirectClass;
  3276.   /*
  3277.     Allocate image buffer and scanline buffer for 4 rows of the image.
  3278.   */
  3279.   scanline=(RunlengthPacket *)
  3280.     malloc(4*(image->columns+1)*sizeof(RunlengthPacket));
  3281.   if (scanline == (RunlengthPacket *) NULL)
  3282.     {
  3283.       Warning("Unable to reduce image","Memory allocation failed");
  3284.       DestroyImage(reduced_image);
  3285.       return((Image *) NULL);
  3286.     }
  3287.   /*
  3288.     Preload the first 2 rows of the image.
  3289.   */
  3290.   p=image->pixels;
  3291.   image->runlength=p->length+1;
  3292.   s=scanline;
  3293.   for (x=0; x < (image->columns << 1); x++)
  3294.   {
  3295.     if (image->runlength != 0)
  3296.       image->runlength--;
  3297.     else
  3298.       {
  3299.         p++;
  3300.         image->runlength=p->length;
  3301.       }
  3302.     *s=(*p);
  3303.     s++;
  3304.   }
  3305.   /*
  3306.     Reduce each row.
  3307.   */
  3308.   p=image->pixels;
  3309.   image->runlength=p->length+1;
  3310.   q=reduced_image->pixels;
  3311.   for (y=0; y < (image->rows-1); y+=2)
  3312.   {
  3313.     /*
  3314.       Initialize sliding window pointers.
  3315.     */
  3316.     s0=scanline+image->columns*((y+0) % 4);
  3317.     s1=scanline+image->columns*((y+1) % 4);
  3318.     s2=scanline+image->columns*((y+2) % 4);
  3319.     s3=scanline+image->columns*((y+3) % 4);
  3320.     /*
  3321.       Read another scan line.
  3322.     */
  3323.     s=s2;
  3324.     for (x=0; x < image->columns; x++)
  3325.     {
  3326.       if (image->runlength != 0)
  3327.         image->runlength--;
  3328.       else
  3329.         {
  3330.           p++;
  3331.           image->runlength=p->length;
  3332.         }
  3333.       *s=(*p);
  3334.       s++;
  3335.     }
  3336.     /*
  3337.       Read another scan line.
  3338.     */
  3339.     s=s3;
  3340.     for (x=0; x < image->columns; x++)
  3341.     {
  3342.       if (image->runlength != 0)
  3343.         image->runlength--;
  3344.       else
  3345.         {
  3346.           p++;
  3347.           image->runlength=p->length;
  3348.         }
  3349.       *s=(*p);
  3350.       s++;
  3351.     }
  3352.     for (x=0; x < (image->columns-1); x+=2)
  3353.     {
  3354.       /*
  3355.         Compute weighted average of target pixel color components.
  3356.  
  3357.         These particular coefficients total to 128.  Use 128/2-1 or 63 to
  3358.         insure correct round off.
  3359.       */
  3360.       total_red=0;
  3361.       total_green=0;
  3362.       total_blue=0;
  3363.       total_alpha=0;
  3364.       s=s0;
  3365.       Rsum(3); Rsum(7);  Rsum(7);  Rsum(3);
  3366.       s=s1;
  3367.       Rsum(7); Rsum(15); Rsum(15); Rsum(7);
  3368.       s=s2;
  3369.       Rsum(7); Rsum(15); Rsum(15); Rsum(7);
  3370.       s=s3;
  3371.       Rsum(3); Rsum(7);  Rsum(7);  Rsum(3);
  3372.       s0+=2;
  3373.       s1+=2;
  3374.       s2+=2;
  3375.       s3+=2;
  3376.       q->red=(unsigned char) ((total_red+63) >> 7);
  3377.       q->green=(unsigned char) ((total_green+63) >> 7);
  3378.       q->blue=(unsigned char) ((total_blue+63) >> 7);
  3379.       q->index=(unsigned char) ((total_alpha+63) >> 7);
  3380.       q->length=0;
  3381.       q++;
  3382.     }
  3383.   }
  3384.   (void) free((char *) scanline);
  3385.   return(reduced_image);
  3386. }
  3387.  
  3388. /*
  3389. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3390. %                                                                             %
  3391. %                                                                             %
  3392. %                                                                             %
  3393. %   R e f l e c t I m a g e                                                   %
  3394. %                                                                             %
  3395. %                                                                             %
  3396. %                                                                             %
  3397. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3398. %
  3399. %  Function ReflectImage creates a new image that refelects each scanline of an
  3400. %  existing one.  It allocates the memory necessary for the new Image structure
  3401. %  and returns a pointer to the new image.
  3402. %
  3403. %  The format of the ReflectImage routine is:
  3404. %
  3405. %      reflected_image=ReflectImage(image)
  3406. %
  3407. %  A description of each parameter follows:
  3408. %
  3409. %    o reflected_image: Function ReflectImage returns a pointer to the image
  3410. %      after reflecting.  A null image is returned if there is a memory
  3411. %      shortage.
  3412. %
  3413. %    o image: The address of a structure of type Image.
  3414. %
  3415. %
  3416. */
  3417. Image *ReflectImage(image)
  3418. Image
  3419.   *image;
  3420. {
  3421.   Image
  3422.     *reflected_image;
  3423.  
  3424.   register RunlengthPacket
  3425.     *p,
  3426.     *q,
  3427.     *s;
  3428.  
  3429.   register unsigned int
  3430.     x,
  3431.     y;
  3432.  
  3433.   RunlengthPacket
  3434.     *scanline;
  3435.  
  3436.   /*
  3437.     Initialize reflected image attributes.
  3438.   */
  3439.   reflected_image=CopyImage(image,image->columns,image->rows,False);
  3440.   if (reflected_image == (Image *) NULL)
  3441.     {
  3442.       Warning("Unable to reflect image","Memory allocation failed");
  3443.       return((Image *) NULL);
  3444.     }
  3445.   /*
  3446.     Allocate scan line buffer and column offset buffers.
  3447.   */
  3448.   scanline=(RunlengthPacket *) malloc(image->columns*sizeof(RunlengthPacket));
  3449.   if (scanline == (RunlengthPacket *) NULL)
  3450.     {
  3451.       Warning("Unable to reflect image","Memory allocation failed");
  3452.       DestroyImage(reflected_image);
  3453.       return((Image *) NULL);
  3454.     }
  3455.   /*
  3456.     Reflect each row.
  3457.   */
  3458.   p=image->pixels;
  3459.   image->runlength=p->length+1;
  3460.   q=reflected_image->pixels;
  3461.   for (y=0; y < reflected_image->rows; y++)
  3462.   {
  3463.     /*
  3464.       Read a scan line.
  3465.     */
  3466.     s=scanline;
  3467.     for (x=0; x < image->columns; x++)
  3468.     {
  3469.       if (image->runlength != 0)
  3470.         image->runlength--;
  3471.       else
  3472.         {
  3473.           p++;
  3474.           image->runlength=p->length;
  3475.         }
  3476.       *s=(*p);
  3477.       s++;
  3478.     }
  3479.     /*
  3480.       Reflect each column.
  3481.     */
  3482.     s=scanline+image->columns;
  3483.     for (x=0; x < reflected_image->columns; x++)
  3484.     {
  3485.       s--;
  3486.       *q=(*s);
  3487.       q->length=0;
  3488.       q++;
  3489.     }
  3490.   }
  3491.   (void) free((char *) scanline);
  3492.   return(reflected_image);
  3493. }
  3494.  
  3495. /*
  3496. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3497. %                                                                             %
  3498. %                                                                             %
  3499. %     R G B T r a n s f o r m I m a g e                                       %
  3500. %                                                                             %
  3501. %                                                                             %
  3502. %                                                                             %
  3503. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3504. %
  3505. %  Procedure RGBTransformImage converts the reference image from RGB to
  3506. %  an alternate colorspace.  The transformation matrices are not the standard
  3507. %  ones: the weights are rescaled to normalized the range of the transformed
  3508. %  values to be [0..255].
  3509. %
  3510. %  The format of the RGBTransformImage routine is:
  3511. %
  3512. %      RGBTransformImage(image,colorspace)
  3513. %
  3514. %  A description of each parameter follows:
  3515. %
  3516. %    o image: The address of a structure of type Image;  returned from
  3517. %      ReadImage.
  3518. %
  3519. %    o colorspace: An unsigned integer value that indicates which colorspace
  3520. %      to transform the image.
  3521. %
  3522. %
  3523. */
  3524. void RGBTransformImage(image,colorspace)
  3525. Image
  3526.   *image;
  3527.  
  3528. unsigned int
  3529.   colorspace;
  3530. {
  3531. #define X 0
  3532. #define Y (MaxRGB+1)
  3533. #define Z (MaxRGB+1)*2
  3534.  
  3535.   long
  3536.     tx,
  3537.     ty,
  3538.     tz,
  3539.     *x,
  3540.     *y,
  3541.     *z;
  3542.  
  3543.   register int
  3544.     blue,
  3545.     green,
  3546.     i,
  3547.     red;
  3548.  
  3549.   register RunlengthPacket
  3550.     *p;
  3551.  
  3552.   register unsigned char
  3553.     *range_limit;
  3554.  
  3555.   unsigned char
  3556.     *range_table;
  3557.  
  3558.   if (colorspace == RGBColorspace)
  3559.     return;
  3560.   /*
  3561.     Allocate the tables.
  3562.   */
  3563.   x=(long *) malloc(3*(MaxRGB+1)*sizeof(long));
  3564.   y=(long *) malloc(3*(MaxRGB+1)*sizeof(long));
  3565.   z=(long *) malloc(3*(MaxRGB+1)*sizeof(long));
  3566.   range_table=(unsigned char *) malloc(3*(MaxRGB+1)*sizeof(unsigned char));
  3567.   if ((x == (long *) NULL) || (y == (long *) NULL) ||
  3568.       (z == (long *) NULL) || (range_table == (unsigned char *) NULL))
  3569.     {
  3570.       Warning("Unable to transform color space","Memory allocation failed");
  3571.       return;
  3572.     }
  3573.   /*
  3574.     Pre-compute conversion tables.
  3575.   */
  3576.   for (i=0; i <= MaxRGB; i++)
  3577.   {
  3578.     range_table[i]=0;
  3579.     range_table[i+(MaxRGB+1)]=(unsigned char) i;
  3580.     range_table[i+(MaxRGB+1)*2]=MaxRGB;
  3581.   }
  3582.   range_limit=range_table+(MaxRGB+1);
  3583.   tx=0;
  3584.   ty=0;
  3585.   tz=0;
  3586.   switch (colorspace)
  3587.   {
  3588.     case GRAYColorspace:
  3589.     {
  3590.       /*
  3591.         Initialize GRAY tables:
  3592.  
  3593.           G = 0.29900*R+0.58700*G+0.11400*B
  3594.       */
  3595.       for (i=0; i <= MaxRGB; i++)
  3596.       {
  3597.         x[i+X]=UpShifted(0.29900)*i;
  3598.         y[i+X]=UpShifted(0.58700)*i;
  3599.         z[i+X]=UpShifted(0.11400)*i;
  3600.         x[i+Y]=UpShifted(0.29900)*i;
  3601.         y[i+Y]=UpShifted(0.58700)*i;
  3602.         z[i+Y]=UpShifted(0.11400)*i;
  3603.         x[i+Z]=UpShifted(0.29900)*i;
  3604.         y[i+Z]=UpShifted(0.58700)*i;
  3605.         z[i+Z]=UpShifted(0.11400)*i;
  3606.       }
  3607.       break;
  3608.     }
  3609.     case OHTAColorspace:
  3610.     {
  3611.       /*
  3612.         Initialize OHTA tables:
  3613.  
  3614.           I1 = 0.33333*R+0.33334*G+0.33333*B
  3615.           I2 = 0.50000*R+0.00000*G-0.50000*B
  3616.           I3 =-0.25000*R+0.50000*G-0.25000*B
  3617.  
  3618.         I and Q, normally -0.5 through 0.5, are normalized to the range 0
  3619.         through MaxRGB.
  3620.       */
  3621.       ty=UpShifted((MaxRGB+1) >> 1);
  3622.       tz=UpShifted((MaxRGB+1) >> 1);
  3623.       for (i=0; i <= MaxRGB; i++)
  3624.       {
  3625.         x[i+X]=UpShifted(0.33333)*i;
  3626.         y[i+X]=UpShifted(0.33334)*i;
  3627.         z[i+X]=UpShifted(0.33333)*i;
  3628.         x[i+Y]=UpShifted(0.50000)*i;
  3629.         y[i+Y]=0;
  3630.         z[i+Y]=(-UpShifted(0.50000))*i;
  3631.         x[i+Z]=(-UpShifted(0.25000))*i;
  3632.         y[i+Z]=UpShifted(0.50000)*i;
  3633.         z[i+Z]=(-UpShifted(0.25000))*i;
  3634.       }
  3635.       break;
  3636.     }
  3637.     case XYZColorspace:
  3638.     {
  3639.       /*
  3640.         Initialize XYZ tables:
  3641.  
  3642.           X = 0.61800*R+0.17700*G+0.20500*B
  3643.           Y = 0.29900*R+0.58700*G+0.11400*B
  3644.           Z = 0.00000*R+0.05600*G+0.94400*B
  3645.       */
  3646.       for (i=0; i <= MaxRGB; i++)
  3647.       {
  3648.         x[i+X]=UpShifted(0.61800)*i;
  3649.         y[i+X]=UpShifted(0.17700)*i;
  3650.         z[i+X]=UpShifted(0.20500)*i;
  3651.         x[i+Y]=UpShifted(0.29900)*i;
  3652.         y[i+Y]=UpShifted(0.58700)*i;
  3653.         z[i+Y]=UpShifted(0.11400)*i;
  3654.         x[i+Z]=0;
  3655.         y[i+Z]=UpShifted(0.05600)*i;
  3656.         z[i+Z]=UpShifted(0.94400)*i;
  3657.       }
  3658.       break;
  3659.     }
  3660.     case YCbCrColorspace:
  3661.     {
  3662.       /*
  3663.         Initialize YCbCr tables:
  3664.  
  3665.           Y =  0.29900*R+0.58700*G+0.11400*B
  3666.           Cb= -0.16874*R-0.33126*G+0.50000*B
  3667.           Cr=  0.50000*R-0.41869*G-0.08131*B
  3668.  
  3669.         Cb and Cr, normally -0.5 through 0.5, are normalized to the range 0
  3670.         through MaxRGB.
  3671.       */
  3672.       ty=UpShifted((MaxRGB+1) >> 1);
  3673.       tz=UpShifted((MaxRGB+1) >> 1);
  3674.       for (i=0; i <= MaxRGB; i++)
  3675.       {
  3676.         x[i+X]=UpShifted(0.29900)*i;
  3677.         y[i+X]=UpShifted(0.58700)*i;
  3678.         z[i+X]=UpShifted(0.11400)*i;
  3679.         x[i+Y]=(-UpShifted(0.16874))*i;
  3680.         y[i+Y]=(-UpShifted(0.33126))*i;
  3681.         z[i+Y]=UpShifted(0.50000)*i;
  3682.         x[i+Z]=UpShifted(0.50000)*i;
  3683.         y[i+Z]=(-UpShifted(0.41869))*i;
  3684.         z[i+Z]=(-UpShifted(0.08131))*i;
  3685.       }
  3686.       break;
  3687.     }
  3688.     case YIQColorspace:
  3689.     {
  3690.       /*
  3691.         Initialize YIQ tables:
  3692.  
  3693.           Y = 0.29900*R+0.58700*G+0.11400*B
  3694.           I = 0.50000*R-0.23000*G-0.27000*B
  3695.           Q = 0.20200*R-0.50000*G+0.29800*B
  3696.  
  3697.         I and Q, normally -0.5 through 0.5, are normalized to the range 0
  3698.         through MaxRGB.
  3699.       */
  3700.       ty=UpShifted((MaxRGB+1) >> 1);
  3701.       tz=UpShifted((MaxRGB+1) >> 1);
  3702.       for (i=0; i <= MaxRGB; i++)
  3703.       {
  3704.         x[i+X]=UpShifted(0.29900)*i;
  3705.         y[i+X]=UpShifted(0.58700)*i;
  3706.         z[i+X]=UpShifted(0.11400)*i;
  3707.         x[i+Y]=UpShifted(0.50000)*i;
  3708.         y[i+Y]=(-UpShifted(0.23000))*i;
  3709.         z[i+Y]=(-UpShifted(0.27000))*i;
  3710.         x[i+Z]=UpShifted(0.20200)*i;
  3711.         y[i+Z]=(-UpShifted(0.50000))*i;
  3712.         z[i+Z]=UpShifted(0.29800)*i;
  3713.       }
  3714.       break;
  3715.     }
  3716.     case YUVColorspace:
  3717.     default:
  3718.     {
  3719.       /*
  3720.         Initialize YUV tables:
  3721.  
  3722.           Y =  0.29900*R+0.58700*G+0.11400*B
  3723.           U = -0.14740*R-0.28950*G+0.43690*B
  3724.           V =  0.61500*R-0.51500*G-0.10000*B
  3725.  
  3726.         U and V, normally -0.5 through 0.5, are normalized to the range 0
  3727.         through MaxRGB.  Note that U = 0.493*(B-Y), V = 0.877*(R-Y).
  3728.       */
  3729.       ty=UpShifted((MaxRGB+1) >> 1);
  3730.       tz=UpShifted((MaxRGB+1) >> 1);
  3731.       for (i=0; i <= MaxRGB; i++)
  3732.       {
  3733.         x[i+X]=UpShifted(0.29900)*i;
  3734.         y[i+X]=UpShifted(0.58700)*i;
  3735.         z[i+X]=UpShifted(0.11400)*i;
  3736.         x[i+Y]=(-UpShifted(0.14740))*i;
  3737.         y[i+Y]=(-UpShifted(0.28950))*i;
  3738.         z[i+Y]=UpShifted(0.43690)*i;
  3739.         x[i+Z]=UpShifted(0.61500)*i;
  3740.         y[i+Z]=(-UpShifted(0.51500))*i;
  3741.         z[i+Z]=(-UpShifted(0.10000))*i;
  3742.       }
  3743.       break;
  3744.     }
  3745.   }
  3746.   /*
  3747.     Convert from RGB.
  3748.   */
  3749.   switch (image->class)
  3750.   {
  3751.     case DirectClass:
  3752.     {
  3753.       /*
  3754.         Convert DirectClass image.
  3755.       */
  3756.       p=image->pixels;
  3757.       for (i=0; i < image->packets; i++)
  3758.       {
  3759.         red=p->red;
  3760.         green=p->green;
  3761.         blue=p->blue;
  3762.         p->red=range_limit[DownShift(x[red+X]+y[green+X]+z[blue+X]+tx)];
  3763.         p->green=range_limit[DownShift(x[red+Y]+y[green+Y]+z[blue+Y]+ty)];
  3764.         p->blue=range_limit[DownShift(x[red+Z]+y[green+Z]+z[blue+Z]+tz)];
  3765.         p++;
  3766.       }
  3767.       break;
  3768.     }
  3769.     case PseudoClass:
  3770.     {
  3771.       /*
  3772.         Convert PseudoClass image.
  3773.       */
  3774.       for (i=0; i < image->colors; i++)
  3775.       {
  3776.         red=image->colormap[i].red;
  3777.         green=image->colormap[i].green;
  3778.         blue=image->colormap[i].blue;
  3779.         image->colormap[i].red=
  3780.           range_limit[DownShift(x[red+X]+y[green+X]+z[blue+X]+tx)];
  3781.         image->colormap[i].green=
  3782.           range_limit[DownShift(x[red+Y]+y[green+Y]+z[blue+Y]+ty)];
  3783.         image->colormap[i].blue=
  3784.           range_limit[DownShift(x[red+Z]+y[green+Z]+z[blue+Z]+tz)];
  3785.       }
  3786.       SyncImage(image);
  3787.       break;
  3788.     }
  3789.   }
  3790.   /*
  3791.     Free allocated memory.
  3792.   */
  3793.   (void) free((char *) range_table);
  3794.   (void) free((char *) z);
  3795.   (void) free((char *) y);
  3796.   (void) free((char *) x);
  3797. }
  3798.  
  3799. /*
  3800. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3801. %                                                                             %
  3802. %                                                                             %
  3803. %                                                                             %
  3804. %   R o l l I m a g e                                                         %
  3805. %                                                                             %
  3806. %                                                                             %
  3807. %                                                                             %
  3808. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3809. %
  3810. %  Function RollImage rolls an image vertically and horizontally.  It
  3811. %  allocates the memory necessary for the new Image structure and returns a
  3812. %  pointer to the new image.
  3813. %
  3814. %  The format of the RollImage routine is:
  3815. %
  3816. %      rolled_image=RollImage(image,columns,rows)
  3817. %
  3818. %  A description of each parameter follows:
  3819. %
  3820. %    o rolled_image: Function RollImage returns a pointer to the image after
  3821. %      rolling.  A null image is returned if there is a memory shortage.
  3822. %
  3823. %    o image: The address of a structure of type Image.
  3824. %
  3825. %    o x_offset: An integer that specifies the number of columns to roll
  3826. %      in the horizontal direction.
  3827. %
  3828. %    o y_offset: An integer that specifies the number of rows to roll in the
  3829. %      veritical direction.
  3830. %
  3831. %
  3832. */
  3833. Image *RollImage(image,x_offset,y_offset)
  3834. Image
  3835.   *image;
  3836.  
  3837. int
  3838.   x_offset,
  3839.   y_offset;
  3840. {
  3841.   Image
  3842.     *rolled_image;
  3843.  
  3844.   register RunlengthPacket
  3845.     *p,
  3846.     *q;
  3847.  
  3848.   register unsigned int
  3849.     packets,
  3850.     x;
  3851.  
  3852.   unsigned int
  3853.     y;
  3854.  
  3855.   /*
  3856.     Initialize rolled image attributes.
  3857.   */
  3858.   rolled_image=CopyImage(image,image->columns,image->rows,False);
  3859.   if (rolled_image == (Image *) NULL)
  3860.     {
  3861.       Warning("Unable to roll image","Memory allocation failed");
  3862.       return((Image *) NULL);
  3863.     }
  3864.   /*
  3865.     Roll image.
  3866.   */
  3867.   p=image->pixels;
  3868.   image->runlength=p->length+1;
  3869.   packets=image->columns*image->rows;
  3870.   for (y=0; y < image->rows; y++)
  3871.   {
  3872.     /*
  3873.       Transfer scanline.
  3874.     */
  3875.     for (x=0; x < image->columns; x++)
  3876.     {
  3877.       if (image->runlength != 0)
  3878.         image->runlength--;
  3879.       else
  3880.         {
  3881.           p++;
  3882.           image->runlength=p->length;
  3883.         }
  3884.       q=rolled_image->pixels+(y_offset+y)*image->columns+x+x_offset;
  3885.       if (q < rolled_image->pixels)
  3886.         q+=packets;
  3887.       else
  3888.         if (q >= (rolled_image->pixels+packets))
  3889.           q-=packets;
  3890.       *q=(*p);
  3891.       q->length=0;
  3892.     }
  3893.   }
  3894.   return(rolled_image);
  3895. }
  3896.  
  3897. /*
  3898. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3899. %                                                                             %
  3900. %                                                                             %
  3901. %                                                                             %
  3902. %   S a m p l e I m a g e                                                     %
  3903. %                                                                             %
  3904. %                                                                             %
  3905. %                                                                             %
  3906. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3907. %
  3908. %  Function SampleImage creates a new image that is a scaled size of an
  3909. %  existing one using pixel sampling.  It allocates the memory necessary
  3910. %  for the new Image structure and returns a pointer to the new image.
  3911. %
  3912. %  The format of the SampleImage routine is:
  3913. %
  3914. %      sampled_image=SampleImage(image,columns,rows)
  3915. %
  3916. %  A description of each parameter follows:
  3917. %
  3918. %    o sampled_image: Function SampleImage returns a pointer to the image after
  3919. %      scaling.  A null image is returned if there is a memory shortage.
  3920. %
  3921. %    o image: The address of a structure of type Image.
  3922. %
  3923. %    o columns: An integer that specifies the number of columns in the sampled
  3924. %      image.
  3925. %
  3926. %    o rows: An integer that specifies the number of rows in the sampled
  3927. %      image.
  3928. %
  3929. %
  3930. */
  3931. Image *SampleImage(image,columns,rows)
  3932. Image
  3933.   *image;
  3934.  
  3935. unsigned int
  3936.   columns,
  3937.   rows;
  3938. {
  3939.   Image
  3940.     *sampled_image;
  3941.  
  3942.   register RunlengthPacket
  3943.     *p,
  3944.     *q,
  3945.     *s;
  3946.  
  3947.   register unsigned int
  3948.     x;
  3949.  
  3950.   RunlengthPacket
  3951.     *scanline;
  3952.  
  3953.   unsigned int
  3954.     *x_offset,
  3955.     y,
  3956.     *y_offset;
  3957.  
  3958.   unsigned long
  3959.     sample_factor;
  3960.  
  3961.   if ((columns == 0) || (rows == 0))
  3962.     {
  3963.       Warning("Unable to sample image","image dimensions are zero");
  3964.       return((Image *) NULL);
  3965.     }
  3966.   if ((columns > MaxImageSize) || (rows > MaxImageSize))
  3967.     {
  3968.       Warning("Unable to sample image","image too large");
  3969.       return((Image *) NULL);
  3970.     }
  3971.   /*
  3972.     Initialize sampled image attributes.
  3973.   */
  3974.   sampled_image=CopyImage(image,columns,rows,False);
  3975.   if (sampled_image == (Image *) NULL)
  3976.     {
  3977.       Warning("Unable to sample image","Memory allocation failed");
  3978.       return((Image *) NULL);
  3979.     }
  3980.   /*
  3981.     Allocate scan line buffer and column offset buffers.
  3982.   */
  3983.   scanline=(RunlengthPacket *) malloc(image->columns*sizeof(RunlengthPacket));
  3984.   x_offset=(unsigned int *)
  3985.     malloc(sampled_image->columns*sizeof(unsigned int));
  3986.   y_offset=(unsigned int *) malloc(sampled_image->rows*sizeof(unsigned int));
  3987.   if ((scanline == (RunlengthPacket *) NULL) ||
  3988.       (x_offset == (unsigned int *) NULL) ||
  3989.       (y_offset == (unsigned int *) NULL))
  3990.     {
  3991.       Warning("Unable to sample image","Memory allocation failed");
  3992.       DestroyImage(sampled_image);
  3993.       return((Image *) NULL);
  3994.     }
  3995.   /*
  3996.     Initialize column pixel offsets.
  3997.   */
  3998.   sample_factor=UpShift(image->columns-1)/sampled_image->columns;
  3999.   columns=0;
  4000.   for (x=0; x < sampled_image->columns; x++)
  4001.   {
  4002.     x_offset[x]=DownShift((x+1)*sample_factor)-columns;
  4003.     columns+=x_offset[x];
  4004.   }
  4005.   /*
  4006.     Initialize row pixel offsets.
  4007.   */
  4008.   sample_factor=UpShift(image->rows-1)/sampled_image->rows;
  4009.   rows=0;
  4010.   for (y=0; y < sampled_image->rows; y++)
  4011.   {
  4012.     y_offset[y]=DownShift((y+1)*sample_factor)-rows;
  4013.     rows+=y_offset[y];
  4014.   }
  4015.   /*
  4016.     Preload first scanline.
  4017.   */
  4018.   p=image->pixels;
  4019.   image->runlength=p->length+1;
  4020.   s=scanline;
  4021.   for (x=0; x < image->columns; x++)
  4022.   {
  4023.     if (image->runlength != 0)
  4024.       image->runlength--;
  4025.     else
  4026.       {
  4027.         p++;
  4028.         image->runlength=p->length;
  4029.       }
  4030.     *s=(*p);
  4031.     s++;
  4032.   }
  4033.   /*
  4034.     Sample each row.
  4035.   */
  4036.   q=sampled_image->pixels;
  4037.   for (y=0; y < sampled_image->rows; y++)
  4038.   {
  4039.     /*
  4040.       Sample each column.
  4041.     */
  4042.     s=scanline;
  4043.     for (x=0; x < sampled_image->columns; x++)
  4044.     {
  4045.       *q=(*s);
  4046.       q->length=0;
  4047.       q++;
  4048.       s+=x_offset[x];
  4049.     }
  4050.     if (y_offset[y] != 0)
  4051.       {
  4052.         /*
  4053.           Skip a scan line.
  4054.         */
  4055.         for (x=0; x < (image->columns*(y_offset[y]-1)); x++)
  4056.           if (image->runlength != 0)
  4057.             image->runlength--;
  4058.           else
  4059.             {
  4060.               p++;
  4061.               image->runlength=p->length;
  4062.             }
  4063.         /*
  4064.           Read a scan line.
  4065.         */
  4066.         s=scanline;
  4067.         for (x=0; x < image->columns; x++)
  4068.         {
  4069.           if (image->runlength != 0)
  4070.             image->runlength--;
  4071.           else
  4072.             {
  4073.               p++;
  4074.               image->runlength=p->length;
  4075.             }
  4076.           *s=(*p);
  4077.           s++;
  4078.         }
  4079.       }
  4080.   }
  4081.   (void) free((char *) scanline);
  4082.   (void) free((char *) x_offset);
  4083.   (void) free((char *) y_offset);
  4084.   return(sampled_image);
  4085. }
  4086.  
  4087. /*
  4088. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4089. %                                                                             %
  4090. %                                                                             %
  4091. %                                                                             %
  4092. %   S c a l e I m a g e                                                       %
  4093. %                                                                             %
  4094. %                                                                             %
  4095. %                                                                             %
  4096. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4097. %
  4098. %  Function ScaleImage creates a new image that is a scaled size of an
  4099. %  existing one.  It allocates the memory necessary for the new Image
  4100. %  structure and returns a pointer to the new image.  To scale a scanline
  4101. %  from x pixels to y pixels, each new pixel represents x/y old pixels.  To
  4102. %  read x/y pixels, read (x/y rounded up) pixels but only count the required
  4103. %  fraction of the last old pixel read in your new pixel.  The remainder
  4104. %  of the old pixel will be counted in the next new pixel.
  4105. %
  4106. %  The scaling algorithm was suggested by rjohnson@shell.com and is adapted
  4107. %  from pnmscale(1) of PBMPLUS by Jef Poskanzer.
  4108. %
  4109. %  The format of the ScaleImage routine is:
  4110. %
  4111. %      scaled_image=ScaleImage(image,columns,rows)
  4112. %
  4113. %  A description of each parameter follows:
  4114. %
  4115. %    o scaled_image: Function ScaleImage returns a pointer to the image after
  4116. %      scaling.  A null image is returned if there is a memory shortage.
  4117. %
  4118. %    o image: The address of a structure of type Image.
  4119. %
  4120. %    o columns: An integer that specifies the number of columns in the scaled
  4121. %      image.
  4122. %
  4123. %    o rows: An integer that specifies the number of rows in the scaled
  4124. %      image.
  4125. %
  4126. %
  4127. */
  4128. Image *ScaleImage(image,columns,rows)
  4129. Image
  4130.   *image;
  4131.  
  4132. unsigned int
  4133.   columns,
  4134.   rows;
  4135. {
  4136.   typedef struct ScaledPacket
  4137.   {
  4138.     long
  4139.       red,
  4140.       green,
  4141.       blue,
  4142.       index;
  4143.   } ScaledPacket;
  4144.  
  4145.   Image
  4146.     *scaled_image;
  4147.  
  4148.   int
  4149.     next_row,
  4150.     number_rows;
  4151.  
  4152.   long
  4153.     x_scale,
  4154.     x_span;
  4155.  
  4156.   register RunlengthPacket
  4157.     *p,
  4158.     *q;
  4159.  
  4160.   register ScaledPacket
  4161.     *s,
  4162.     *t;
  4163.  
  4164.   register unsigned int
  4165.     x;
  4166.  
  4167.   ScaledPacket
  4168.     *scaled_scanline,
  4169.     *scanline,
  4170.     *y_vector,
  4171.     *x_vector;
  4172.  
  4173.   unsigned int
  4174.     y;
  4175.  
  4176.   unsigned long
  4177.     blue,
  4178.     green,
  4179.     index,
  4180.     red;
  4181.  
  4182.   if ((columns == 0) || (rows == 0))
  4183.     {
  4184.       Warning("Unable to scale image","image dimensions are zero");
  4185.       return((Image *) NULL);
  4186.     }
  4187.   if ((columns > MaxImageSize) || (rows > MaxImageSize))
  4188.     {
  4189.       Warning("Unable to scale image","image too large");
  4190.       return((Image *) NULL);
  4191.     }
  4192.   /*
  4193.     Initialize scaled image attributes.
  4194.   */
  4195.   scaled_image=CopyImage(image,columns,rows,False);
  4196.   if (scaled_image == (Image *) NULL)
  4197.     {
  4198.       Warning("Unable to scale image","Memory allocation failed");
  4199.       return((Image *) NULL);
  4200.     }
  4201.   scaled_image->class=DirectClass;
  4202.   /*
  4203.     Allocate memory.
  4204.   */
  4205.   x_vector=(ScaledPacket *) malloc(image->columns*sizeof(ScaledPacket));
  4206.   scanline=x_vector;
  4207.   if (scaled_image->rows != image->rows)
  4208.     scanline=(ScaledPacket *) malloc(image->columns*sizeof(ScaledPacket));
  4209.   scaled_scanline=(ScaledPacket *)
  4210.     malloc(scaled_image->columns*sizeof(ScaledPacket));
  4211.   y_vector=(ScaledPacket *) malloc(image->columns*sizeof(ScaledPacket));
  4212.   if ((x_vector == (ScaledPacket *) NULL) ||
  4213.       (scanline == (ScaledPacket *) NULL) ||
  4214.       (scaled_scanline == (ScaledPacket *) NULL) ||
  4215.       (y_vector == (ScaledPacket *) NULL))
  4216.     {
  4217.       Warning("Unable to scale image","Memory allocation failed");
  4218.       DestroyImage(scaled_image);
  4219.       return((Image *) NULL);
  4220.     }
  4221.   /*
  4222.     Scale image.
  4223.   */
  4224.   number_rows=0;
  4225.   next_row=True;
  4226.   x_scale=UpShift(scaled_image->rows)/image->rows;
  4227.   x_span=UpShift(1);
  4228.   for (x=0; x < image->columns; x++)
  4229.   {
  4230.     y_vector[x].red=0;
  4231.     y_vector[x].green=0;
  4232.     y_vector[x].blue=0;
  4233.     y_vector[x].index=0;
  4234.   }
  4235.   p=image->pixels;
  4236.   image->runlength=p->length+1;
  4237.   q=scaled_image->pixels;
  4238.   for (y=0; y < scaled_image->rows; y++)
  4239.   {
  4240.     if (scaled_image->rows == image->rows)
  4241.       for (x=0; x < image->columns; x++)
  4242.       {
  4243.         /*
  4244.           Read a new scanline.
  4245.         */
  4246.         if (image->runlength != 0)
  4247.           image->runlength--;
  4248.         else
  4249.           {
  4250.             p++;
  4251.             image->runlength=p->length;
  4252.           }
  4253.         x_vector[x].red=p->red;
  4254.         x_vector[x].green=p->green;
  4255.         x_vector[x].blue=p->blue;
  4256.         x_vector[x].index=p->index;
  4257.       }
  4258.     else
  4259.       {
  4260.         /*
  4261.           Scale Y direction.
  4262.         */
  4263.         while (x_scale < x_span)
  4264.         {
  4265.           if (next_row && (number_rows < image->rows))
  4266.             {
  4267.               /*
  4268.                 Read a new scanline.
  4269.               */
  4270.               for (x=0; x < image->columns; x++)
  4271.               {
  4272.                 if (image->runlength != 0)
  4273.                   image->runlength--;
  4274.                 else
  4275.                   {
  4276.                     p++;
  4277.                     image->runlength=p->length;
  4278.                   }
  4279.                 x_vector[x].red=p->red;
  4280.                 x_vector[x].green=p->green;
  4281.                 x_vector[x].blue=p->blue;
  4282.                 x_vector[x].index=p->index;
  4283.               }
  4284.               number_rows++;
  4285.             }
  4286.           for (x=0; x < image->columns; x++)
  4287.           {
  4288.             y_vector[x].red+=x_scale*x_vector[x].red;
  4289.             y_vector[x].green+=x_scale*x_vector[x].green;
  4290.             y_vector[x].blue+=x_scale*x_vector[x].blue;
  4291.             y_vector[x].index+=x_scale*x_vector[x].index;
  4292.           }
  4293.           x_span-=x_scale;
  4294.           x_scale=UpShift(scaled_image->rows)/image->rows;
  4295.           next_row=True;
  4296.         }
  4297.         if (next_row && (number_rows < image->rows))
  4298.           {
  4299.             /*
  4300.               Read a new scanline.
  4301.             */
  4302.             for (x=0; x < image->columns; x++)
  4303.             {
  4304.               if (image->runlength != 0)
  4305.                 image->runlength--;
  4306.               else
  4307.                 {
  4308.                   p++;
  4309.                   image->runlength=p->length;
  4310.                 }
  4311.               x_vector[x].red=p->red;
  4312.               x_vector[x].green=p->green;
  4313.               x_vector[x].blue=p->blue;
  4314.               x_vector[x].index=p->index;
  4315.             }
  4316.             number_rows++;
  4317.             next_row=False;
  4318.           }
  4319.         s=scanline;
  4320.         for (x=0; x < image->columns; x++)
  4321.         {
  4322.           red=DownShift(y_vector[x].red+x_span*x_vector[x].red);
  4323.           green=DownShift(y_vector[x].green+x_span*x_vector[x].green);
  4324.           blue=DownShift(y_vector[x].blue+x_span*x_vector[x].blue);
  4325.           index=DownShift(y_vector[x].index+x_span*x_vector[x].index);
  4326.           s->red=red > MaxRGB ? MaxRGB : red;
  4327.           s->green=green > MaxRGB ? MaxRGB : green;
  4328.           s->blue=blue > MaxRGB ? MaxRGB : blue;
  4329.           s->index=index > MaxColormapSize ? MaxColormapSize : index;
  4330.           s++;
  4331.           y_vector[x].red=0;
  4332.           y_vector[x].green=0;
  4333.           y_vector[x].blue=0;
  4334.           y_vector[x].index=0;
  4335.         }
  4336.         x_scale-=x_span;
  4337.         if (x_scale == 0)
  4338.           {
  4339.             x_scale=UpShift(scaled_image->rows)/image->rows;
  4340.             next_row=True;
  4341.           }
  4342.         x_span=UpShift(1);
  4343.       }
  4344.     if (scaled_image->columns == image->columns)
  4345.       {
  4346.         /*
  4347.           Transfer scanline to scaled image.
  4348.         */
  4349.         s=scanline;
  4350.         for (x=0; x < scaled_image->columns; x++)
  4351.         {
  4352.           q->red=(unsigned char) s->red;
  4353.           q->green=(unsigned char) s->green;
  4354.           q->blue=(unsigned char) s->blue;
  4355.           q->index=(unsigned short) s->index;
  4356.           q->length=0;
  4357.           q++;
  4358.           s++;
  4359.         }
  4360.       }
  4361.     else
  4362.       {
  4363.         int
  4364.           next_column;
  4365.  
  4366.         long int
  4367.           y_scale,
  4368.           y_span;
  4369.  
  4370.         /*
  4371.           Scale X direction.
  4372.         */
  4373.         red=0;
  4374.         green=0;
  4375.         blue=0;
  4376.         next_column=False;
  4377.         y_span=UpShift(1);
  4378.         s=scanline;
  4379.         t=scaled_scanline;
  4380.         for (x=0; x < image->columns; x++)
  4381.         {
  4382.           y_scale=UpShift(scaled_image->columns)/image->columns;
  4383.           while (y_scale >= y_span)
  4384.           {
  4385.             if (next_column)
  4386.               {
  4387.                 red=0;
  4388.                 green=0;
  4389.                 blue=0;
  4390.                 index=0;
  4391.                 t++;
  4392.               }
  4393.             red=DownShift(red+y_span*s->red);
  4394.             green=DownShift(green+y_span*s->green);
  4395.             blue=DownShift(blue+y_span*s->blue);
  4396.             index=DownShift(index+y_span*s->index);
  4397.             t->red=red > MaxRGB ? MaxRGB : red;
  4398.             t->green=green > MaxRGB ? MaxRGB : green;
  4399.             t->blue=blue > MaxRGB ? MaxRGB : blue;
  4400.             t->index=index > MaxColormapSize ? MaxColormapSize : index;
  4401.             y_scale-=y_span;
  4402.             y_span=UpShift(1);
  4403.             next_column=True;
  4404.           }
  4405.         if (y_scale > 0)
  4406.           {
  4407.             if (next_column)
  4408.               {
  4409.                 red=0;
  4410.                 green=0;
  4411.                 blue=0;
  4412.                 index=0;
  4413.                 next_column=False;
  4414.                 t++;
  4415.               }
  4416.             red+=y_scale*s->red;
  4417.             green+=y_scale*s->green;
  4418.             blue+=y_scale*s->blue;
  4419.             index+=y_scale*s->index;
  4420.             y_span-=y_scale;
  4421.           }
  4422.         s++;
  4423.       }
  4424.       if (y_span > 0)
  4425.         {
  4426.           s--;
  4427.           red+=y_span*s->red;
  4428.           green+=y_span*s->green;
  4429.           blue+=y_span*s->blue;
  4430.           index+=y_span*s->index;
  4431.         }
  4432.       if (!next_column)
  4433.         {
  4434.           red=DownShift(red);
  4435.           green=DownShift(green);
  4436.           blue=DownShift(blue);
  4437.           index=DownShift(index);
  4438.           t->red=red > MaxRGB ? MaxRGB : red;
  4439.           t->green=green > MaxRGB ? MaxRGB : green;
  4440.           t->blue=blue > MaxRGB ? MaxRGB : blue;
  4441.           t->index=index > MaxRGB ? MaxRGB : index;
  4442.         }
  4443.       /*
  4444.         Transfer scanline to scaled image.
  4445.       */
  4446.       t=scaled_scanline;
  4447.       for (x=0; x < scaled_image->columns; x++)
  4448.       {
  4449.         q->red=(unsigned char) t->red;
  4450.         q->green=(unsigned char) t->green;
  4451.         q->blue=(unsigned char) t->blue;
  4452.         q->index=(unsigned short) t->index;
  4453.         q->length=0;
  4454.         q++;
  4455.         t++;
  4456.       }
  4457.     }
  4458.   }
  4459.   /*
  4460.     Free allocated memory.
  4461.   */
  4462.   (void) free((char *) y_vector);
  4463.   (void) free((char *) scaled_scanline);
  4464.   if (scanline != x_vector)
  4465.     (void) free((char *) scanline);
  4466.   (void) free((char *) x_vector);
  4467.   return(scaled_image);
  4468. }
  4469.  
  4470. /*
  4471. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4472. %                                                                             %
  4473. %                                                                             %
  4474. %                                                                             %
  4475. %   S e t I m a g e M a g i c k                                               %
  4476. %                                                                             %
  4477. %                                                                             %
  4478. %                                                                             %
  4479. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4480. %
  4481. %  Function SetImageMagick initializes the `magick' field of the ImageInfo
  4482. %  structure.  It is set to a type of image format based on the prefix or
  4483. %  suffix of the filename.  For example, `ps:image' returns PS indicating
  4484. %  a Postscript image.  JPEG is returned for this filename: `image.jpg'.
  4485. %  The filename prefix has precedance over the suffix.
  4486. %
  4487. %  The format of the SetImageMagick routine is:
  4488. %
  4489. %      SetImageMagick(image_info)
  4490. %
  4491. %  A description of each parameter follows:
  4492. %
  4493. %    o image_info: Specifies a pointer to a ImageInfo structure.
  4494. %
  4495. %
  4496. */
  4497. void SetImageMagick(image_info)
  4498. ImageInfo
  4499.   *image_info;
  4500. {
  4501.   static char
  4502.     *ImageTypes[]=
  4503.     {
  4504.       "ALPHA",
  4505.       "AVS",
  4506.       "BMP",
  4507.       "CMYK",
  4508.       "EPS",
  4509.       "EPSF",
  4510.       "EPSI",
  4511.       "FAX",
  4512.       "FITS",
  4513.       "GIF",
  4514.       "GIF87",
  4515.       "GRAY",
  4516.       "G3",
  4517.       "HISTOGRAM",
  4518.       "IRIS",
  4519.       "JPEG",
  4520.       "JPG",
  4521.       "MAP",
  4522.       "MIFF",
  4523.       "MTV",
  4524.       "PBM",
  4525.       "PCD",
  4526.       "PCX",
  4527.       "PGM",
  4528.       "PICT",
  4529.       "PM",
  4530.       "PPM",
  4531.       "PNM",
  4532.       "PS",
  4533.       "PS2",
  4534.       "RAS",
  4535.       "RGB",
  4536.       "RLE",
  4537.       "SUN",
  4538.       "TGA",
  4539.       "TEXT",
  4540.       "TIF",
  4541.       "TIFF",
  4542.       "VICAR",
  4543.       "VIFF",
  4544.       "X",
  4545.       "XBM",
  4546.       "XC",
  4547.       "XPM",
  4548.       "XV",
  4549.       "XWD",
  4550.       "YUV",
  4551.       "YUV3",
  4552.       (char *) NULL,
  4553.     };
  4554.  
  4555.   char
  4556.     c,
  4557.     magick[12];
  4558.  
  4559.   register char
  4560.     *p,
  4561.     *q;
  4562.  
  4563.   register int
  4564.     i;
  4565.  
  4566.   /*
  4567.     Look for 'image.format' in filename.
  4568.   */
  4569.   *magick='\0';
  4570.   p=image_info->filename+strlen(image_info->filename)-1;
  4571.   while ((*p != '.') && (p > image_info->filename))
  4572.     p--;
  4573.   if ((strcmp(p,".gz") == 0) || (strcmp(p,".Z") == 0))
  4574.     do
  4575.     {
  4576.       p--;
  4577.     } while ((*p != '.') && (p > image_info->filename));
  4578.   if ((*p == '.') && (strlen(p) < sizeof(magick)))
  4579.     {
  4580.       /*
  4581.         User specified image format.
  4582.       */
  4583.       (void) strcpy(magick,p+1);
  4584.       for (q=magick; *q != '\0'; q++)
  4585.       {
  4586.         if (*q == '.')
  4587.           {
  4588.             *q='\0';
  4589.             break;
  4590.           }
  4591.         c=(*q);
  4592.         if (isascii(c) && islower(c))
  4593.           *q=toupper(c);
  4594.       }
  4595.       for (i=0; ImageTypes[i] != (char *) NULL; i++)
  4596.         if (strcmp(magick,ImageTypes[i]) == 0)
  4597.           {
  4598.             (void) strcpy(image_info->magick,magick);
  4599.             break;
  4600.           }
  4601.     }
  4602.   /*
  4603.     Look for explicit 'format:image' in filename.
  4604.   */
  4605.   p=image_info->filename;
  4606.   while ((*p != ':') && (*p != '\0'))
  4607.     p++;
  4608.   if ((*p == ':') && ((p-image_info->filename) < sizeof(magick)))
  4609.     {
  4610.       /*
  4611.         User specified image format.
  4612.       */
  4613.       (void) strncpy(magick,image_info->filename,p-image_info->filename);
  4614.       magick[p-image_info->filename]='\0';
  4615.       for (q=magick; *q != '\0'; q++)
  4616.       {
  4617.         c=(*q);
  4618.         if (isascii(c) && islower(c))
  4619.           *q=toupper(c);
  4620.       }
  4621.       for (i=0; ImageTypes[i] != (char *) NULL; i++)
  4622.         if (strcmp(magick,ImageTypes[i]) == 0)
  4623.           {
  4624.             /*
  4625.               Strip off image format prefix.
  4626.             */
  4627.             p++;
  4628.             (void) strcpy(image_info->filename,p);
  4629.             (void) strcpy(image_info->magick,magick);
  4630.             image_info->assert=True;
  4631.             break;
  4632.           }
  4633.     }
  4634. }
  4635.  
  4636. /*
  4637. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4638. %                                                                             %
  4639. %                                                                             %
  4640. %                                                                             %
  4641. %   S o r t C o l o r m a p B y I n t e n t s i t y                           %
  4642. %                                                                             %
  4643. %                                                                             %
  4644. %                                                                             %
  4645. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4646. %
  4647. %  Function SortColormapByIntensity sorts the colormap of a PseudoClass image
  4648. %  by decreasing color intensity.
  4649. %
  4650. %  The format of the SortColormapByIntensity routine is:
  4651. %
  4652. %      SortColormapByIntensity(image)
  4653. %
  4654. %  A description of each parameter follows:
  4655. %
  4656. %    o image: A pointer to a Image structure.
  4657. %
  4658. %
  4659. */
  4660. static int IntensityCompare(x,y)
  4661. const void
  4662.   *x,
  4663.   *y;
  4664. {
  4665.   ColorPacket
  4666.     *color_1,
  4667.     *color_2;
  4668.  
  4669.   color_1=(ColorPacket *) x;
  4670.   color_2=(ColorPacket *) y;
  4671.   return((int) Intensity(*color_2)-(int) Intensity(*color_1));
  4672. }
  4673.  
  4674. void SortColormapByIntensity(image)
  4675. Image
  4676.   *image;
  4677. {
  4678.   register int
  4679.     i;
  4680.  
  4681.   register RunlengthPacket
  4682.     *p;
  4683.  
  4684.   register unsigned short
  4685.     index;
  4686.  
  4687.   unsigned short
  4688.     *pixels;
  4689.  
  4690.   if (image->class != PseudoClass)
  4691.     return;
  4692.   /*
  4693.     Allocate memory for pixel indexes.
  4694.   */
  4695.   pixels=(unsigned short *) malloc(image->colors*sizeof(unsigned short));
  4696.   if (pixels == (unsigned short *) NULL)
  4697.     {
  4698.       Warning("Unable to sort colormap","Memory allocation failed");
  4699.       return;
  4700.     }
  4701.   /*
  4702.     Assign index values to colormap entries.
  4703.   */
  4704.   for (i=0; i < image->colors; i++)
  4705.     image->colormap[i].index=(unsigned short) i;
  4706.   /*
  4707.     Sort image colormap by decreasing color popularity.
  4708.   */
  4709.   (void) qsort((void *) image->colormap,(int) image->colors,sizeof(ColorPacket),
  4710.     IntensityCompare);
  4711.   /*
  4712.     Update image colormap indexes to sorted colormap order.
  4713.   */
  4714.   for (i=0; i < image->colors; i++)
  4715.     pixels[image->colormap[i].index]=(unsigned short) i;
  4716.   p=image->pixels;
  4717.   for (i=0; i < image->packets; i++)
  4718.   {
  4719.     index=pixels[p->index];
  4720.     p->red=image->colormap[index].red;
  4721.     p->green=image->colormap[index].green;
  4722.     p->blue=image->colormap[index].blue;
  4723.     p->index=index;
  4724.     p++;
  4725.   }
  4726.   (void) free((char *) pixels);
  4727. }
  4728.  
  4729. /*
  4730. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4731. %                                                                             %
  4732. %                                                                             %
  4733. %                                                                             %
  4734. %   S t e r e o I m a g e                                                     %
  4735. %                                                                             %
  4736. %                                                                             %
  4737. %                                                                             %
  4738. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4739. %
  4740. %  Function StereoImage combines two images and produces a single image that
  4741. %  is the composite of a left and right image of a stereo pair.  The left
  4742. %  image is converted to grayscale and written to the red channel of the
  4743. %  stereo image.  The right image is converted to grayscale and written to the
  4744. %  blue channel of the stereo image.  View the composite image with red-blue
  4745. %  glasses to create a stereo effect.
  4746. %
  4747. %  The format of the StereoImage routine is:
  4748. %
  4749. %      stereo_image=StereoImage(left_image,right_image)
  4750. %
  4751. %  A description of each parameter follows:
  4752. %
  4753. %    o stereo_image: Function StereoImage returns a pointer to the stereo
  4754. %      image.  A null image is returned if there is a memory shortage.
  4755. %
  4756. %    o left_image: The address of a structure of type Image.
  4757. %
  4758. %    o right_image: The address of a structure of type Image.
  4759. %
  4760. %
  4761. */
  4762. Image *StereoImage(left_image,right_image)
  4763. Image
  4764.   *left_image,
  4765.   *right_image;
  4766. {
  4767.   Image
  4768.     *stereo_image;
  4769.  
  4770.   register int
  4771.     i;
  4772.  
  4773.   register RunlengthPacket
  4774.     *p,
  4775.     *q,
  4776.     *r;
  4777.  
  4778.   if ((left_image->columns != right_image->columns) ||
  4779.       (left_image->rows != right_image->rows))
  4780.     {
  4781.       Warning("Unable to create stereo image",
  4782.         "left and right image sizes differ");
  4783.       return((Image *) NULL);
  4784.     }
  4785.   /*
  4786.     Initialize stereo image attributes.
  4787.   */
  4788.   stereo_image=CopyImage(left_image,left_image->columns,left_image->rows,False);
  4789.   if (stereo_image == (Image *) NULL)
  4790.     {
  4791.       Warning("Unable to create stereo image","Memory allocation failed");
  4792.       return((Image *) NULL);
  4793.     }
  4794.   stereo_image->class=DirectClass;
  4795.   /*
  4796.     Copy left image to red channel and right image to blue channel.
  4797.   */
  4798.   QuantizeImage(left_image,256,8,False,GRAYColorspace,True);
  4799.   SyncImage(left_image);
  4800.   p=left_image->pixels;
  4801.   left_image->runlength=p->length+1;
  4802.   QuantizeImage(right_image,256,8,False,GRAYColorspace,True);
  4803.   SyncImage(right_image);
  4804.   q=right_image->pixels;
  4805.   right_image->runlength=q->length+1;
  4806.   r=stereo_image->pixels;
  4807.   for (i=0; i < (stereo_image->columns*stereo_image->rows); i++)
  4808.   {
  4809.     if (left_image->runlength != 0)
  4810.       left_image->runlength--;
  4811.     else
  4812.       {
  4813.         p++;
  4814.         left_image->runlength=p->length;
  4815.       }
  4816.     if (right_image->runlength != 0)
  4817.       right_image->runlength--;
  4818.     else
  4819.       {
  4820.         q++;
  4821.         right_image->runlength=q->length;
  4822.       }
  4823.     r->red=(unsigned int) (p->red*12) >> 4;
  4824.     r->green=0;
  4825.     r->blue=q->blue;
  4826.     r->index=0;
  4827.     r->length=0;
  4828.     r++;
  4829.   }
  4830.   return(stereo_image);
  4831. }
  4832.  
  4833. /*
  4834. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4835. %                                                                             %
  4836. %                                                                             %
  4837. %                                                                             %
  4838. %   S y n c I m a g e                                                         %
  4839. %                                                                             %
  4840. %                                                                             %
  4841. %                                                                             %
  4842. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4843. %
  4844. %  Function SyncImage initializes the red, green, and blue intensities of each
  4845. %  pixel as defined by the colormap index.
  4846. %
  4847. %  The format of the SyncImage routine is:
  4848. %
  4849. %      SyncImage(image)
  4850. %
  4851. %  A description of each parameter follows:
  4852. %
  4853. %    o image: The address of a structure of type Image.
  4854. %
  4855. %
  4856. */
  4857. void SyncImage(image)
  4858. Image
  4859.   *image;
  4860. {
  4861.   register int
  4862.     i;
  4863.  
  4864.   register RunlengthPacket
  4865.     *p;
  4866.  
  4867.   register unsigned short
  4868.     index;
  4869.  
  4870.   p=image->pixels;
  4871.   for (i=0; i < image->packets; i++)
  4872.   {
  4873.     index=p->index;
  4874.     p->red=image->colormap[index].red;
  4875.     p->green=image->colormap[index].green;
  4876.     p->blue=image->colormap[index].blue;
  4877.     p++;
  4878.   }
  4879. }
  4880.  
  4881. /*
  4882. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4883. %                                                                             %
  4884. %                                                                             %
  4885. %                                                                             %
  4886. %   T r a n s f o r m I m a g e                                               %
  4887. %                                                                             %
  4888. %                                                                             %
  4889. %                                                                             %
  4890. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  4891. %
  4892. %  Function TransformImage creates a new image that is a transformed size of
  4893. %  of existing one as specified by the clip and image geometries.  It
  4894. %  allocates the memory necessary for the new Image structure and returns a
  4895. %  pointer to the new image.
  4896. %
  4897. %  If a clip geometry is specified a subregion of the image is obtained.
  4898. %  If the specified image size, as defined by the image and scale geometries,
  4899. %  is smaller than the actual image size, the image is first reduced to an
  4900. %  integral of the specified image size with an antialias digital filter.  The
  4901. %  image is then scaled to the exact specified image size with pixel
  4902. %  replication.  If the specified image size is greater than the actual image
  4903. %  size, the image is first enlarged to an integral of the specified image
  4904. %  size with bilinear interpolation.  The image is then scaled to the exact
  4905. %  specified image size with pixel replication.
  4906. %
  4907. %  The format of the TransformImage routine is:
  4908. %
  4909. %      TransformImage(image,clip_geometry,image_geometry)
  4910. %
  4911. %  A description of each parameter follows:
  4912. %
  4913. %    o image: The address of an address of a structure of type Image.  The
  4914. %      transformed image is returned as this parameter.
  4915. %
  4916. %    o clip_geometry: Specifies a pointer to a clip geometry string.
  4917. %      This geometry defines a subregion of the image.
  4918. %
  4919. %    o image_geometry: Specifies a pointer to a image geometry string.
  4920. %      The specified width and height of this geometry string are absolute.
  4921. %
  4922. %
  4923. */
  4924. void TransformImage(image,clip_geometry,image_geometry)
  4925. Image
  4926.   **image;
  4927.  
  4928. char
  4929.   *clip_geometry,
  4930.   *image_geometry;
  4931. {
  4932.   Image
  4933.     *transformed_image;
  4934.  
  4935.   int
  4936.     flags;
  4937.  
  4938.   unsigned int
  4939.     height,
  4940.     width;
  4941.  
  4942.   transformed_image=(*image);
  4943.   if (clip_geometry != (char *) NULL)
  4944.     {
  4945.       Image
  4946.         *clipped_image;
  4947.  
  4948.       RectangleInfo
  4949.         clip_info;
  4950.  
  4951.       /*
  4952.         Clip image to a user specified size.
  4953.       */
  4954.       clip_info.x=0;
  4955.       clip_info.y=0;
  4956.       flags=XParseGeometry(clip_geometry,&clip_info.x,&clip_info.y,
  4957.         &clip_info.width,&clip_info.height);
  4958.       if ((flags & WidthValue) == 0)
  4959.         clip_info.width=(unsigned int)
  4960.           ((int) transformed_image->columns-clip_info.x);
  4961.       if ((flags & HeightValue) == 0)
  4962.         clip_info.height=(unsigned int)
  4963.           ((int) transformed_image->rows-clip_info.y);
  4964.       if ((flags & XNegative) != 0)
  4965.         clip_info.x+=transformed_image->columns-clip_info.width;
  4966.       if ((flags & YNegative) != 0)
  4967.         clip_info.y+=transformed_image->rows-clip_info.height;
  4968.       clipped_image=ClipImage(transformed_image,&clip_info);
  4969.       if (clipped_image != (Image *) NULL)
  4970.         {
  4971.           DestroyImage(transformed_image);
  4972.           transformed_image=clipped_image;
  4973.         }
  4974.     }
  4975.   /*
  4976.     Scale image to a user specified size.
  4977.   */
  4978.   width=transformed_image->columns;
  4979.   height=transformed_image->rows;
  4980.   ParseImageGeometry(image_geometry,&width,&height);
  4981.   while ((transformed_image->columns >= (width << 1)) &&
  4982.          (transformed_image->rows >= (height << 1)))
  4983.   {
  4984.     Image
  4985.       *reduced_image;
  4986.  
  4987.     /*
  4988.       Reduce image with a antialias digital filter.
  4989.     */
  4990.     reduced_image=ReduceImage(transformed_image);
  4991.     if (reduced_image == (Image *) NULL)
  4992.       break;
  4993.     DestroyImage(transformed_image);
  4994.     transformed_image=reduced_image;
  4995.   }
  4996.   while ((transformed_image->columns <= (width >> 1)) &&
  4997.          (transformed_image->rows <= (height >> 1)))
  4998.   {
  4999.     Image
  5000.       *zoomed_image;
  5001.  
  5002.     /*
  5003.       Zoom image with bilinear interpolation.
  5004.     */
  5005.     zoomed_image=ZoomImage(transformed_image);
  5006.     if (zoomed_image == (Image *) NULL)
  5007.       break;
  5008.     DestroyImage(transformed_image);
  5009.     transformed_image=zoomed_image;
  5010.   }
  5011.   if ((transformed_image->columns != width) ||
  5012.       (transformed_image->rows != height))
  5013.     {
  5014.       Image
  5015.         *scaled_image;
  5016.  
  5017.       /*
  5018.         Scale image with pixel replication.
  5019.       */
  5020.       scaled_image=ScaleImage(transformed_image,width,height);
  5021.       if (scaled_image != (Image *) NULL)
  5022.         {
  5023.           DestroyImage(transformed_image);
  5024.           transformed_image=scaled_image;
  5025.         }
  5026.     }
  5027.   *image=transformed_image;
  5028. }
  5029.  
  5030. /*
  5031. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5032. %                                                                             %
  5033. %                                                                             %
  5034. %     T r a n s f o r m R G B I m a g e                                       %
  5035. %                                                                             %
  5036. %                                                                             %
  5037. %                                                                             %
  5038. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5039. %
  5040. %  Procedure TransformRGBImage converts the reference image from an alternate
  5041. %  colorspace.  The transformation matrices are not the standard ones:  the
  5042. %  weights are rescaled to normalized the range of the transformed values to
  5043. %  be [0..255].
  5044. %
  5045. %  The format of the TransformRGBImage routine is:
  5046. %
  5047. %      TransformRGBImage(image,colorspace)
  5048. %
  5049. %  A description of each parameter follows:
  5050. %
  5051. %    o image: The address of a structure of type Image;  returned from
  5052. %      ReadImage.
  5053. %
  5054. %    o colorspace: An unsigned integer value that indicates the colorspace
  5055. %      the image is currently in.  On return the image is in the RGB
  5056. %      color space.
  5057. %
  5058. %
  5059. */
  5060. void TransformRGBImage(image,colorspace)
  5061. Image
  5062.   *image;
  5063.  
  5064. unsigned int
  5065.   colorspace;
  5066. {
  5067. #define R 0
  5068. #define G (MaxRGB+1)
  5069. #define B (MaxRGB+1)*2
  5070.  
  5071.   long
  5072.     *blue,
  5073.     *green,
  5074.     *red;
  5075.  
  5076.   register int
  5077.     i,
  5078.     x,
  5079.     y,
  5080.     z;
  5081.  
  5082.   register RunlengthPacket
  5083.     *p;
  5084.  
  5085.   register unsigned char
  5086.     *range_limit;
  5087.  
  5088.   unsigned char
  5089.     *range_table;
  5090.  
  5091.   if ((colorspace == RGBColorspace) || (colorspace == GRAYColorspace))
  5092.     return;
  5093.   /*
  5094.     Allocate the tables.
  5095.   */
  5096.   red=(long *) malloc(3*(MaxRGB+1)*sizeof(long));
  5097.   green=(long *) malloc(3*(MaxRGB+1)*sizeof(long));
  5098.   blue=(long *) malloc(3*(MaxRGB+1)*sizeof(long));
  5099.   range_table=(unsigned char *) malloc(3*(MaxRGB+1)*sizeof(unsigned char));
  5100.   if ((red == (long *) NULL) || (green == (long *) NULL) ||
  5101.       (blue == (long *) NULL) || (range_table == (unsigned char *) NULL))
  5102.     {
  5103.       Warning("Unable to transform color space","Memory allocation failed");
  5104.       return;
  5105.     }
  5106.   /*
  5107.     Initialize tables.
  5108.   */
  5109.   for (i=0; i <= MaxRGB; i++)
  5110.   {
  5111.     range_table[i]=0;
  5112.     range_table[i+(MaxRGB+1)]=(unsigned char) i;
  5113.     range_table[i+(MaxRGB+1)*2]=MaxRGB;
  5114.   }
  5115.   range_limit=range_table+(MaxRGB+1);
  5116.   switch (colorspace)
  5117.   {
  5118.     case OHTAColorspace:
  5119.     {
  5120.       /*
  5121.         Initialize OHTA tables:
  5122.  
  5123.           R = I1+1.00000*I2-0.66668*I3
  5124.           G = I1+0.00000*I2+1.33333*I3
  5125.           B = I1-1.00000*I2-0.66668*I3
  5126.  
  5127.         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
  5128.         through MaxRGB.
  5129.       */
  5130.       for (i=0; i <= MaxRGB; i++)
  5131.       {
  5132.         red[i+R]=UpShifted(1.00000)*i;
  5133.         green[i+R]=UpShifted(1.0000*0.5)*((i << 1)-MaxRGB);
  5134.         blue[i+R]=(-UpShifted(0.66668*0.5))*((i << 1)-MaxRGB);
  5135.         red[i+G]=UpShifted(1.00000)*i;
  5136.         green[i+G]=0;
  5137.         blue[i+G]=UpShifted(1.33333*0.5)*((i << 1)-MaxRGB);
  5138.         red[i+B]=UpShifted(1.00000)*i;
  5139.         green[i+B]=(-UpShifted(1.00000*0.5))*((i << 1)-MaxRGB);
  5140.         blue[i+B]=(-UpShifted(0.66668*0.5))*((i << 1)-MaxRGB);
  5141.       }
  5142.       break;
  5143.     }
  5144.     case XYZColorspace:
  5145.     {
  5146.       /*
  5147.         Initialize XYZ tables:
  5148.  
  5149.           R =  1.87597*X-0.53294*Y-0.34303*Z
  5150.           G = -0.96670*X+1.99806*Y+0.03136*Z
  5151.           B =  0.05735*X-0.11853*Y+1.06118*Z
  5152.       */
  5153.       for (i=0; i <= MaxRGB; i++)
  5154.       {
  5155.         red[i+R]=UpShifted(1.87597)*i;
  5156.         green[i+R]=(-UpShifted(0.53294))*i;
  5157.         blue[i+R]=(-UpShifted(0.34303))*i;
  5158.         red[i+G]=(-UpShifted(0.96670))*i;
  5159.         green[i+G]=UpShifted(1.99806)*i;
  5160.         blue[i+G]=UpShifted(0.03136)*i;
  5161.         red[i+B]=UpShifted(0.05735)*i;
  5162.         green[i+B]=(-UpShifted(0.11853))*i;
  5163.         blue[i+B]=UpShifted(1.06118)*i;
  5164.       }
  5165.       break;
  5166.     }
  5167.     case YCbCrColorspace:
  5168.     {
  5169.       /*
  5170.         Initialize YCbCr tables:
  5171.  
  5172.           R = Y           +1.40200*Cr
  5173.           G = Y-0.34414*Cb-0.71414*Cr
  5174.           B = Y+1.77200*Cb
  5175.  
  5176.         Cb and Cr, normally -0.5 through 0.5, must be normalized to the range 0
  5177.         through MaxRGB.
  5178.       */
  5179.       for (i=0; i <= MaxRGB; i++)
  5180.       {
  5181.         red[i+R]=UpShifted(1.00000)*i;
  5182.         green[i+R]=0;
  5183.         blue[i+R]=UpShifted(1.40200*0.5)*((i << 1)-MaxRGB);
  5184.         red[i+G]=UpShifted(1.00000)*i;
  5185.         green[i+G]=(-UpShifted(0.34414*0.5))*((i << 1)-MaxRGB);
  5186.         blue[i+G]=(-UpShifted(0.71414*0.5))*((i << 1)-MaxRGB);
  5187.         red[i+B]=UpShifted(1.00000)*i;
  5188.         green[i+B]=UpShifted(1.77200*0.5)*((i << 1)-MaxRGB);
  5189.         blue[i+B]=0;
  5190.       }
  5191.       break;
  5192.     }
  5193.     case YIQColorspace:
  5194.     {
  5195.       /*
  5196.         Initialize YIQ tables:
  5197.  
  5198.           R = 0.97087*Y+1.17782*I+0.59800*Q
  5199.           G = 0.97087*Y-0.28626*I-0.72851*Q
  5200.           B = 0.97087*Y-1.27870*I+1.72801*Q
  5201.  
  5202.         I and Q, normally -0.5 through 0.5, must be normalized to the range 0
  5203.         through MaxRGB.
  5204.       */
  5205.       for (i=0; i <= MaxRGB; i++)
  5206.       {
  5207.         red[i+R]=UpShifted(0.97087)*i;
  5208.         green[i+R]=UpShifted(1.17782*0.5)*((i << 1)-MaxRGB);
  5209.         blue[i+R]=UpShifted(0.59800*0.5)*((i << 1)-MaxRGB);
  5210.         red[i+G]=UpShifted(0.97087)*i;
  5211.         green[i+G]=(-UpShifted(0.28626*0.5))*((i << 1)-MaxRGB);
  5212.         blue[i+G]=(-UpShifted(0.72851*0.5))*((i << 1)-MaxRGB);
  5213.         red[i+B]=UpShifted(0.97087)*i;
  5214.         green[i+B]=(-UpShifted(1.27870*0.5))*((i << 1)-MaxRGB);
  5215.         blue[i+B]=UpShifted(1.72801*0.5)*((i << 1)-MaxRGB);
  5216.       }
  5217.       break;
  5218.     }
  5219.     case YUVColorspace:
  5220.     default:
  5221.     {
  5222.       /*
  5223.         Initialize YUV tables:
  5224.  
  5225.           R = Y          +1.13980*V
  5226.           G = Y-0.39380*U-0.58050*V
  5227.           B = Y+2.02790*U
  5228.  
  5229.         U and V, normally -0.5 through 0.5, must be normalized to the range 0
  5230.         through MaxRGB.
  5231.       */
  5232.       for (i=0; i <= MaxRGB; i++)
  5233.       {
  5234.         red[i+R]=UpShifted(1.00000)*i;
  5235.         green[i+R]=0;
  5236.         blue[i+R]=UpShifted(1.13980*0.5)*((i << 1)-MaxRGB);
  5237.         red[i+G]=UpShifted(1.00000)*i;
  5238.         green[i+G]=(-UpShifted(0.39380*0.5))*((i << 1)-MaxRGB);
  5239.         blue[i+G]=(-UpShifted(0.58050*0.5))*((i << 1)-MaxRGB);
  5240.         red[i+B]=UpShifted(1.00000)*i;
  5241.         green[i+B]=UpShifted(2.02790*0.5)*((i << 1)-MaxRGB);
  5242.         blue[i+B]=0;
  5243.       }
  5244.       break;
  5245.     }
  5246.   }
  5247.   /*
  5248.     Convert to RGB.
  5249.   */
  5250.   switch (image->class)
  5251.   {
  5252.     case DirectClass:
  5253.     {
  5254.       /*
  5255.         Convert DirectClass image.
  5256.       */
  5257.       p=image->pixels;
  5258.       for (i=0; i < image->packets; i++)
  5259.       {
  5260.         x=p->red;
  5261.         y=p->green;
  5262.         z=p->blue;
  5263.         p->red=range_limit[DownShift(red[x+R]+green[y+R]+blue[z+R])];
  5264.         p->green=range_limit[DownShift(red[x+G]+green[y+G]+blue[z+G])];
  5265.         p->blue=range_limit[DownShift(red[x+B]+green[y+B]+blue[z+B])];
  5266.         p++;
  5267.       }
  5268.       break;
  5269.     }
  5270.     case PseudoClass:
  5271.     {
  5272.       /*
  5273.         Convert PseudoClass image.
  5274.       */
  5275.       for (i=0; i < image->colors; i++)
  5276.       {
  5277.         x=image->colormap[i].red;
  5278.         y=image->colormap[i].green;
  5279.         z=image->colormap[i].blue;
  5280.         image->colormap[i].red=
  5281.           range_limit[DownShift(red[x+R]+green[y+R]+blue[z+R])];
  5282.         image->colormap[i].green=
  5283.           range_limit[DownShift(red[x+G]+green[y+G]+blue[z+G])];
  5284.         image->colormap[i].blue=
  5285.           range_limit[DownShift(red[x+B]+green[y+B]+blue[z+B])];
  5286.       }
  5287.       p=image->pixels;
  5288.       for (i=0; i < image->packets; i++)
  5289.       {
  5290.         x=p->red;
  5291.         y=p->green;
  5292.         z=p->blue;
  5293.         p->red=range_limit[DownShift(red[x+R]+green[y+R]+blue[z+R])];
  5294.         p->green=range_limit[DownShift(red[x+G]+green[y+G]+blue[z+G])];
  5295.         p->blue=range_limit[DownShift(red[x+B]+green[y+B]+blue[z+B])];
  5296.         p++;
  5297.       }
  5298.       break;
  5299.     }
  5300.   }
  5301.   /*
  5302.     Free allocated memory.
  5303.   */
  5304.   (void) free((char *) range_table);
  5305.   (void) free((char *) blue);
  5306.   (void) free((char *) green);
  5307.   (void) free((char *) red);
  5308. }
  5309.  
  5310. /*
  5311. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5312. %                                                                             %
  5313. %                                                                             %
  5314. %                                                                             %
  5315. %   U n C o m p r e s s I m a g e                                             %
  5316. %                                                                             %
  5317. %                                                                             %
  5318. %                                                                             %
  5319. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5320. %
  5321. %  Function UncompressImage uncompresses runlength-encoded pixels packets to
  5322. %  a rectangular array of pixels.
  5323. %
  5324. %  The format of the UncompressImage routine is:
  5325. %
  5326. %      status=UncompressImage(image)
  5327. %
  5328. %  A description of each parameter follows:
  5329. %
  5330. %    o status: Function UncompressImage returns True if the image is
  5331. %      uncompressed otherwise False.
  5332. %
  5333. %    o image: The address of a structure of type Image.
  5334. %
  5335. %
  5336. */
  5337. unsigned int UncompressImage(image)
  5338. Image
  5339.   *image;
  5340. {
  5341.   register int
  5342.     i,
  5343.     j,
  5344.     length;
  5345.  
  5346.   register RunlengthPacket
  5347.     *p,
  5348.     *q;
  5349.  
  5350.   RunlengthPacket
  5351.     *uncompressed_pixels;
  5352.  
  5353.   if (image->packets == (image->columns*image->rows))
  5354.     return(True);
  5355.   /*
  5356.     Uncompress runlength-encoded packets.
  5357.   */
  5358.   uncompressed_pixels=(RunlengthPacket *) realloc((char *) image->pixels,
  5359.     image->columns*image->rows*sizeof(RunlengthPacket));
  5360.   if (uncompressed_pixels == (RunlengthPacket *) NULL)
  5361.     return(False);
  5362.   image->pixels=uncompressed_pixels;
  5363.   p=image->pixels+image->packets-1;
  5364.   q=uncompressed_pixels+image->columns*image->rows-1;
  5365.   for (i=0; i < image->packets; i++)
  5366.   {
  5367.     length=p->length;
  5368.     for (j=0; j <= length; j++)
  5369.     {
  5370.       *q=(*p);
  5371.       q->length=0;
  5372.       q--;
  5373.     }
  5374.     p--;
  5375.   }
  5376.   image->packets=image->columns*image->rows;
  5377.   return(True);
  5378. }
  5379.  
  5380. /*
  5381. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5382. %                                                                             %
  5383. %                                                                             %
  5384. %                                                                             %
  5385. %   Z o o m I m a g e                                                         %
  5386. %                                                                             %
  5387. %                                                                             %
  5388. %                                                                             %
  5389. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5390. %
  5391. %  Function ZoomImage creates a new image that is a integral size greater
  5392. %  than an existing one.  It allocates the memory necessary for the new Image
  5393. %  structure and returns a pointer to the new image.
  5394. %
  5395. %  ZoomImage scans the reference image to create a zoomed image by bilinear
  5396. %  interpolation.  The zoomed image columns and rows become:
  5397. %
  5398. %    number_columns << 1
  5399. %    number_rows << 1
  5400. %
  5401. %  The format of the ZoomImage routine is:
  5402. %
  5403. %      zoomed_image=ZoomImage(image)
  5404. %
  5405. %  A description of each parameter follows:
  5406. %
  5407. %    o zoomed_image: Function ZoomImage returns a pointer to the image after
  5408. %      zooming.  A null image is returned if there is a a memory shortage.
  5409. %
  5410. %    o image: The address of a structure of type Image.
  5411. %
  5412. %
  5413. */
  5414. static Image *ZoomImage(image)
  5415. Image
  5416.   *image;
  5417. {
  5418.   Image
  5419.     *zoomed_image;
  5420.  
  5421.   register RunlengthPacket
  5422.     *cs,
  5423.     *ns,
  5424.     *p,
  5425.     *q,
  5426.     *s;
  5427.  
  5428.   register unsigned int
  5429.     x;
  5430.  
  5431.   RunlengthPacket
  5432.     *scanline;
  5433.  
  5434.   unsigned int
  5435.     y;
  5436.  
  5437.   if (((image->columns*image->rows) << 1) > MaxImageSize)
  5438.     {
  5439.       Warning("Unable to zoom image","image size too large");
  5440.       return((Image *) NULL);
  5441.     }
  5442.   /*
  5443.     Initialize scaled image attributes.
  5444.   */
  5445.   zoomed_image=CopyImage(image,image->columns << 1,image->rows << 1,False);
  5446.   if (zoomed_image == (Image *) NULL)
  5447.     {
  5448.       Warning("Unable to zoom image","Memory allocation failed");
  5449.       return((Image *) NULL);
  5450.     }
  5451.   zoomed_image->class=DirectClass;
  5452.   /*
  5453.     Allocate scan line buffer.
  5454.   */
  5455.   scanline=(RunlengthPacket *) malloc(4*image->columns*sizeof(RunlengthPacket));
  5456.   if (scanline == (RunlengthPacket *) NULL)
  5457.     {
  5458.       Warning("Unable to zoom image","Memory allocation failed");
  5459.       DestroyImage(zoomed_image);
  5460.       return((Image *) NULL);
  5461.     }
  5462.   /*
  5463.     Preload a scan line and interpolate.
  5464.   */
  5465.   p=image->pixels;
  5466.   image->runlength=p->length+1;
  5467.   s=scanline;
  5468.   for (x=0; x < image->columns; x++)
  5469.   {
  5470.     *s=(*p);
  5471.     s++;
  5472.     if (image->runlength != 0)
  5473.       {
  5474.         image->runlength--;
  5475.         *s=(*p);
  5476.       }
  5477.     else
  5478.       {
  5479.         p++;
  5480.         image->runlength=p->length;
  5481.         s->red=(unsigned char) ((int) (p->red+(s-1)->red) >> 1);
  5482.         s->green=(unsigned char) ((int) (p->green+(s-1)->green) >> 1);
  5483.         s->blue=(unsigned char) ((int) (p->blue+(s-1)->blue) >> 1);
  5484.         s->index=(unsigned short) ((int) (p->index+(s-1)->index) >> 1);
  5485.       }
  5486.     s++;
  5487.   }
  5488.   /*
  5489.     Zoom each row.
  5490.   */
  5491.   p=image->pixels;
  5492.   image->runlength=p->length+1;
  5493.   q=zoomed_image->pixels;
  5494.   for (y=0; y < image->rows; y++)
  5495.   {
  5496.     cs=scanline+image->columns*((y+0) % 2)*2;
  5497.     ns=scanline+image->columns*((y+1) % 2)*2;
  5498.     /*
  5499.       Read a scan line and interpolate.
  5500.     */
  5501.     s=ns;
  5502.     for (x=0; x < image->columns; x++)
  5503.     {
  5504.       *s=(*p);
  5505.       s++;
  5506.       if (image->runlength != 0)
  5507.         {
  5508.           image->runlength--;
  5509.           *s=(*p);
  5510.         }
  5511.       else
  5512.         {
  5513.           p++;
  5514.           image->runlength=p->length;
  5515.           s->red=(unsigned char) ((int) (p->red+(s-1)->red) >> 1);
  5516.           s->green=(unsigned char) ((int) (p->green+(s-1)->green) >> 1);
  5517.           s->blue=(unsigned char) ((int) (p->blue+(s-1)->blue) >> 1);
  5518.           s->index=(unsigned short) ((int) (p->index+(s-1)->index) >> 1);
  5519.         }
  5520.       s++;
  5521.     }
  5522.     /*
  5523.       Dump column interpolation values.
  5524.     */
  5525.     s=cs;
  5526.     for (x=0; x < zoomed_image->columns; x++)
  5527.     {
  5528.       *q=(*s);
  5529.       q->length=0;
  5530.       q++;
  5531.       s++;
  5532.     }
  5533.     /*
  5534.       Dump row interpolation values.
  5535.     */
  5536.     for (x=0; x < zoomed_image->columns; x++)
  5537.     {
  5538.       q->red=(unsigned char) ((int) (cs->red+ns->red) >> 1);
  5539.       q->green=(unsigned char) ((int) (cs->green+ns->green) >> 1);
  5540.       q->blue=(unsigned char) ((int) (cs->blue+ns->blue) >> 1);
  5541.       q->index=(unsigned short) ((int) (cs->index+ns->index) >> 1);
  5542.       q->length=0;
  5543.       q++;
  5544.       cs++;
  5545.       ns++;
  5546.     }
  5547.   }
  5548.   (void) free((char *) scanline);
  5549.   return(zoomed_image);
  5550. }
  5551.