xpm.c revision 4cb162a81b4dfaf673e94c9dea88ad0a92f0a3d7
1afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner/*
27c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell%                                                                             %
47c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell%                                                                             %
57c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell%                                                                             %
67c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell%                            X   X  PPPP   M   M                              %
77c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell%                             X X   P   P  MM MM                              %
87c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell%                              X    PPPP   M M M                              %
9afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                             X X   P      M   M                              %
10efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner%                            X   X  P      M   M                              %
11efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner%                                                                             %
12afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                                                                             %
13afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                  Read/Write X Windows system Pixmap Format                  %
14afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                                                                             %
15afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                              Software Design                                %
16e49603d79d220a795bd50684c8b1f503ee40f97fMisha Brukman%                                John Cristy                                  %
17afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                                 July 1992                                   %
18afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                                                                             %
19d1a85a744cc1001c2b7fc37cf37aca266964f519Brian Gaeke%                                                                             %
20e49603d79d220a795bd50684c8b1f503ee40f97fMisha Brukman%  Copyright 1999-2010 ImageMagick Studio LLC, a non-profit organization      %
21e49603d79d220a795bd50684c8b1f503ee40f97fMisha Brukman%  dedicated to making software imaging solutions freely available.           %
22afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%                                                                             %
236520785dcd22012535934098942d57c07c7631c2Chris Lattner%  You may not use this file except in compliance with the License.  You may  %
24afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner%  obtain a copy of the License at                                            %
255e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner%                                                                             %
265da69c79f9c4490c6657c207430dfeb1060fc4ddChris Lattner%    http://www.imagemagick.org/script/license.php                            %
27551ccae044b0ff658fe629dd67edd5ffe75d10e8Reid Spencer%                                                                             %
28551ccae044b0ff658fe629dd67edd5ffe75d10e8Reid Spencer%  Unless required by applicable law or agreed to in writing, software        %
29551ccae044b0ff658fe629dd67edd5ffe75d10e8Reid Spencer%  distributed under the License is distributed on an "AS IS" BASIS,          %
30fb4b96e77e2930bf3d0c148f1c3685b6a4434666Chris Lattner%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31c6b519d64ef55d39e66a49510d4703a49bf228ccChris Lattner%  See the License for the specific language governing permissions and        %
32d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke%  limitations under the License.                                             %
33d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke%                                                                             %
34c6b519d64ef55d39e66a49510d4703a49bf228ccChris Lattner%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke%
36d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke%
376db70ef879916e6115ac97eb76e4fea973652e2cChris Lattner*/
386db70ef879916e6115ac97eb76e4fea973652e2cChris Lattner
396db70ef879916e6115ac97eb76e4fea973652e2cChris Lattner/*
406db70ef879916e6115ac97eb76e4fea973652e2cChris Lattner  Include declarations.
4147ae4a1cee5eec5767a11403c0fac7c91ec45461Chris Lattner*/
4247ae4a1cee5eec5767a11403c0fac7c91ec45461Chris Lattner#include "magick/studio.h"
436db70ef879916e6115ac97eb76e4fea973652e2cChris Lattner#include "magick/blob.h"
446db70ef879916e6115ac97eb76e4fea973652e2cChris Lattner#include "magick/blob-private.h"
45afade9294af43c6b947b9aeaa1555883d5f853e3Chris Lattner#include "magick/cache.h"
466520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/color.h"
476520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/color-private.h"
486520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/colormap.h"
496520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/colorspace.h"
506520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/exception.h"
510cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/exception-private.h"
526520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/geometry.h"
536520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/image.h"
546520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/image-private.h"
550cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/list.h"
560cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/magick.h"
576520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/memory_.h"
586520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/monitor.h"
590cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/monitor-private.h"
600cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/pixel-private.h"
616520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/quantize.h"
626520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/quantum-private.h"
630cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/resize.h"
646520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/resource_.h"
656520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/splay-tree.h"
660cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/static.h"
670cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/string_.h"
686520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/module.h"
696520785dcd22012535934098942d57c07c7631c2Chris Lattner#include "magick/threshold.h"
700cc8807029f577996a442b96d24c3346ed6de091Chris Lattner#include "magick/utility.h"
710cc8807029f577996a442b96d24c3346ed6de091Chris Lattner
726520785dcd22012535934098942d57c07c7631c2Chris Lattner/*
736520785dcd22012535934098942d57c07c7631c2Chris Lattner  Forward declarations.
740cc8807029f577996a442b96d24c3346ed6de091Chris Lattner*/
756520785dcd22012535934098942d57c07c7631c2Chris Lattnerstatic MagickBooleanType
7644be25716628941b4cccccf56a28ee0ba2606850Chris Lattner  WritePICONImage(const ImageInfo *,Image *),
776520785dcd22012535934098942d57c07c7631c2Chris Lattner  WriteXPMImage(const ImageInfo *,Image *);
785da69c79f9c4490c6657c207430dfeb1060fc4ddChris Lattner
795da69c79f9c4490c6657c207430dfeb1060fc4ddChris Lattner/*
805da69c79f9c4490c6657c207430dfeb1060fc4ddChris Lattner%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner%                                                                             %
82efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner%                                                                             %
836db70ef879916e6115ac97eb76e4fea973652e2cChris Lattner%                                                                             %
846520785dcd22012535934098942d57c07c7631c2Chris Lattner%   I s X P M                                                                 %
8547ae4a1cee5eec5767a11403c0fac7c91ec45461Chris Lattner%                                                                             %
866520785dcd22012535934098942d57c07c7631c2Chris Lattner%                                                                             %
8710f22cb1a0f2755050218cd0e07221a0985c6b63Chris Lattner%                                                                             %
8810f22cb1a0f2755050218cd0e07221a0985c6b63Chris Lattner%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
896520785dcd22012535934098942d57c07c7631c2Chris Lattner%
906520785dcd22012535934098942d57c07c7631c2Chris Lattner%  IsXPM() returns MagickTrue if the image format type, identified by the
916520785dcd22012535934098942d57c07c7631c2Chris Lattner%  magick string, is XPM.
92ba386d943f4a83095d9c625cb0d46c1afe45ed1fChris Lattner%
93fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%  The format of the IsXPM method is:
94fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%
95fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%      MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
96fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%
97fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%  A description of each parameter follows:
98fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%
99ba386d943f4a83095d9c625cb0d46c1afe45ed1fChris Lattner%    o magick: compare image format pattern against these bytes. or
100ba386d943f4a83095d9c625cb0d46c1afe45ed1fChris Lattner%      blob.
101ba386d943f4a83095d9c625cb0d46c1afe45ed1fChris Lattner%
102ba386d943f4a83095d9c625cb0d46c1afe45ed1fChris Lattner%    o length: Specifies the length of the magick string.
103fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%
10428b8ed90c75ce6c271500fa778fef252f267a5ffChris Lattner*/
10528b8ed90c75ce6c271500fa778fef252f267a5ffChris Lattnerstatic MagickBooleanType IsXPM(const unsigned char *magick,const size_t length)
10628b8ed90c75ce6c271500fa778fef252f267a5ffChris Lattner{
107dbe48dcaec69ff78e39e2d5faf4323ade6fffb04Chris Lattner  if (length < 9)
108fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner    return(MagickFalse);
109fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner  if (LocaleNCompare((char *) magick+1,"* XPM *",7) == 0)
110fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner    return(MagickTrue);
111fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner  return(MagickFalse);
112fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner}
113c6b519d64ef55d39e66a49510d4703a49bf228ccChris Lattner
114c6b519d64ef55d39e66a49510d4703a49bf228ccChris Lattner/*
115c6b519d64ef55d39e66a49510d4703a49bf228ccChris Lattner%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116c6b519d64ef55d39e66a49510d4703a49bf228ccChris Lattner%                                                                             %
117fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%                                                                             %
118a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner%                                                                             %
119a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner%   R e a d X P M I m a g e                                                   %
1207546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%                                                                             %
121fcb6ec0c7e37c2d15ddb04878f05cbd69d1da036Chris Lattner%                                                                             %
122a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner%                                                                             %
123a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124ba386d943f4a83095d9c625cb0d46c1afe45ed1fChris Lattner%
125be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner%  ReadXPMImage() reads an X11 pixmap image file and returns it.  It
126be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner%  allocates the memory necessary for the new Image structure and returns a
1277546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%  pointer to the new image.
1287546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%
1297546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%  The format of the ReadXPMImage method is:
1307546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%
1317546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%      Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
1327546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%
1337546c3884a400b72d10fc19f120c6798b294a39dChris Lattner%  A description of each parameter follows:
134a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner%
135a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner%    o image_info: the image info.
136a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner%
137a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner%    o exception: return any errors or warnings in this structure.
138a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner%
139a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner*/
140a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner
1417546c3884a400b72d10fc19f120c6798b294a39dChris Lattnerstatic int CompareXPMColor(const void *target,const void *source)
1427546c3884a400b72d10fc19f120c6798b294a39dChris Lattner{
143a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner  const char
144a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner    *p,
145a269ec7b0a83d3b20730fd2d9f7c3ed5a552da90Chris Lattner    *q;
146a269ec7b0a83d3b20730fd2d9f7c3ed5a552da90Chris Lattner
147a269ec7b0a83d3b20730fd2d9f7c3ed5a552da90Chris Lattner  p=(const char *) target;
14890c18c5c69d9c451e5fdca1e4b4b95e8ed13291aChris Lattner  q=(const char *) source;
149a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner  return(strcmp(p,q));
150a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner}
15190c18c5c69d9c451e5fdca1e4b4b95e8ed13291aChris Lattner
15290c18c5c69d9c451e5fdca1e4b4b95e8ed13291aChris Lattnerstatic char *CopyXPMColor(char *destination,const char *source,size_t length)
15390c18c5c69d9c451e5fdca1e4b4b95e8ed13291aChris Lattner{
15490c18c5c69d9c451e5fdca1e4b4b95e8ed13291aChris Lattner  while (length-- && (*source != '\0'))
15590c18c5c69d9c451e5fdca1e4b4b95e8ed13291aChris Lattner    *destination++=(*source++);
156a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner  *destination='\0';
157a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner  return(destination-length);
158a75766a6c14b364b74b30546802e26d4b4b36a9bChris Lattner}
1597546c3884a400b72d10fc19f120c6798b294a39dChris Lattner
1607546c3884a400b72d10fc19f120c6798b294a39dChris Lattnerstatic char *NextXPMLine(char *p)
1617546c3884a400b72d10fc19f120c6798b294a39dChris Lattner{
162be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  assert(p != (char*)NULL);
163be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  p=strchr(p,'\n');
164be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  if (p != (char *) NULL)
165be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    p++;
166be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  return(p);
167be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner}
168be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner
169be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattnerstatic inline size_t MagickMin(const size_t x,const size_t y)
170be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner{
171be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  if (x < y)
172be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    return(x);
173be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  return(y);
1745eda1f2f65941a24ef9a5a85addf4d90eb13fa9dChris Lattner}
1755eda1f2f65941a24ef9a5a85addf4d90eb13fa9dChris Lattner
1765eda1f2f65941a24ef9a5a85addf4d90eb13fa9dChris Lattnerstatic char *ParseXPMColor(char *color)
1775eda1f2f65941a24ef9a5a85addf4d90eb13fa9dChris Lattner{
1785eda1f2f65941a24ef9a5a85addf4d90eb13fa9dChris Lattner#define NumberTargets  6
179be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner
180be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  register char
181be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    *p,
182be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    *r;
183be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner
184be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  register const char
185be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    *q;
186be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner
187be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  register ssize_t
188be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    i;
189be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner
190be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  static const char
191be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    *targets[NumberTargets] = { "c ", "g ", "g4 ", "m ", "b ", "s " };
192be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner
193be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  for (i=0; i < NumberTargets; i++)
194be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner  {
195fb4b96e77e2930bf3d0c148f1c3685b6a4434666Chris Lattner    p=color;
196be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner    for (q=targets[i]; *p != '\0'; p++)
197fb4b96e77e2930bf3d0c148f1c3685b6a4434666Chris Lattner    {
198be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner      if (*p == '\n')
199be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner        break;
200be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner      if (*p != *q)
201be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner        continue;
202be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner      if (isspace((int) ((unsigned char) (*(p-1)))) == 0)
203be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner        continue;
204be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner      r=p;
205fb4b96e77e2930bf3d0c148f1c3685b6a4434666Chris Lattner      for ( ; ; )
206fb4b96e77e2930bf3d0c148f1c3685b6a4434666Chris Lattner      {
207be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner        if (*q == '\0')
208be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner          return(p);
209be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner        if (*r++ != *q++)
2105e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner          break;
2115e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner      }
2125e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner      q=targets[i];
2135e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    }
2145e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  }
2155e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  return((char *) NULL);
2165e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner}
2175e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2185e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattnerstatic Image *ReadXPMImage(const ImageInfo *image_info,ExceptionInfo *exception)
2195e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner{
2205e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  char
221b12914bfc0f76a7a48357162d5f4c39a1343e69bChris Lattner    key[MaxTextExtent],
222b12914bfc0f76a7a48357162d5f4c39a1343e69bChris Lattner    target[MaxTextExtent],
2235e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *xpm_buffer;
2245e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2255e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  Image
2265e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *image;
2275e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
228b12914bfc0f76a7a48357162d5f4c39a1343e69bChris Lattner  ssize_t
2295e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    j,
2305e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    y;
2315e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2325e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  MagickBooleanType
2335e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    active,
2345e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    status;
2355e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2365e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  register char
2375e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *p,
2385e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *q,
2395e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *next;
2405e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2415e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  register IndexPacket
2425e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *indexes;
2435e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2445e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  register ssize_t
2455e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    i,
2465e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    x;
2475e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2485e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  register PixelPacket
2495e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *r;
2505e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2515e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  size_t
2525e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    length;
2535e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2545e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  SplayTreeInfo
2555e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    *xpm_colors;
2565e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2575e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  ssize_t
2585e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    count;
2595e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2605e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  unsigned long
2615e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    colors,
2625e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    columns,
2635e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    rows,
2645e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    width;
2655e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner
2665e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  /*
2675e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    Open image file.
2685e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  */
2695e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  assert(image_info != (const ImageInfo *) NULL);
2705e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  assert(image_info->signature == MagickSignature);
2715e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  if (image_info->debug != MagickFalse)
272891150f0b2a124a75c9f31516182ce864ae69ef8Chris Lattner    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
2735e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner      image_info->filename);
274891150f0b2a124a75c9f31516182ce864ae69ef8Chris Lattner  assert(exception != (ExceptionInfo *) NULL);
275891150f0b2a124a75c9f31516182ce864ae69ef8Chris Lattner  assert(exception->signature == MagickSignature);
276891150f0b2a124a75c9f31516182ce864ae69ef8Chris Lattner  image=AcquireImage(image_info);
277891150f0b2a124a75c9f31516182ce864ae69ef8Chris Lattner  status=OpenBlob(image_info,image,ReadBinaryBlobMode,exception);
2785e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner  if (status == MagickFalse)
2795e783ab0b5fc3407ec59f1a598fdb9ef3b96b287Chris Lattner    {
280      image=DestroyImageList(image);
281      return((Image *) NULL);
282    }
283  /*
284    Read XPM file.
285  */
286  length=MaxTextExtent;
287  xpm_buffer=(char *) AcquireQuantumMemory((size_t) length,sizeof(*xpm_buffer));
288  p=xpm_buffer;
289  if (xpm_buffer != (char *) NULL)
290    while (ReadBlobString(image,p) != (char *) NULL)
291    {
292      if ((*p == '#') && ((p == xpm_buffer) || (*(p-1) == '\n')))
293        continue;
294      if ((*p == '}') && (*(p+1) == ';'))
295        break;
296      p+=strlen(p);
297      if ((size_t) (p-xpm_buffer+MaxTextExtent) < length)
298        continue;
299      length<<=1;
300      xpm_buffer=(char *) ResizeQuantumMemory(xpm_buffer,length+MaxTextExtent,
301        sizeof(*xpm_buffer));
302      if (xpm_buffer == (char *) NULL)
303        break;
304      p=xpm_buffer+strlen(xpm_buffer);
305    }
306  if (xpm_buffer == (char *) NULL)
307    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
308  /*
309    Remove comments.
310  */
311  count=0;
312  for (p=xpm_buffer; *p != '\0'; p++)
313  {
314    if (*p != '"')
315      continue;
316    count=(ssize_t) sscanf(p+1,"%lu %lu %lu %lu",&columns,&rows,&colors,&width);
317    image->columns=columns;
318    image->rows=rows;
319    image->colors=colors;
320    if (count == 4)
321      break;
322  }
323  if ((count != 4) || (width > 10) || (image->columns == 0) ||
324      (image->rows == 0) || (image->colors == 0))
325    ThrowReaderException(CorruptImageError,"ImproperImageHeader");
326  image->depth=16;
327  /*
328    Remove unquoted characters.
329  */
330  i=0;
331  active=MagickFalse;
332  q=xpm_buffer;
333  while (*p != '\0')
334  {
335    if (*p++ == '"')
336      {
337        if (active != MagickFalse)
338          *q++='\n';
339        active=active != MagickFalse ? MagickFalse : MagickTrue;
340      }
341    if (active != MagickFalse)
342      *q++=(*p);
343  }
344  *q='\0';
345  /*
346    Initialize image structure.
347  */
348  xpm_colors=NewSplayTree(CompareXPMColor,RelinquishMagickMemory,
349    (void *(*)(void *)) NULL);
350  if (AcquireImageColormap(image,image->colors) == MagickFalse)
351    ThrowReaderException(ResourceLimitError,"MemoryAllocationFailed");
352  /*
353    Read image colormap.
354  */
355  i=1;
356  next=NextXPMLine(xpm_buffer);
357  for (j=0; (j < (ssize_t) image->colors) && (next != (char*) NULL); j++)
358  {
359    p=next;
360    next=NextXPMLine(p);
361    (void) CopyXPMColor(key,p,MagickMin((size_t) width,MaxTextExtent));
362    status=AddValueToSplayTree(xpm_colors,ConstantString(key),(void *) j);
363    /*
364      Parse color.
365    */
366    (void) CopyMagickString(target,"gray",MaxTextExtent);
367    q=ParseXPMColor(p+width);
368    if (q != (char *) NULL)
369      {
370        while ((isspace((int) ((unsigned char) *q)) == 0) && (*q != '\0'))
371          q++;
372        if (next != (char *) NULL)
373          (void) CopyXPMColor(target,q,MagickMin((size_t) (next-q),
374            MaxTextExtent));
375        else
376          (void) CopyMagickString(target,q,MaxTextExtent);
377        q=ParseXPMColor(target);
378        if (q != (char *) NULL)
379          *q='\0';
380      }
381    StripString(target);
382    if (LocaleCompare(target,"none") == 0)
383      {
384        image->storage_class=DirectClass;
385        image->matte=MagickTrue;
386      }
387    if (QueryColorDatabase(target,&image->colormap[j],exception) == MagickFalse)
388      break;
389  }
390  if (j < (ssize_t) image->colors)
391    ThrowReaderException(CorruptImageError,"CorruptImage");
392  j=0;
393  if (image_info->ping == MagickFalse)
394    {
395      /*
396        Read image pixels.
397      */
398      for (y=0; y < (ssize_t) image->rows; y++)
399      {
400        p=NextXPMLine(p);
401        if (p == (char *) NULL)
402          break;
403        r=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
404        if (r == (PixelPacket *) NULL)
405          break;
406        indexes=GetAuthenticIndexQueue(image);
407        for (x=0; x < (ssize_t) image->columns; x++)
408        {
409          (void) CopyXPMColor(key,p,(size_t) width);
410          j=(ssize_t) GetValueFromSplayTree(xpm_colors,key);
411          if (image->storage_class == PseudoClass)
412            indexes[x]=(IndexPacket) j;
413          *r=image->colormap[j];
414          r++;
415          p+=width;
416        }
417        if (SyncAuthenticPixels(image,exception) == MagickFalse)
418          break;
419      }
420      if (y < (ssize_t) image->rows)
421        ThrowReaderException(CorruptImageError,"NotEnoughPixelData");
422    }
423  /*
424    Relinquish resources.
425  */
426  xpm_colors=DestroySplayTree(xpm_colors);
427  (void) CloseBlob(image);
428  return(GetFirstImageInList(image));
429}
430
431/*
432%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
433%                                                                             %
434%                                                                             %
435%                                                                             %
436%   R e g i s t e r X P M I m a g e                                           %
437%                                                                             %
438%                                                                             %
439%                                                                             %
440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441%
442%  RegisterXPMImage() adds attributes for the XPM image format to
443%  the list of supported formats.  The attributes include the image format
444%  tag, a method to read and/or write the format, whether the format
445%  supports the saving of more than one frame to the same file or blob,
446%  whether the format supports native in-memory I/O, and a brief
447%  description of the format.
448%
449%  The format of the RegisterXPMImage method is:
450%
451%      size_t RegisterXPMImage(void)
452%
453*/
454ModuleExport size_t RegisterXPMImage(void)
455{
456  MagickInfo
457    *entry;
458
459  entry=SetMagickInfo("PICON");
460  entry->decoder=(DecodeImageHandler *) ReadXPMImage;
461  entry->encoder=(EncodeImageHandler *) WritePICONImage;
462  entry->adjoin=MagickFalse;
463  entry->description=ConstantString("Personal Icon");
464  entry->module=ConstantString("XPM");
465  (void) RegisterMagickInfo(entry);
466  entry=SetMagickInfo("PM");
467  entry->decoder=(DecodeImageHandler *) ReadXPMImage;
468  entry->encoder=(EncodeImageHandler *) WriteXPMImage;
469  entry->adjoin=MagickFalse;
470  entry->stealth=MagickTrue;
471  entry->description=ConstantString("X Windows system pixmap (color)");
472  entry->module=ConstantString("XPM");
473  (void) RegisterMagickInfo(entry);
474  entry=SetMagickInfo("XPM");
475  entry->decoder=(DecodeImageHandler *) ReadXPMImage;
476  entry->encoder=(EncodeImageHandler *) WriteXPMImage;
477  entry->magick=(IsImageFormatHandler *) IsXPM;
478  entry->adjoin=MagickFalse;
479  entry->description=ConstantString("X Windows system pixmap (color)");
480  entry->module=ConstantString("XPM");
481  (void) RegisterMagickInfo(entry);
482  return(MagickImageCoderSignature);
483}
484
485/*
486%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
487%                                                                             %
488%                                                                             %
489%                                                                             %
490%   U n r e g i s t e r X P M I m a g e                                       %
491%                                                                             %
492%                                                                             %
493%                                                                             %
494%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495%
496%  UnregisterXPMImage() removes format registrations made by the
497%  XPM module from the list of supported formats.
498%
499%  The format of the UnregisterXPMImage method is:
500%
501%      UnregisterXPMImage(void)
502%
503*/
504ModuleExport void UnregisterXPMImage(void)
505{
506  (void) UnregisterMagickInfo("PICON");
507  (void) UnregisterMagickInfo("PM");
508  (void) UnregisterMagickInfo("XPM");
509}
510
511/*
512%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
513%                                                                             %
514%                                                                             %
515%                                                                             %
516%   W r i t e P I C O N I m a g e                                             %
517%                                                                             %
518%                                                                             %
519%                                                                             %
520%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
521%
522%  Procedure WritePICONImage() writes an image to a file in the Personal Icon
523%  format.
524%
525%  The format of the WritePICONImage method is:
526%
527%      MagickBooleanType WritePICONImage(const ImageInfo *image_info,
528%        Image *image)
529%
530%  A description of each parameter follows.
531%
532%    o image_info: the image info.
533%
534%    o image:  The image.
535%
536*/
537static MagickBooleanType WritePICONImage(const ImageInfo *image_info,
538  Image *image)
539{
540#define ColormapExtent  155
541#define GraymapExtent  95
542#define PiconGeometry  "48x48>"
543
544  static unsigned char
545    Colormap[]=
546    {
547      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x06, 0x00, 0x05, 0x00, 0xf4, 0x05,
548      0x00, 0x00, 0x00, 0x00, 0x2f, 0x4f, 0x4f, 0x70, 0x80, 0x90, 0x7e, 0x7e,
549      0x7e, 0xdc, 0xdc, 0xdc, 0xff, 0xff, 0xff, 0x00, 0x00, 0x80, 0x00, 0x00,
550      0xff, 0x1e, 0x90, 0xff, 0x87, 0xce, 0xeb, 0xe6, 0xe6, 0xfa, 0x00, 0xff,
551      0xff, 0x80, 0x00, 0x80, 0xb2, 0x22, 0x22, 0x2e, 0x8b, 0x57, 0x32, 0xcd,
552      0x32, 0x00, 0xff, 0x00, 0x98, 0xfb, 0x98, 0xff, 0x00, 0xff, 0xff, 0x00,
553      0x00, 0xff, 0x63, 0x47, 0xff, 0xa5, 0x00, 0xff, 0xd7, 0x00, 0xff, 0xff,
554      0x00, 0xee, 0x82, 0xee, 0xa0, 0x52, 0x2d, 0xcd, 0x85, 0x3f, 0xd2, 0xb4,
555      0x8c, 0xf5, 0xde, 0xb3, 0xff, 0xfa, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00,
556      0x00, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
557      0x00, 0x00, 0x06, 0x00, 0x05, 0x00, 0x00, 0x05, 0x18, 0x20, 0x10, 0x08,
558      0x03, 0x51, 0x18, 0x07, 0x92, 0x28, 0x0b, 0xd3, 0x38, 0x0f, 0x14, 0x49,
559      0x13, 0x55, 0x59, 0x17, 0x96, 0x69, 0x1b, 0xd7, 0x85, 0x00, 0x3b,
560    },
561    Graymap[]=
562    {
563      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x04, 0x00, 0x04, 0x00, 0xf3, 0x0f,
564      0x00, 0x00, 0x00, 0x00, 0x12, 0x12, 0x12, 0x21, 0x21, 0x21, 0x33, 0x33,
565      0x33, 0x45, 0x45, 0x45, 0x54, 0x54, 0x54, 0x66, 0x66, 0x66, 0x78, 0x78,
566      0x78, 0x87, 0x87, 0x87, 0x99, 0x99, 0x99, 0xab, 0xab, 0xab, 0xba, 0xba,
567      0xba, 0xcc, 0xcc, 0xcc, 0xde, 0xde, 0xde, 0xed, 0xed, 0xed, 0xff, 0xff,
568      0xff, 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00,
569      0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x04, 0x0c, 0x10, 0x04, 0x31,
570      0x48, 0x31, 0x07, 0x25, 0xb5, 0x58, 0x73, 0x4f, 0x04, 0x00, 0x3b,
571    };
572
573#define MaxCixels  92
574
575  static const char
576    Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
577                         "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
578
579  char
580    buffer[MaxTextExtent],
581    basename[MaxTextExtent],
582    name[MaxTextExtent],
583    symbol[MaxTextExtent];
584
585  ExceptionInfo
586    *exception;
587
588  Image
589    *affinity_image,
590    *picon;
591
592  ImageInfo
593    *blob_info;
594
595  ssize_t
596    j,
597    k,
598    y;
599
600  MagickBooleanType
601    status,
602    transparent;
603
604  MagickPixelPacket
605    pixel;
606
607  QuantizeInfo
608    *quantize_info;
609
610  RectangleInfo
611    geometry;
612
613  register const IndexPacket
614    *indexes;
615
616  register const PixelPacket
617    *p;
618
619  register ssize_t
620    i,
621    x;
622
623  register PixelPacket
624    *q;
625
626  size_t
627    characters_per_pixel,
628    colors;
629
630  /*
631    Open output image file.
632  */
633  assert(image_info != (const ImageInfo *) NULL);
634  assert(image_info->signature == MagickSignature);
635  assert(image != (Image *) NULL);
636  assert(image->signature == MagickSignature);
637  if (image->debug != MagickFalse)
638    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
639  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
640  if (status == MagickFalse)
641    return(status);
642  if (image->colorspace != RGBColorspace)
643    (void) TransformImageColorspace(image,RGBColorspace);
644  SetGeometry(image,&geometry);
645  (void) ParseMetaGeometry(PiconGeometry,&geometry.x,&geometry.y,
646    &geometry.width,&geometry.height);
647  picon=ResizeImage(image,geometry.width,geometry.height,TriangleFilter,1.0,
648    &image->exception);
649  blob_info=CloneImageInfo(image_info);
650  (void) AcquireUniqueFilename(blob_info->filename);
651  if ((image_info->type != TrueColorType) &&
652      (IsGrayImage(image,&image->exception) != MagickFalse))
653    affinity_image=BlobToImage(blob_info,Graymap,GraymapExtent,
654      &image->exception);
655  else
656    affinity_image=BlobToImage(blob_info,Colormap,ColormapExtent,
657      &image->exception);
658  (void) RelinquishUniqueFileResource(blob_info->filename);
659  blob_info=DestroyImageInfo(blob_info);
660  if ((picon == (Image *) NULL) || (affinity_image == (Image *) NULL))
661    return(MagickFalse);
662  quantize_info=AcquireQuantizeInfo(image_info);
663  status=RemapImage(quantize_info,picon,affinity_image);
664  quantize_info=DestroyQuantizeInfo(quantize_info);
665  affinity_image=DestroyImage(affinity_image);
666  transparent=MagickFalse;
667  exception=(&image->exception);
668  if (picon->storage_class == PseudoClass)
669    {
670      (void) CompressImageColormap(picon);
671      if (picon->matte != MagickFalse)
672        transparent=MagickTrue;
673    }
674  else
675    {
676      /*
677        Convert DirectClass to PseudoClass picon.
678      */
679      if (picon->matte != MagickFalse)
680        {
681          /*
682            Map all the transparent pixels.
683          */
684          for (y=0; y < (ssize_t) picon->rows; y++)
685          {
686            q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
687            if (q == (PixelPacket *) NULL)
688              break;
689            for (x=0; x < (ssize_t) picon->columns; x++)
690            {
691              if (q->opacity == (Quantum) TransparentOpacity)
692                transparent=MagickTrue;
693              else
694                SetOpacityPixelComponent(q,OpaqueOpacity);
695              q++;
696            }
697            if (SyncAuthenticPixels(picon,exception) == MagickFalse)
698              break;
699          }
700        }
701      (void) SetImageType(picon,PaletteType);
702    }
703  colors=picon->colors;
704  if (transparent != MagickFalse)
705    {
706      register IndexPacket
707        *indexes;
708
709      colors++;
710      picon->colormap=(PixelPacket *) ResizeQuantumMemory((void **)
711        picon->colormap,(size_t) colors,sizeof(*picon->colormap));
712      if (picon->colormap == (PixelPacket *) NULL)
713        ThrowWriterException(ResourceLimitError,"MemoryAllocationError");
714      for (y=0; y < (ssize_t) picon->rows; y++)
715      {
716        q=GetAuthenticPixels(picon,0,y,picon->columns,1,exception);
717        if (q == (PixelPacket *) NULL)
718          break;
719        indexes=GetAuthenticIndexQueue(picon);
720        for (x=0; x < (ssize_t) picon->columns; x++)
721        {
722          if (q->opacity == (Quantum) TransparentOpacity)
723            indexes[x]=(IndexPacket) picon->colors;
724          q++;
725        }
726        if (SyncAuthenticPixels(picon,exception) == MagickFalse)
727          break;
728      }
729    }
730  /*
731    Compute the character per pixel.
732  */
733  characters_per_pixel=1;
734  for (k=MaxCixels; (ssize_t) colors > k; k*=MaxCixels)
735    characters_per_pixel++;
736  /*
737    XPM header.
738  */
739  (void) WriteBlobString(image,"/* XPM */\n");
740  GetPathComponent(picon->filename,BasePath,basename);
741  (void) FormatMagickString(buffer,MaxTextExtent,
742    "static char *%s[] = {\n",basename);
743  (void) WriteBlobString(image,buffer);
744  (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
745  (void) FormatMagickString(buffer,MaxTextExtent,"\"%lu %lu %lu %lu\",\n",
746    (unsigned long) picon->columns,(unsigned long) picon->rows,(unsigned long)
747    colors,(unsigned long) characters_per_pixel);
748  (void) WriteBlobString(image,buffer);
749  GetMagickPixelPacket(image,&pixel);
750  for (i=0; i < (ssize_t) colors; i++)
751  {
752    /*
753      Define XPM color.
754    */
755    SetMagickPixelPacket(image,picon->colormap+i,(IndexPacket *) NULL,&pixel);
756    pixel.colorspace=RGBColorspace;
757    pixel.depth=8;
758    pixel.opacity=(MagickRealType) OpaqueOpacity;
759    (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
760      &image->exception);
761    if (transparent != MagickFalse)
762      {
763        if (i == (ssize_t) (colors-1))
764          (void) CopyMagickString(name,"grey75",MaxTextExtent);
765      }
766    /*
767      Write XPM color.
768    */
769    k=i % MaxCixels;
770    symbol[0]=Cixel[k];
771    for (j=1; j < (ssize_t) characters_per_pixel; j++)
772    {
773      k=((i-k)/MaxCixels) % MaxCixels;
774      symbol[j]=Cixel[k];
775    }
776    symbol[j]='\0';
777    (void) FormatMagickString(buffer,MaxTextExtent,"\"%s c %s\",\n",
778       symbol,name);
779    (void) WriteBlobString(image,buffer);
780  }
781  /*
782    Define XPM pixels.
783  */
784  (void) WriteBlobString(image,"/* pixels */\n");
785  for (y=0; y < (ssize_t) picon->rows; y++)
786  {
787    p=GetVirtualPixels(picon,0,y,picon->columns,1,&picon->exception);
788    if (p == (const PixelPacket *) NULL)
789      break;
790    indexes=GetVirtualIndexQueue(picon);
791    (void) WriteBlobString(image,"\"");
792    for (x=0; x < (ssize_t) picon->columns; x++)
793    {
794      k=((ssize_t) indexes[x] % MaxCixels);
795      symbol[0]=Cixel[k];
796      for (j=1; j < (ssize_t) characters_per_pixel; j++)
797      {
798        k=(((int) indexes[x]-k)/MaxCixels) % MaxCixels;
799        symbol[j]=Cixel[k];
800      }
801      symbol[j]='\0';
802      (void) CopyMagickString(buffer,symbol,MaxTextExtent);
803      (void) WriteBlobString(image,buffer);
804    }
805    (void) FormatMagickString(buffer,MaxTextExtent,"\"%s\n",
806      y == (ssize_t) (picon->rows-1) ? "" : ",");
807    (void) WriteBlobString(image,buffer);
808    status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
809      picon->rows);
810    if (status == MagickFalse)
811      break;
812  }
813  picon=DestroyImage(picon);
814  (void) WriteBlobString(image,"};\n");
815  (void) CloseBlob(image);
816  return(MagickTrue);
817}
818
819/*
820%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
821%                                                                             %
822%                                                                             %
823%                                                                             %
824%   W r i t e X P M I m a g e                                                 %
825%                                                                             %
826%                                                                             %
827%                                                                             %
828%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
829%
830%  Procedure WriteXPMImage() writes an image to a file in the X pixmap format.
831%
832%  The format of the WriteXPMImage method is:
833%
834%      MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
835%
836%  A description of each parameter follows.
837%
838%    o image_info: the image info.
839%
840%    o image:  The image.
841%
842%
843*/
844static MagickBooleanType WriteXPMImage(const ImageInfo *image_info,Image *image)
845{
846#define MaxCixels  92
847
848  static const char
849    Cixel[MaxCixels+1] = " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk"
850                         "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|";
851
852  char
853    buffer[MaxTextExtent],
854    basename[MaxTextExtent],
855    name[MaxTextExtent],
856    symbol[MaxTextExtent];
857
858  ssize_t
859    j,
860    k,
861    opacity,
862    y;
863
864  MagickBooleanType
865    status;
866
867  MagickPixelPacket
868    pixel;
869
870  register const IndexPacket
871    *indexes;
872
873  register const PixelPacket
874    *p;
875
876  register ssize_t
877    i,
878    x;
879
880  size_t
881    characters_per_pixel;
882
883  /*
884    Open output image file.
885  */
886  assert(image_info != (const ImageInfo *) NULL);
887  assert(image_info->signature == MagickSignature);
888  assert(image != (Image *) NULL);
889  assert(image->signature == MagickSignature);
890  if (image->debug != MagickFalse)
891    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
892  status=OpenBlob(image_info,image,WriteBinaryBlobMode,&image->exception);
893  if (status == MagickFalse)
894    return(status);
895  if (image->colorspace != RGBColorspace)
896    (void) TransformImageColorspace(image,RGBColorspace);
897  opacity=(-1);
898  if (image->matte == MagickFalse)
899    {
900      if ((image->storage_class == DirectClass) || (image->colors > 256))
901        (void) SetImageType(image,PaletteType);
902    }
903  else
904    {
905      MagickRealType
906        alpha,
907        beta;
908
909      /*
910        Identify transparent colormap index.
911      */
912      if ((image->storage_class == DirectClass) || (image->colors > 256))
913        (void) SetImageType(image,PaletteBilevelMatteType);
914      for (i=0; i < (ssize_t) image->colors; i++)
915        if (image->colormap[i].opacity != OpaqueOpacity)
916          {
917            if (opacity < 0)
918              {
919                opacity=i;
920                continue;
921              }
922            alpha=(Quantum) TransparentOpacity-(MagickRealType)
923              image->colormap[i].opacity;
924            beta=(Quantum) TransparentOpacity-(MagickRealType)
925              image->colormap[opacity].opacity;
926            if (alpha < beta)
927              opacity=i;
928          }
929      if (opacity == -1)
930        {
931          (void) SetImageType(image,PaletteBilevelMatteType);
932          for (i=0; i < (ssize_t) image->colors; i++)
933            if (image->colormap[i].opacity != OpaqueOpacity)
934              {
935                if (opacity < 0)
936                  {
937                    opacity=i;
938                    continue;
939                  }
940                alpha=(Quantum) TransparentOpacity-(MagickRealType)
941                  image->colormap[i].opacity;
942                beta=(Quantum) TransparentOpacity-(MagickRealType)
943                  image->colormap[opacity].opacity;
944                if (alpha < beta)
945                  opacity=i;
946              }
947        }
948      if (opacity >= 0)
949        {
950          image->colormap[opacity].red=image->transparent_color.red;
951          image->colormap[opacity].green=image->transparent_color.green;
952          image->colormap[opacity].blue=image->transparent_color.blue;
953        }
954    }
955  /*
956    Compute the character per pixel.
957  */
958  characters_per_pixel=1;
959  for (k=MaxCixels; (ssize_t) image->colors > k; k*=MaxCixels)
960    characters_per_pixel++;
961  /*
962    XPM header.
963  */
964  (void) WriteBlobString(image,"/* XPM */\n");
965  GetPathComponent(image->filename,BasePath,basename);
966  if (isalnum((int) ((unsigned char) *basename)) == 0)
967    {
968      (void) FormatMagickString(buffer,MaxTextExtent,"xpm_%s",basename);
969      (void) CopyMagickString(basename,buffer,MaxTextExtent);
970    }
971  for (i=0; basename[i] != '\0'; i++)
972    if (isalpha((int) ((unsigned char) basename[i])) == 0)
973      basename[i]='_';
974  (void) FormatMagickString(buffer,MaxTextExtent,
975    "static char *%s[] = {\n",basename);
976  (void) WriteBlobString(image,buffer);
977  (void) WriteBlobString(image,"/* columns rows colors chars-per-pixel */\n");
978  (void) FormatMagickString(buffer,MaxTextExtent,"\"%lu %lu %lu %lu\",\n",
979    (unsigned long) image->columns,(unsigned long) image->rows,(unsigned long)
980    image->colors,(unsigned long) characters_per_pixel);
981  (void) WriteBlobString(image,buffer);
982  GetMagickPixelPacket(image,&pixel);
983  for (i=0; i < (ssize_t) image->colors; i++)
984  {
985    /*
986      Define XPM color.
987    */
988    SetMagickPixelPacket(image,image->colormap+i,(IndexPacket *) NULL,&pixel);
989    pixel.colorspace=RGBColorspace;
990    pixel.depth=8;
991    pixel.opacity=(MagickRealType) OpaqueOpacity;
992    (void) QueryMagickColorname(image,&pixel,XPMCompliance,name,
993      &image->exception);
994    if (i == opacity)
995      (void) CopyMagickString(name,"None",MaxTextExtent);
996    /*
997      Write XPM color.
998    */
999    k=i % MaxCixels;
1000    symbol[0]=Cixel[k];
1001    for (j=1; j < (ssize_t) characters_per_pixel; j++)
1002    {
1003      k=((i-k)/MaxCixels) % MaxCixels;
1004      symbol[j]=Cixel[k];
1005    }
1006    symbol[j]='\0';
1007    (void) FormatMagickString(buffer,MaxTextExtent,"\"%s c %s\",\n",symbol,
1008      name);
1009    (void) WriteBlobString(image,buffer);
1010  }
1011  /*
1012    Define XPM pixels.
1013  */
1014  (void) WriteBlobString(image,"/* pixels */\n");
1015  for (y=0; y < (ssize_t) image->rows; y++)
1016  {
1017    p=GetVirtualPixels(image,0,y,image->columns,1,&image->exception);
1018    if (p == (const PixelPacket *) NULL)
1019      break;
1020    indexes=GetVirtualIndexQueue(image);
1021    (void) WriteBlobString(image,"\"");
1022    for (x=0; x < (ssize_t) image->columns; x++)
1023    {
1024      k=((ssize_t) indexes[x] % MaxCixels);
1025      symbol[0]=Cixel[k];
1026      for (j=1; j < (ssize_t) characters_per_pixel; j++)
1027      {
1028        k=(((int) indexes[x]-k)/MaxCixels) % MaxCixels;
1029        symbol[j]=Cixel[k];
1030      }
1031      symbol[j]='\0';
1032      (void) CopyMagickString(buffer,symbol,MaxTextExtent);
1033      (void) WriteBlobString(image,buffer);
1034    }
1035    (void) FormatMagickString(buffer,MaxTextExtent,"\"%s\n",
1036      (y == (ssize_t) (image->rows-1) ? "" : ","));
1037    (void) WriteBlobString(image,buffer);
1038    if (image->previous == (Image *) NULL)
1039      {
1040        status=SetImageProgress(image,SaveImageTag,(MagickOffsetType) y,
1041          image->rows);
1042        if (status == MagickFalse)
1043          break;
1044      }
1045  }
1046  (void) WriteBlobString(image,"};\n");
1047  (void) CloseBlob(image);
1048  return(MagickTrue);
1049}
1050