]> granicus.if.org Git - imagemagick/blob - MagickCore/pixel.c
(no commit message)
[imagemagick] / MagickCore / pixel.c
1 /*
2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 %                                                                             %
4 %                                                                             %
5 %                                                                             %
6 %                      PPPP   IIIII  X   X  EEEEE  L                          %
7 %                      P   P    I     X X   E      L                          %
8 %                      PPPP     I      X    EEE    L                          %
9 %                      P        I     X X   E      L                          %
10 %                      P      IIIII  X   X  EEEEE  LLLLL                      %
11 %                                                                             %
12 %                  MagickCore Methods to Import/Export Pixels                 %
13 %                                                                             %
14 %                             Software Design                                 %
15 %                               John Cristy                                   %
16 %                               October 1998                                  %
17 %                                                                             %
18 %                                                                             %
19 %  Copyright 1999-2013 ImageMagick Studio LLC, a non-profit organization      %
20 %  dedicated to making software imaging solutions freely available.           %
21 %                                                                             %
22 %  You may not use this file except in compliance with the License.  You may  %
23 %  obtain a copy of the License at                                            %
24 %                                                                             %
25 %    http://www.imagemagick.org/script/license.php                            %
26 %                                                                             %
27 %  Unless required by applicable law or agreed to in writing, software        %
28 %  distributed under the License is distributed on an "AS IS" BASIS,          %
29 %  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
30 %  See the License for the specific language governing permissions and        %
31 %  limitations under the License.                                             %
32 %                                                                             %
33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
34 %
35 %
36 */
37 \f
38 /*
39   Include declarations.
40 */
41 #include "MagickCore/studio.h"
42 #include "MagickCore/property.h"
43 #include "MagickCore/blob.h"
44 #include "MagickCore/blob-private.h"
45 #include "MagickCore/cache-private.h"
46 #include "MagickCore/color-private.h"
47 #include "MagickCore/draw.h"
48 #include "MagickCore/exception.h"
49 #include "MagickCore/exception-private.h"
50 #include "MagickCore/cache.h"
51 #include "MagickCore/constitute.h"
52 #include "MagickCore/delegate.h"
53 #include "MagickCore/geometry.h"
54 #include "MagickCore/image-private.h"
55 #include "MagickCore/list.h"
56 #include "MagickCore/magick.h"
57 #include "MagickCore/memory_.h"
58 #include "MagickCore/monitor.h"
59 #include "MagickCore/option.h"
60 #include "MagickCore/pixel.h"
61 #include "MagickCore/pixel-accessor.h"
62 #include "MagickCore/pixel-private.h"
63 #include "MagickCore/quantum.h"
64 #include "MagickCore/quantum-private.h"
65 #include "MagickCore/resource_.h"
66 #include "MagickCore/semaphore.h"
67 #include "MagickCore/statistic.h"
68 #include "MagickCore/stream.h"
69 #include "MagickCore/string_.h"
70 #include "MagickCore/transform.h"
71 #include "MagickCore/utility.h"
72 \f
73 #define LogPixelChannels(image) \
74 { \
75   register ssize_t \
76     i; \
77  \
78   (void) LogMagickEvent(PixelEvent,GetMagickModule(),"%s[%.20g]", \
79     image->filename,(double) image->number_channels); \
80   for (i=0; i < (ssize_t) image->number_channels; i++) \
81   { \
82     char \
83       traits[MaxTextExtent]; \
84  \
85     const char \
86       *name; \
87  \
88     PixelChannel \
89       channel; \
90  \
91     switch (GetPixelChannelChannel(image,i)) \
92     { \
93       case RedPixelChannel: \
94       { \
95         name="red"; \
96         if (image->colorspace == CMYKColorspace) \
97           name="cyan"; \
98         if (image->colorspace == GRAYColorspace) \
99           name="gray"; \
100         break; \
101       } \
102       case GreenPixelChannel: \
103       { \
104         name="green"; \
105         if (image->colorspace == CMYKColorspace) \
106           name="magenta"; \
107         break; \
108       } \
109       case BluePixelChannel: \
110       { \
111         name="blue"; \
112         if (image->colorspace == CMYKColorspace) \
113           name="yellow"; \
114         break; \
115       } \
116       case BlackPixelChannel: \
117       { \
118         name="black"; \
119         if (image->storage_class == PseudoClass) \
120           name="index"; \
121         break; \
122       } \
123       case IndexPixelChannel: \
124       { \
125         name="index"; \
126         break; \
127       } \
128       case AlphaPixelChannel: \
129       { \
130         name="alpha"; \
131         break; \
132       } \
133       case MaskPixelChannel: \
134       { \
135         name="mask"; \
136         break; \
137       } \
138       case MetaPixelChannel: \
139       { \
140         name="meta"; \
141         break; \
142       } \
143       default: \
144         name="undefined"; \
145     } \
146     channel=GetPixelChannelChannel(image,i); \
147     *traits='\0'; \
148     if ((GetPixelChannelTraits(image,channel) & UpdatePixelTrait) != 0) \
149       (void) ConcatenateMagickString(traits,"update,",MaxTextExtent); \
150     if ((GetPixelChannelTraits(image,channel) & BlendPixelTrait) != 0) \
151       (void) ConcatenateMagickString(traits,"blend,",MaxTextExtent); \
152     if ((GetPixelChannelTraits(image,channel) & CopyPixelTrait) != 0) \
153       (void) ConcatenateMagickString(traits,"copy,",MaxTextExtent); \
154     if (*traits == '\0') \
155       (void) ConcatenateMagickString(traits,"undefined,",MaxTextExtent); \
156     traits[strlen(traits)-1]='\0'; \
157     (void) LogMagickEvent(PixelEvent,GetMagickModule(),"  %.20g: %s (%s)", \
158       (double) i,name,traits); \
159   } \
160 }
161 \f
162 /*
163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164 %                                                                             %
165 %                                                                             %
166 %                                                                             %
167 +   A c q u i r e P i x e l C h a n n e l M a p                               %
168 %                                                                             %
169 %                                                                             %
170 %                                                                             %
171 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 %
173 %  AcquirePixelChannelMap() acquires a pixel component map.
174 %
175 %  The format of the AcquirePixelChannelMap() method is:
176 %
177 %      PixelChannelMap *AcquirePixelChannelMap(void)
178 %
179 */
180 MagickExport PixelChannelMap *AcquirePixelChannelMap(void)
181 {
182   PixelChannelMap
183     *channel_map;
184
185   register ssize_t
186     i;
187
188   channel_map=(PixelChannelMap *) AcquireQuantumMemory(MaxPixelChannels,
189     sizeof(*channel_map));
190   if (channel_map == (PixelChannelMap *) NULL)
191     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
192   (void) ResetMagickMemory(channel_map,0,MaxPixelChannels*sizeof(*channel_map));
193   for (i=0; i < MaxPixelChannels; i++)
194     channel_map[i].channel=(PixelChannel) i;
195   return(channel_map);
196 }
197 \f
198 /*
199 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200 %                                                                             %
201 %                                                                             %
202 %                                                                             %
203 +   C l o n e P i x e l C h a n n e l M a p                                   %
204 %                                                                             %
205 %                                                                             %
206 %                                                                             %
207 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208 %
209 %  ClonePixelChannelMap() clones a pixel component map.
210 %
211 %  The format of the ClonePixelChannelMap() method is:
212 %
213 %      PixelChannelMap *ClonePixelChannelMap(PixelChannelMap *channel_map)
214 %
215 %  A description of each parameter follows:
216 %
217 %    o channel_map: the pixel component map.
218 %
219 */
220 MagickExport PixelChannelMap *ClonePixelChannelMap(PixelChannelMap *channel_map)
221 {
222   PixelChannelMap
223     *clone_map;
224
225   assert(channel_map != (PixelChannelMap *) NULL);
226   clone_map=AcquirePixelChannelMap();
227   if (clone_map == (PixelChannelMap *) NULL)
228     return((PixelChannelMap *) NULL);
229   (void) CopyMagickMemory(clone_map,channel_map,MaxPixelChannels*
230     sizeof(*channel_map));
231   return(clone_map);
232 }
233 \f
234 /*
235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236 %                                                                             %
237 %                                                                             %
238 %                                                                             %
239 +   C l o n e P i x e l I n f o                                               %
240 %                                                                             %
241 %                                                                             %
242 %                                                                             %
243 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244 %
245 %  ClonePixelInfo() makes a duplicate of the given pixel info structure, or if
246 %  pixel info is NULL, a new one.
247 %
248 %  The format of the ClonePixelInfo method is:
249 %
250 %      PixelInfo *ClonePixelInfo(const PixelInfo *pixel_info)
251 %
252 %  A description of each parameter follows:
253 %
254 %    o pixel_info: the pixel info.
255 %
256 */
257 MagickExport PixelInfo *ClonePixelInfo(const PixelInfo *pixel)
258 {
259   PixelInfo
260     *pixel_info;
261
262   pixel_info=(PixelInfo *) AcquireQuantumMemory(1,sizeof(*pixel_info));
263   if (pixel_info == (PixelInfo *) NULL)
264     ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
265   *pixel_info=(*pixel);
266   return(pixel_info);
267 }
268 \f
269 /*
270 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271 %                                                                             %
272 %                                                                             %
273 %                                                                             %
274 %   D e c o d e P i x e l G a m m a                                           %
275 %                                                                             %
276 %                                                                             %
277 %                                                                             %
278 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279 %
280 %  DecodePixelGamma() applies the expansive power-law nonlinearity to the pixel.
281 %
282 %  The format of the DecodePixelGammaImage method is:
283 %
284 %      double DecodePixelGamma(const MagickRealType pixel)
285 %
286 %  A description of each parameter follows:
287 %
288 %    o pixel: the pixel.
289 %
290 */
291 MagickExport MagickRealType DecodePixelGamma(const MagickRealType pixel)
292 {
293   if (pixel <= (0.0404482362771076*QuantumRange))
294     return(pixel/12.92f);
295   return((MagickRealType) (QuantumRange*pow((double) (QuantumScale*pixel+
296     0.055)/1.055,2.4)));
297 }
298 \f
299 /*
300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301 %                                                                             %
302 %                                                                             %
303 %                                                                             %
304 +   D e s t r o y P i x e l C h a n n e l M a p                               %
305 %                                                                             %
306 %                                                                             %
307 %                                                                             %
308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309 %
310 %  DestroyPixelChannelMap() deallocates memory associated with the pixel
311 %  channel map.
312 %
313 %  The format of the DestroyPixelChannelMap() method is:
314 %
315 %      PixelChannelMap *DestroyPixelChannelMap(PixelChannelMap *channel_map)
316 %
317 %  A description of each parameter follows:
318 %
319 %    o channel_map: the pixel component map.
320 %
321 */
322 MagickExport PixelChannelMap *DestroyPixelChannelMap(
323   PixelChannelMap *channel_map)
324 {
325   assert(channel_map != (PixelChannelMap *) NULL);
326   channel_map=(PixelChannelMap *) RelinquishMagickMemory(channel_map);
327   return((PixelChannelMap *) RelinquishMagickMemory(channel_map));
328 }
329 \f
330 /*
331 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332 %                                                                             %
333 %                                                                             %
334 %                                                                             %
335 +   E n c o d e P i x e l G a m m a                                           %
336 %                                                                             %
337 %                                                                             %
338 %                                                                             %
339 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 %
341 %  EncodePixelGamma() cancels any nonlinearity in the pixel.
342 %
343 %  The format of the EncodePixelGammaImage method is:
344 %
345 %      MagickRealType EncodePixelGamma(const double MagickRealType)
346 %
347 %  A description of each parameter follows:
348 %
349 %    o pixel: the pixel.
350 %
351 */
352 MagickExport MagickRealType EncodePixelGamma(const MagickRealType pixel)
353 {
354   if (pixel <= (0.0031306684425005883*QuantumRange))
355     return(12.92f*pixel);
356   return((MagickRealType) QuantumRange*(1.055*pow((double) QuantumScale*pixel,
357     1.0/2.4)-0.055));
358 }
359 \f
360 /*
361 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 %                                                                             %
363 %                                                                             %
364 %                                                                             %
365 %   E x p o r t I m a g e P i x e l s                                         %
366 %                                                                             %
367 %                                                                             %
368 %                                                                             %
369 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 %
371 %  ExportImagePixels() extracts pixel data from an image and returns it to you.
372 %  The method returns MagickTrue on success otherwise MagickFalse if an error is
373 %  encountered.  The data is returned as char, short int, Quantum, unsigned int,
374 %  unsigned long long, float, or double in the order specified by map.
375 %
376 %  Suppose you want to extract the first scanline of a 640x480 image as
377 %  character data in red-green-blue order:
378 %
379 %      ExportImagePixels(image,0,0,640,1,"RGB",CharPixel,pixels,exception);
380 %
381 %  The format of the ExportImagePixels method is:
382 %
383 %      MagickBooleanType ExportImagePixels(const Image *image,const ssize_t x,
384 %        const ssize_t y,const size_t width,const size_t height,
385 %        const char *map,const StorageType type,void *pixels,
386 %        ExceptionInfo *exception)
387 %
388 %  A description of each parameter follows:
389 %
390 %    o image: the image.
391 %
392 %    o x,y,width,height:  These values define the perimeter
393 %      of a region of pixels you want to extract.
394 %
395 %    o map:  This string reflects the expected ordering of the pixel array.
396 %      It can be any combination or order of R = red, G = green, B = blue,
397 %      A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
398 %      Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
399 %      P = pad.
400 %
401 %    o type: Define the data type of the pixels.  Float and double types are
402 %      normalized to [0..1] otherwise [0..QuantumRange].  Choose from these
403 %      types: CharPixel (char *), DoublePixel (double *), FloatPixel (float *),
404 %      LongPixel (unsigned int *), LongLongPixel (unsigned long long *),
405 %      QuantumPixel (Quantum *), or ShortPixel (unsigned short *).
406 %
407 %    o pixels: This array of values contain the pixel components as defined by
408 %      map and type.  You must preallocate this array where the expected
409 %      length varies depending on the values of width, height, map, and type.
410 %
411 %    o exception: return any errors or warnings in this structure.
412 %
413 */
414
415 static void ExportCharPixel(Image *image,const RectangleInfo *roi,
416   const char *restrict map,const QuantumType *quantum_map,void *pixels,
417   ExceptionInfo *exception)
418 {
419   register const Quantum
420     *restrict p;
421
422   register ssize_t
423     x;
424
425   register unsigned char
426     *restrict q;
427
428   size_t
429     length;
430
431   ssize_t
432     y;
433
434   q=(unsigned char *) pixels;
435   if (LocaleCompare(map,"BGR") == 0)
436     {
437       for (y=0; y < (ssize_t) roi->height; y++)
438       {
439         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
440         if (p == (const Quantum *) NULL)
441           break;
442         for (x=0; x < (ssize_t) roi->width; x++)
443         {
444           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
445           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
446           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
447           p+=GetPixelChannels(image);
448         }
449       }
450       return;
451     }
452   if (LocaleCompare(map,"BGRA") == 0)
453     {
454       for (y=0; y < (ssize_t) roi->height; y++)
455       {
456         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
457         if (p == (const Quantum *) NULL)
458           break;
459         for (x=0; x < (ssize_t) roi->width; x++)
460         {
461           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
462           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
463           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
464           *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
465           p+=GetPixelChannels(image);
466         }
467       }
468       return;
469     }
470   if (LocaleCompare(map,"BGRP") == 0)
471     {
472       for (y=0; y < (ssize_t) roi->height; y++)
473       {
474         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
475         if (p == (const Quantum *) NULL)
476           break;
477         for (x=0; x < (ssize_t) roi->width; x++)
478         {
479           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
480           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
481           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
482           *q++=ScaleQuantumToChar((Quantum) 0);
483           p+=GetPixelChannels(image);
484         }
485       }
486       return;
487     }
488   if (LocaleCompare(map,"I") == 0)
489     {
490       for (y=0; y < (ssize_t) roi->height; y++)
491       {
492         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
493         if (p == (const Quantum *) NULL)
494           break;
495         for (x=0; x < (ssize_t) roi->width; x++)
496         {
497           *q++=ScaleQuantumToChar(ClampToQuantum(GetPixelIntensity(image,p)));
498           p+=GetPixelChannels(image);
499         }
500       }
501       return;
502     }
503   if (LocaleCompare(map,"RGB") == 0)
504     {
505       for (y=0; y < (ssize_t) roi->height; y++)
506       {
507         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
508         if (p == (const Quantum *) NULL)
509           break;
510         for (x=0; x < (ssize_t) roi->width; x++)
511         {
512           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
513           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
514           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
515           p+=GetPixelChannels(image);
516         }
517       }
518       return;
519     }
520   if (LocaleCompare(map,"RGBA") == 0)
521     {
522       for (y=0; y < (ssize_t) roi->height; y++)
523       {
524         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
525         if (p == (const Quantum *) NULL)
526           break;
527         for (x=0; x < (ssize_t) roi->width; x++)
528         {
529           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
530           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
531           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
532           *q++=ScaleQuantumToChar(GetPixelAlpha(image,p));
533           p+=GetPixelChannels(image);
534         }
535       }
536       return;
537     }
538   if (LocaleCompare(map,"RGBP") == 0)
539     {
540       for (y=0; y < (ssize_t) roi->height; y++)
541       {
542         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
543         if (p == (const Quantum *) NULL)
544           break;
545         for (x=0; x < (ssize_t) roi->width; x++)
546         {
547           *q++=ScaleQuantumToChar(GetPixelRed(image,p));
548           *q++=ScaleQuantumToChar(GetPixelGreen(image,p));
549           *q++=ScaleQuantumToChar(GetPixelBlue(image,p));
550           *q++=ScaleQuantumToChar((Quantum) 0);
551           p+=GetPixelChannels(image);
552         }
553       }
554       return;
555     }
556   length=strlen(map);
557   for (y=0; y < (ssize_t) roi->height; y++)
558   {
559     p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
560     if (p == (const Quantum *) NULL)
561       break;
562     for (x=0; x < (ssize_t) roi->width; x++)
563     {
564       register ssize_t
565         i;
566
567       for (i=0; i < (ssize_t) length; i++)
568       {
569         *q=0;
570         switch (quantum_map[i])
571         {
572           case RedQuantum:
573           case CyanQuantum:
574           {
575             *q=ScaleQuantumToChar(GetPixelRed(image,p));
576             break;
577           }
578           case GreenQuantum:
579           case MagentaQuantum:
580           {
581             *q=ScaleQuantumToChar(GetPixelGreen(image,p));
582             break;
583           }
584           case BlueQuantum:
585           case YellowQuantum:
586           {
587             *q=ScaleQuantumToChar(GetPixelBlue(image,p));
588             break;
589           }
590           case AlphaQuantum:
591           {
592             *q=ScaleQuantumToChar(GetPixelAlpha(image,p));
593             break;
594           }
595           case OpacityQuantum:
596           {
597             *q=ScaleQuantumToChar(GetPixelAlpha(image,p));
598             break;
599           }
600           case BlackQuantum:
601           {
602             if (image->colorspace == CMYKColorspace)
603               *q=ScaleQuantumToChar(GetPixelBlack(image,p));
604             break;
605           }
606           case IndexQuantum:
607           {
608             *q=ScaleQuantumToChar(ClampToQuantum(GetPixelIntensity(image,p)));
609             break;
610           }
611           default:
612             break;
613         }
614         q++;
615       }
616       p+=GetPixelChannels(image);
617     }
618   }
619 }
620
621 static void ExportDoublePixel(Image *image,const RectangleInfo *roi,
622   const char *restrict map,const QuantumType *quantum_map,void *pixels,
623   ExceptionInfo *exception)
624 {
625   register const Quantum
626     *restrict p;
627
628   register double
629     *restrict q;
630
631   register ssize_t
632     x;
633
634   size_t
635     length;
636
637   ssize_t
638     y;
639
640   q=(double *) pixels;
641   if (LocaleCompare(map,"BGR") == 0)
642     {
643       for (y=0; y < (ssize_t) roi->height; y++)
644       {
645         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
646         if (p == (const Quantum *) NULL)
647           break;
648         for (x=0; x < (ssize_t) roi->width; x++)
649         {
650           *q++=(double) (QuantumScale*GetPixelBlue(image,p));
651           *q++=(double) (QuantumScale*GetPixelGreen(image,p));
652           *q++=(double) (QuantumScale*GetPixelRed(image,p));
653           p+=GetPixelChannels(image);
654         }
655       }
656       return;
657     }
658   if (LocaleCompare(map,"BGRA") == 0)
659     {
660       for (y=0; y < (ssize_t) roi->height; y++)
661       {
662         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
663         if (p == (const Quantum *) NULL)
664           break;
665         for (x=0; x < (ssize_t) roi->width; x++)
666         {
667           *q++=(double) (QuantumScale*GetPixelBlue(image,p));
668           *q++=(double) (QuantumScale*GetPixelGreen(image,p));
669           *q++=(double) (QuantumScale*GetPixelRed(image,p));
670           *q++=(double) (QuantumScale*GetPixelAlpha(image,p));
671           p+=GetPixelChannels(image);
672         }
673       }
674       return;
675     }
676   if (LocaleCompare(map,"BGRP") == 0)
677     {
678       for (y=0; y < (ssize_t) roi->height; y++)
679       {
680         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
681         if (p == (const Quantum *) NULL)
682           break;
683         for (x=0; x < (ssize_t) roi->width; x++)
684         {
685           *q++=(double) (QuantumScale*GetPixelBlue(image,p));
686           *q++=(double) (QuantumScale*GetPixelGreen(image,p));
687           *q++=(double) (QuantumScale*GetPixelRed(image,p));
688           *q++=0.0;
689           p+=GetPixelChannels(image);
690         }
691       }
692       return;
693     }
694   if (LocaleCompare(map,"I") == 0)
695     {
696       for (y=0; y < (ssize_t) roi->height; y++)
697       {
698         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
699         if (p == (const Quantum *) NULL)
700           break;
701         for (x=0; x < (ssize_t) roi->width; x++)
702         {
703           *q++=(double) (QuantumScale*GetPixelIntensity(image,p));
704           p+=GetPixelChannels(image);
705         }
706       }
707       return;
708     }
709   if (LocaleCompare(map,"RGB") == 0)
710     {
711       for (y=0; y < (ssize_t) roi->height; y++)
712       {
713         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
714         if (p == (const Quantum *) NULL)
715           break;
716         for (x=0; x < (ssize_t) roi->width; x++)
717         {
718           *q++=(double) (QuantumScale*GetPixelRed(image,p));
719           *q++=(double) (QuantumScale*GetPixelGreen(image,p));
720           *q++=(double) (QuantumScale*GetPixelBlue(image,p));
721           p+=GetPixelChannels(image);
722         }
723       }
724       return;
725     }
726   if (LocaleCompare(map,"RGBA") == 0)
727     {
728       for (y=0; y < (ssize_t) roi->height; y++)
729       {
730         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
731         if (p == (const Quantum *) NULL)
732           break;
733         for (x=0; x < (ssize_t) roi->width; x++)
734         {
735           *q++=(double) (QuantumScale*GetPixelRed(image,p));
736           *q++=(double) (QuantumScale*GetPixelGreen(image,p));
737           *q++=(double) (QuantumScale*GetPixelBlue(image,p));
738           *q++=(double) (QuantumScale*GetPixelAlpha(image,p));
739           p+=GetPixelChannels(image);
740         }
741       }
742       return;
743     }
744   if (LocaleCompare(map,"RGBP") == 0)
745     {
746       for (y=0; y < (ssize_t) roi->height; y++)
747       {
748         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
749         if (p == (const Quantum *) NULL)
750           break;
751         for (x=0; x < (ssize_t) roi->width; x++)
752         {
753           *q++=(double) (QuantumScale*GetPixelRed(image,p));
754           *q++=(double) (QuantumScale*GetPixelGreen(image,p));
755           *q++=(double) (QuantumScale*GetPixelBlue(image,p));
756           *q++=0.0;
757           p+=GetPixelChannels(image);
758         }
759       }
760       return;
761     }
762   length=strlen(map);
763   for (y=0; y < (ssize_t) roi->height; y++)
764   {
765     p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
766     if (p == (const Quantum *) NULL)
767       break;
768     for (x=0; x < (ssize_t) roi->width; x++)
769     {
770       register ssize_t
771         i;
772
773       for (i=0; i < (ssize_t) length; i++)
774       {
775         *q=0;
776         switch (quantum_map[i])
777         {
778           case RedQuantum:
779           case CyanQuantum:
780           {
781             *q=(double) (QuantumScale*GetPixelRed(image,p));
782             break;
783           }
784           case GreenQuantum:
785           case MagentaQuantum:
786           {
787             *q=(double) (QuantumScale*GetPixelGreen(image,p));
788             break;
789           }
790           case BlueQuantum:
791           case YellowQuantum:
792           {
793             *q=(double) (QuantumScale*GetPixelBlue(image,p));
794             break;
795           }
796           case AlphaQuantum:
797           {
798             *q=(double) (QuantumScale*GetPixelAlpha(image,p));
799             break;
800           }
801           case OpacityQuantum:
802           {
803             *q=(double) (QuantumScale*GetPixelAlpha(image,p));
804             break;
805           }
806           case BlackQuantum:
807           {
808             if (image->colorspace == CMYKColorspace)
809               *q=(double) (QuantumScale*
810                 GetPixelBlack(image,p));
811             break;
812           }
813           case IndexQuantum:
814           {
815             *q=(double) (QuantumScale*GetPixelIntensity(image,p));
816             break;
817           }
818           default:
819             *q=0;
820         }
821         q++;
822       }
823       p+=GetPixelChannels(image);
824     }
825   }
826 }
827
828 static void ExportFloatPixel(Image *image,const RectangleInfo *roi,
829   const char *restrict map,const QuantumType *quantum_map,void *pixels,
830   ExceptionInfo *exception)
831 {
832   register const Quantum
833     *restrict p;
834
835   register float
836     *restrict q;
837
838   register ssize_t
839     x;
840
841   size_t
842     length;
843
844   ssize_t
845     y;
846
847   q=(float *) pixels;
848   if (LocaleCompare(map,"BGR") == 0)
849     {
850       for (y=0; y < (ssize_t) roi->height; y++)
851       {
852         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
853         if (p == (const Quantum *) NULL)
854           break;
855         for (x=0; x < (ssize_t) roi->width; x++)
856         {
857           *q++=(float) (QuantumScale*GetPixelBlue(image,p));
858           *q++=(float) (QuantumScale*GetPixelGreen(image,p));
859           *q++=(float) (QuantumScale*GetPixelRed(image,p));
860           p+=GetPixelChannels(image);
861         }
862       }
863       return;
864     }
865   if (LocaleCompare(map,"BGRA") == 0)
866     {
867       for (y=0; y < (ssize_t) roi->height; y++)
868       {
869         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
870         if (p == (const Quantum *) NULL)
871           break;
872         for (x=0; x < (ssize_t) roi->width; x++)
873         {
874           *q++=(float) (QuantumScale*GetPixelBlue(image,p));
875           *q++=(float) (QuantumScale*GetPixelGreen(image,p));
876           *q++=(float) (QuantumScale*GetPixelRed(image,p));
877           *q++=(float) (QuantumScale*GetPixelAlpha(image,p));
878           p+=GetPixelChannels(image);
879         }
880       }
881       return;
882     }
883   if (LocaleCompare(map,"BGRP") == 0)
884     {
885       for (y=0; y < (ssize_t) roi->height; y++)
886       {
887         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
888         if (p == (const Quantum *) NULL)
889           break;
890         for (x=0; x < (ssize_t) roi->width; x++)
891         {
892           *q++=(float) (QuantumScale*GetPixelBlue(image,p));
893           *q++=(float) (QuantumScale*GetPixelGreen(image,p));
894           *q++=(float) (QuantumScale*GetPixelRed(image,p));
895           *q++=0.0;
896           p+=GetPixelChannels(image);
897         }
898       }
899       return;
900     }
901   if (LocaleCompare(map,"I") == 0)
902     {
903       for (y=0; y < (ssize_t) roi->height; y++)
904       {
905         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
906         if (p == (const Quantum *) NULL)
907           break;
908         for (x=0; x < (ssize_t) roi->width; x++)
909         {
910           *q++=(float) (QuantumScale*GetPixelIntensity(image,p));
911           p+=GetPixelChannels(image);
912         }
913       }
914       return;
915     }
916   if (LocaleCompare(map,"RGB") == 0)
917     {
918       for (y=0; y < (ssize_t) roi->height; y++)
919       {
920         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
921         if (p == (const Quantum *) NULL)
922           break;
923         for (x=0; x < (ssize_t) roi->width; x++)
924         {
925           *q++=(float) (QuantumScale*GetPixelRed(image,p));
926           *q++=(float) (QuantumScale*GetPixelGreen(image,p));
927           *q++=(float) (QuantumScale*GetPixelBlue(image,p));
928           p+=GetPixelChannels(image);
929         }
930       }
931       return;
932     }
933   if (LocaleCompare(map,"RGBA") == 0)
934     {
935       for (y=0; y < (ssize_t) roi->height; y++)
936       {
937         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
938         if (p == (const Quantum *) NULL)
939           break;
940         for (x=0; x < (ssize_t) roi->width; x++)
941         {
942           *q++=(float) (QuantumScale*GetPixelRed(image,p));
943           *q++=(float) (QuantumScale*GetPixelGreen(image,p));
944           *q++=(float) (QuantumScale*GetPixelBlue(image,p));
945           *q++=(float) (QuantumScale*GetPixelAlpha(image,p));
946           p+=GetPixelChannels(image);
947         }
948       }
949       return;
950     }
951   if (LocaleCompare(map,"RGBP") == 0)
952     {
953       for (y=0; y < (ssize_t) roi->height; y++)
954       {
955         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
956         if (p == (const Quantum *) NULL)
957           break;
958         for (x=0; x < (ssize_t) roi->width; x++)
959         {
960           *q++=(float) (QuantumScale*GetPixelRed(image,p));
961           *q++=(float) (QuantumScale*GetPixelGreen(image,p));
962           *q++=(float) (QuantumScale*GetPixelBlue(image,p));
963           *q++=0.0;
964           p+=GetPixelChannels(image);
965         }
966       }
967       return;
968     }
969   length=strlen(map);
970   for (y=0; y < (ssize_t) roi->height; y++)
971   {
972     p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
973     if (p == (const Quantum *) NULL)
974       break;
975     for (x=0; x < (ssize_t) roi->width; x++)
976     {
977       register ssize_t
978         i;
979
980       for (i=0; i < (ssize_t) length; i++)
981       {
982         *q=0;
983         switch (quantum_map[i])
984         {
985           case RedQuantum:
986           case CyanQuantum:
987           {
988             *q=(float) (QuantumScale*GetPixelRed(image,p));
989             break;
990           }
991           case GreenQuantum:
992           case MagentaQuantum:
993           {
994             *q=(float) (QuantumScale*GetPixelGreen(image,p));
995             break;
996           }
997           case BlueQuantum:
998           case YellowQuantum:
999           {
1000             *q=(float) (QuantumScale*GetPixelBlue(image,p));
1001             break;
1002           }
1003           case AlphaQuantum:
1004           {
1005             *q=(float) (QuantumScale*((Quantum) (GetPixelAlpha(image,p))));
1006             break;
1007           }
1008           case OpacityQuantum:
1009           {
1010             *q=(float) (QuantumScale*GetPixelAlpha(image,p));
1011             break;
1012           }
1013           case BlackQuantum:
1014           {
1015             if (image->colorspace == CMYKColorspace)
1016               *q=(float) (QuantumScale* GetPixelBlack(image,p));
1017             break;
1018           }
1019           case IndexQuantum:
1020           {
1021             *q=(float) (QuantumScale*GetPixelIntensity(image,p));
1022             break;
1023           }
1024           default:
1025             *q=0;
1026         }
1027         q++;
1028       }
1029       p+=GetPixelChannels(image);
1030     }
1031   }
1032 }
1033
1034 static void ExportLongPixel(Image *image,const RectangleInfo *roi,
1035   const char *restrict map,const QuantumType *quantum_map,void *pixels,
1036   ExceptionInfo *exception)
1037 {
1038   register const Quantum
1039     *restrict p;
1040
1041   register ssize_t
1042     x;
1043
1044   register unsigned int
1045     *restrict q;
1046
1047   size_t
1048     length;
1049
1050   ssize_t
1051     y;
1052
1053   q=(unsigned int *) pixels;
1054   if (LocaleCompare(map,"BGR") == 0)
1055     {
1056       for (y=0; y < (ssize_t) roi->height; y++)
1057       {
1058         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1059         if (p == (const Quantum *) NULL)
1060           break;
1061         for (x=0; x < (ssize_t) roi->width; x++)
1062         {
1063           *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
1064           *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
1065           *q++=ScaleQuantumToLong(GetPixelRed(image,p));
1066           p+=GetPixelChannels(image);
1067         }
1068       }
1069       return;
1070     }
1071   if (LocaleCompare(map,"BGRA") == 0)
1072     {
1073       for (y=0; y < (ssize_t) roi->height; y++)
1074       {
1075         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1076         if (p == (const Quantum *) NULL)
1077           break;
1078         for (x=0; x < (ssize_t) roi->width; x++)
1079         {
1080           *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
1081           *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
1082           *q++=ScaleQuantumToLong(GetPixelRed(image,p));
1083           *q++=ScaleQuantumToLong(GetPixelAlpha(image,p));
1084           p+=GetPixelChannels(image);
1085         }
1086       }
1087       return;
1088     }
1089   if (LocaleCompare(map,"BGRP") == 0)
1090     {
1091       for (y=0; y < (ssize_t) roi->height; y++)
1092       {
1093         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1094         if (p == (const Quantum *) NULL)
1095           break;
1096         for (x=0; x < (ssize_t) roi->width; x++)
1097         {
1098           *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
1099           *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
1100           *q++=ScaleQuantumToLong(GetPixelRed(image,p));
1101           *q++=0;
1102           p+=GetPixelChannels(image);
1103         }
1104       }
1105       return;
1106     }
1107   if (LocaleCompare(map,"I") == 0)
1108     {
1109       for (y=0; y < (ssize_t) roi->height; y++)
1110       {
1111         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1112         if (p == (const Quantum *) NULL)
1113           break;
1114         for (x=0; x < (ssize_t) roi->width; x++)
1115         {
1116           *q++=ScaleQuantumToLong(ClampToQuantum(GetPixelIntensity(image,p)));
1117           p+=GetPixelChannels(image);
1118         }
1119       }
1120       return;
1121     }
1122   if (LocaleCompare(map,"RGB") == 0)
1123     {
1124       for (y=0; y < (ssize_t) roi->height; y++)
1125       {
1126         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1127         if (p == (const Quantum *) NULL)
1128           break;
1129         for (x=0; x < (ssize_t) roi->width; x++)
1130         {
1131           *q++=ScaleQuantumToLong(GetPixelRed(image,p));
1132           *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
1133           *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
1134           p+=GetPixelChannels(image);
1135         }
1136       }
1137       return;
1138     }
1139   if (LocaleCompare(map,"RGBA") == 0)
1140     {
1141       for (y=0; y < (ssize_t) roi->height; y++)
1142       {
1143         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1144         if (p == (const Quantum *) NULL)
1145           break;
1146         for (x=0; x < (ssize_t) roi->width; x++)
1147         {
1148           *q++=ScaleQuantumToLong(GetPixelRed(image,p));
1149           *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
1150           *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
1151           *q++=ScaleQuantumToLong(GetPixelAlpha(image,p));
1152           p+=GetPixelChannels(image);
1153         }
1154       }
1155       return;
1156     }
1157   if (LocaleCompare(map,"RGBP") == 0)
1158     {
1159       for (y=0; y < (ssize_t) roi->height; y++)
1160       {
1161         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1162         if (p == (const Quantum *) NULL)
1163           break;
1164         for (x=0; x < (ssize_t) roi->width; x++)
1165         {
1166           *q++=ScaleQuantumToLong(GetPixelRed(image,p));
1167           *q++=ScaleQuantumToLong(GetPixelGreen(image,p));
1168           *q++=ScaleQuantumToLong(GetPixelBlue(image,p));
1169           *q++=0;
1170           p+=GetPixelChannels(image);
1171         }
1172       }
1173       return;
1174     }
1175   length=strlen(map);
1176   for (y=0; y < (ssize_t) roi->height; y++)
1177   {
1178     p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1179     if (p == (const Quantum *) NULL)
1180       break;
1181     for (x=0; x < (ssize_t) roi->width; x++)
1182     {
1183       register ssize_t
1184         i;
1185
1186       for (i=0; i < (ssize_t) length; i++)
1187       {
1188         *q=0;
1189         switch (quantum_map[i])
1190         {
1191           case RedQuantum:
1192           case CyanQuantum:
1193           {
1194             *q=ScaleQuantumToLong(GetPixelRed(image,p));
1195             break;
1196           }
1197           case GreenQuantum:
1198           case MagentaQuantum:
1199           {
1200             *q=ScaleQuantumToLong(GetPixelGreen(image,p));
1201             break;
1202           }
1203           case BlueQuantum:
1204           case YellowQuantum:
1205           {
1206             *q=ScaleQuantumToLong(GetPixelBlue(image,p));
1207             break;
1208           }
1209           case AlphaQuantum:
1210           {
1211             *q=ScaleQuantumToLong(GetPixelAlpha(image,p));
1212             break;
1213           }
1214           case OpacityQuantum:
1215           {
1216             *q=ScaleQuantumToLong(GetPixelAlpha(image,p));
1217             break;
1218           }
1219           case BlackQuantum:
1220           {
1221             if (image->colorspace == CMYKColorspace)
1222               *q=ScaleQuantumToLong(GetPixelBlack(image,p));
1223             break;
1224           }
1225           case IndexQuantum:
1226           {
1227             *q=ScaleQuantumToLong(ClampToQuantum(GetPixelIntensity(image,p)));
1228             break;
1229           }
1230           default:
1231             break;
1232         }
1233         q++;
1234       }
1235       p+=GetPixelChannels(image);
1236     }
1237   }
1238 }
1239
1240 static void ExportLongLongPixel(Image *image,const RectangleInfo *roi,
1241   const char *restrict map,const QuantumType *quantum_map,void *pixels,
1242   ExceptionInfo *exception)
1243 {
1244   register const Quantum
1245     *restrict p;
1246
1247   register ssize_t
1248     x;
1249
1250   register MagickSizeType
1251     *restrict q;
1252
1253   size_t
1254     length;
1255
1256   ssize_t
1257     y;
1258
1259   q=(MagickSizeType *) pixels;
1260   if (LocaleCompare(map,"BGR") == 0)
1261     {
1262       for (y=0; y < (ssize_t) roi->height; y++)
1263       {
1264         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1265         if (p == (const Quantum *) NULL)
1266           break;
1267         for (x=0; x < (ssize_t) roi->width; x++)
1268         {
1269           *q++=ScaleQuantumToLongLong(GetPixelBlue(image,p));
1270           *q++=ScaleQuantumToLongLong(GetPixelGreen(image,p));
1271           *q++=ScaleQuantumToLongLong(GetPixelRed(image,p));
1272           p+=GetPixelChannels(image);
1273         }
1274       }
1275       return;
1276     }
1277   if (LocaleCompare(map,"BGRA") == 0)
1278     {
1279       for (y=0; y < (ssize_t) roi->height; y++)
1280       {
1281         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1282         if (p == (const Quantum *) NULL)
1283           break;
1284         for (x=0; x < (ssize_t) roi->width; x++)
1285         {
1286           *q++=ScaleQuantumToLongLong(GetPixelBlue(image,p));
1287           *q++=ScaleQuantumToLongLong(GetPixelGreen(image,p));
1288           *q++=ScaleQuantumToLongLong(GetPixelRed(image,p));
1289           *q++=ScaleQuantumToLongLong(GetPixelAlpha(image,p));
1290           p+=GetPixelChannels(image);
1291         }
1292       }
1293       return;
1294     }
1295   if (LocaleCompare(map,"BGRP") == 0)
1296     {
1297       for (y=0; y < (ssize_t) roi->height; y++)
1298       {
1299         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1300         if (p == (const Quantum *) NULL)
1301           break;
1302         for (x=0; x < (ssize_t) roi->width; x++)
1303         {
1304           *q++=ScaleQuantumToLongLong(GetPixelBlue(image,p));
1305           *q++=ScaleQuantumToLongLong(GetPixelGreen(image,p));
1306           *q++=ScaleQuantumToLongLong(GetPixelRed(image,p));
1307           *q++=0;
1308           p+=GetPixelChannels(image);
1309         }
1310       }
1311       return;
1312     }
1313   if (LocaleCompare(map,"I") == 0)
1314     {
1315       for (y=0; y < (ssize_t) roi->height; y++)
1316       {
1317         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1318         if (p == (const Quantum *) NULL)
1319           break;
1320         for (x=0; x < (ssize_t) roi->width; x++)
1321         {
1322           *q++=ScaleQuantumToLongLong(ClampToQuantum(GetPixelIntensity(image,p)));
1323           p+=GetPixelChannels(image);
1324         }
1325       }
1326       return;
1327     }
1328   if (LocaleCompare(map,"RGB") == 0)
1329     {
1330       for (y=0; y < (ssize_t) roi->height; y++)
1331       {
1332         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1333         if (p == (const Quantum *) NULL)
1334           break;
1335         for (x=0; x < (ssize_t) roi->width; x++)
1336         {
1337           *q++=ScaleQuantumToLongLong(GetPixelRed(image,p));
1338           *q++=ScaleQuantumToLongLong(GetPixelGreen(image,p));
1339           *q++=ScaleQuantumToLongLong(GetPixelBlue(image,p));
1340           p+=GetPixelChannels(image);
1341         }
1342       }
1343       return;
1344     }
1345   if (LocaleCompare(map,"RGBA") == 0)
1346     {
1347       for (y=0; y < (ssize_t) roi->height; y++)
1348       {
1349         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1350         if (p == (const Quantum *) NULL)
1351           break;
1352         for (x=0; x < (ssize_t) roi->width; x++)
1353         {
1354           *q++=ScaleQuantumToLongLong(GetPixelRed(image,p));
1355           *q++=ScaleQuantumToLongLong(GetPixelGreen(image,p));
1356           *q++=ScaleQuantumToLongLong(GetPixelBlue(image,p));
1357           *q++=ScaleQuantumToLongLong(GetPixelAlpha(image,p));
1358           p+=GetPixelChannels(image);
1359         }
1360       }
1361       return;
1362     }
1363   if (LocaleCompare(map,"RGBP") == 0)
1364     {
1365       for (y=0; y < (ssize_t) roi->height; y++)
1366       {
1367         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1368         if (p == (const Quantum *) NULL)
1369           break;
1370         for (x=0; x < (ssize_t) roi->width; x++)
1371         {
1372           *q++=ScaleQuantumToLongLong(GetPixelRed(image,p));
1373           *q++=ScaleQuantumToLongLong(GetPixelGreen(image,p));
1374           *q++=ScaleQuantumToLongLong(GetPixelBlue(image,p));
1375           *q++=0;
1376           p+=GetPixelChannels(image);
1377         }
1378       }
1379       return;
1380     }
1381   length=strlen(map);
1382   for (y=0; y < (ssize_t) roi->height; y++)
1383   {
1384     p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1385     if (p == (const Quantum *) NULL)
1386       break;
1387     for (x=0; x < (ssize_t) roi->width; x++)
1388     {
1389       register ssize_t
1390         i;
1391
1392       for (i=0; i < (ssize_t) length; i++)
1393       {
1394         *q=0;
1395         switch (quantum_map[i])
1396         {
1397           case RedQuantum:
1398           case CyanQuantum:
1399           {
1400             *q=ScaleQuantumToLongLong(GetPixelRed(image,p));
1401             break;
1402           }
1403           case GreenQuantum:
1404           case MagentaQuantum:
1405           {
1406             *q=ScaleQuantumToLongLong(GetPixelGreen(image,p));
1407             break;
1408           }
1409           case BlueQuantum:
1410           case YellowQuantum:
1411           {
1412             *q=ScaleQuantumToLongLong(GetPixelBlue(image,p));
1413             break;
1414           }
1415           case AlphaQuantum:
1416           {
1417             *q=ScaleQuantumToLongLong(GetPixelAlpha(image,p));
1418             break;
1419           }
1420           case OpacityQuantum:
1421           {
1422             *q=ScaleQuantumToLongLong(GetPixelAlpha(image,p));
1423             break;
1424           }
1425           case BlackQuantum:
1426           {
1427             if (image->colorspace == CMYKColorspace)
1428               *q=ScaleQuantumToLongLong(GetPixelBlack(image,p));
1429             break;
1430           }
1431           case IndexQuantum:
1432           {
1433             *q=ScaleQuantumToLongLong(ClampToQuantum(GetPixelIntensity(image,p)));
1434             break;
1435           }
1436           default:
1437             break;
1438         }
1439         q++;
1440       }
1441       p+=GetPixelChannels(image);
1442     }
1443   }
1444 }
1445
1446 static void ExportQuantumPixel(Image *image,const RectangleInfo *roi,
1447   const char *restrict map,const QuantumType *quantum_map,void *pixels,
1448   ExceptionInfo *exception)
1449 {
1450   register const Quantum
1451     *restrict p;
1452
1453   register Quantum
1454     *restrict q;
1455
1456   register ssize_t
1457     x;
1458
1459   size_t
1460     length;
1461
1462   ssize_t
1463     y;
1464
1465   q=(Quantum *) pixels;
1466   if (LocaleCompare(map,"BGR") == 0)
1467     {
1468       for (y=0; y < (ssize_t) roi->height; y++)
1469       {
1470         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1471         if (p == (const Quantum *) NULL)
1472           break;
1473         for (x=0; x < (ssize_t) roi->width; x++)
1474         {
1475           *q++=GetPixelBlue(image,p);
1476           *q++=GetPixelGreen(image,p);
1477           *q++=GetPixelRed(image,p);
1478           p+=GetPixelChannels(image);
1479         }
1480       }
1481       return;
1482     }
1483   if (LocaleCompare(map,"BGRA") == 0)
1484     {
1485       for (y=0; y < (ssize_t) roi->height; y++)
1486       {
1487         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1488         if (p == (const Quantum *) NULL)
1489           break;
1490         for (x=0; x < (ssize_t) roi->width; x++)
1491         {
1492           *q++=GetPixelBlue(image,p);
1493           *q++=GetPixelGreen(image,p);
1494           *q++=GetPixelRed(image,p);
1495           *q++=(Quantum) (GetPixelAlpha(image,p));
1496           p+=GetPixelChannels(image);
1497         }
1498       }
1499       return;
1500     }
1501   if (LocaleCompare(map,"BGRP") == 0)
1502     {
1503       for (y=0; y < (ssize_t) roi->height; y++)
1504       {
1505         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1506         if (p == (const Quantum *) NULL)
1507           break;
1508         for (x=0; x < (ssize_t) roi->width; x++)
1509         {
1510           *q++=GetPixelBlue(image,p);
1511           *q++=GetPixelGreen(image,p);
1512           *q++=GetPixelRed(image,p);
1513           *q++=(Quantum) 0;
1514           p+=GetPixelChannels(image);
1515         }
1516       }
1517       return;
1518     }
1519   if (LocaleCompare(map,"I") == 0)
1520     {
1521       for (y=0; y < (ssize_t) roi->height; y++)
1522       {
1523         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1524         if (p == (const Quantum *) NULL)
1525           break;
1526         for (x=0; x < (ssize_t) roi->width; x++)
1527         {
1528           *q++=ClampToQuantum(GetPixelIntensity(image,p));
1529           p+=GetPixelChannels(image);
1530         }
1531       }
1532       return;
1533     }
1534   if (LocaleCompare(map,"RGB") == 0)
1535     {
1536       for (y=0; y < (ssize_t) roi->height; y++)
1537       {
1538         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1539         if (p == (const Quantum *) NULL)
1540           break;
1541         for (x=0; x < (ssize_t) roi->width; x++)
1542         {
1543           *q++=GetPixelRed(image,p);
1544           *q++=GetPixelGreen(image,p);
1545           *q++=GetPixelBlue(image,p);
1546           p+=GetPixelChannels(image);
1547         }
1548       }
1549       return;
1550     }
1551   if (LocaleCompare(map,"RGBA") == 0)
1552     {
1553       for (y=0; y < (ssize_t) roi->height; y++)
1554       {
1555         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1556         if (p == (const Quantum *) NULL)
1557           break;
1558         for (x=0; x < (ssize_t) roi->width; x++)
1559         {
1560           *q++=GetPixelRed(image,p);
1561           *q++=GetPixelGreen(image,p);
1562           *q++=GetPixelBlue(image,p);
1563           *q++=(Quantum) (GetPixelAlpha(image,p));
1564           p+=GetPixelChannels(image);
1565         }
1566       }
1567       return;
1568     }
1569   if (LocaleCompare(map,"RGBP") == 0)
1570     {
1571       for (y=0; y < (ssize_t) roi->height; y++)
1572       {
1573         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1574         if (p == (const Quantum *) NULL)
1575           break;
1576         for (x=0; x < (ssize_t) roi->width; x++)
1577         {
1578           *q++=GetPixelRed(image,p);
1579           *q++=GetPixelGreen(image,p);
1580           *q++=GetPixelBlue(image,p);
1581           *q++=(Quantum) 0;
1582           p+=GetPixelChannels(image);
1583         }
1584       }
1585       return;
1586     }
1587   length=strlen(map);
1588   for (y=0; y < (ssize_t) roi->height; y++)
1589   {
1590     p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1591     if (p == (const Quantum *) NULL)
1592       break;
1593     for (x=0; x < (ssize_t) roi->width; x++)
1594     {
1595       register ssize_t
1596         i;
1597
1598       for (i=0; i < (ssize_t) length; i++)
1599       {
1600         *q=(Quantum) 0;
1601         switch (quantum_map[i])
1602         {
1603           case RedQuantum:
1604           case CyanQuantum:
1605           {
1606             *q=GetPixelRed(image,p);
1607             break;
1608           }
1609           case GreenQuantum:
1610           case MagentaQuantum:
1611           {
1612             *q=GetPixelGreen(image,p);
1613             break;
1614           }
1615           case BlueQuantum:
1616           case YellowQuantum:
1617           {
1618             *q=GetPixelBlue(image,p);
1619             break;
1620           }
1621           case AlphaQuantum:
1622           {
1623             *q=GetPixelAlpha(image,p);
1624             break;
1625           }
1626           case OpacityQuantum:
1627           {
1628             *q=GetPixelAlpha(image,p);
1629             break;
1630           }
1631           case BlackQuantum:
1632           {
1633             if (image->colorspace == CMYKColorspace)
1634               *q=GetPixelBlack(image,p);
1635             break;
1636           }
1637           case IndexQuantum:
1638           {
1639             *q=ClampToQuantum(GetPixelIntensity(image,p));
1640             break;
1641           }
1642           default:
1643           {
1644             *q=(Quantum) 0;
1645             break;
1646           }
1647         }
1648         q++;
1649       }
1650       p+=GetPixelChannels(image);
1651     }
1652   }
1653 }
1654
1655 static void ExportShortPixel(Image *image,const RectangleInfo *roi,
1656   const char *restrict map,const QuantumType *quantum_map,void *pixels,
1657   ExceptionInfo *exception)
1658 {
1659   register const Quantum
1660     *restrict p;
1661
1662   register ssize_t
1663     x;
1664
1665   register unsigned short
1666     *restrict q;
1667
1668   size_t
1669     length;
1670
1671   ssize_t
1672     y;
1673
1674   q=(unsigned short *) pixels;
1675   if (LocaleCompare(map,"BGR") == 0)
1676     {
1677       for (y=0; y < (ssize_t) roi->height; y++)
1678       {
1679         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1680         if (p == (const Quantum *) NULL)
1681           break;
1682         for (x=0; x < (ssize_t) roi->width; x++)
1683         {
1684           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1685           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1686           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1687           p+=GetPixelChannels(image);
1688         }
1689       }
1690       return;
1691     }
1692   if (LocaleCompare(map,"BGRA") == 0)
1693     {
1694       for (y=0; y < (ssize_t) roi->height; y++)
1695       {
1696         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1697         if (p == (const Quantum *) NULL)
1698           break;
1699         for (x=0; x < (ssize_t) roi->width; x++)
1700         {
1701           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1702           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1703           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1704           *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
1705           p+=GetPixelChannels(image);
1706         }
1707       }
1708       return;
1709     }
1710   if (LocaleCompare(map,"BGRP") == 0)
1711     {
1712       for (y=0; y < (ssize_t) roi->height; y++)
1713       {
1714         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1715         if (p == (const Quantum *) NULL)
1716           break;
1717         for (x=0; x < (ssize_t) roi->width; x++)
1718         {
1719           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1720           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1721           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1722           *q++=0;
1723           p+=GetPixelChannels(image);
1724         }
1725       }
1726       return;
1727     }
1728   if (LocaleCompare(map,"I") == 0)
1729     {
1730       for (y=0; y < (ssize_t) roi->height; y++)
1731       {
1732         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1733         if (p == (const Quantum *) NULL)
1734           break;
1735         for (x=0; x < (ssize_t) roi->width; x++)
1736         {
1737           *q++=ScaleQuantumToShort(ClampToQuantum(GetPixelIntensity(image,p)));
1738           p+=GetPixelChannels(image);
1739         }
1740       }
1741       return;
1742     }
1743   if (LocaleCompare(map,"RGB") == 0)
1744     {
1745       for (y=0; y < (ssize_t) roi->height; y++)
1746       {
1747         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1748         if (p == (const Quantum *) NULL)
1749           break;
1750         for (x=0; x < (ssize_t) roi->width; x++)
1751         {
1752           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1753           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1754           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1755           p+=GetPixelChannels(image);
1756         }
1757       }
1758       return;
1759     }
1760   if (LocaleCompare(map,"RGBA") == 0)
1761     {
1762       for (y=0; y < (ssize_t) roi->height; y++)
1763       {
1764         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1765         if (p == (const Quantum *) NULL)
1766           break;
1767         for (x=0; x < (ssize_t) roi->width; x++)
1768         {
1769           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1770           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1771           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1772           *q++=ScaleQuantumToShort(GetPixelAlpha(image,p));
1773           p+=GetPixelChannels(image);
1774         }
1775       }
1776       return;
1777     }
1778   if (LocaleCompare(map,"RGBP") == 0)
1779     {
1780       for (y=0; y < (ssize_t) roi->height; y++)
1781       {
1782         p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1783         if (p == (const Quantum *) NULL)
1784           break;
1785         for (x=0; x < (ssize_t) roi->width; x++)
1786         {
1787           *q++=ScaleQuantumToShort(GetPixelRed(image,p));
1788           *q++=ScaleQuantumToShort(GetPixelGreen(image,p));
1789           *q++=ScaleQuantumToShort(GetPixelBlue(image,p));
1790           *q++=0;
1791           p+=GetPixelChannels(image);
1792         }
1793       }
1794       return;
1795     }
1796   length=strlen(map);
1797   for (y=0; y < (ssize_t) roi->height; y++)
1798   {
1799     p=GetVirtualPixels(image,roi->x,roi->y+y,roi->width,1,exception);
1800     if (p == (const Quantum *) NULL)
1801       break;
1802     for (x=0; x < (ssize_t) roi->width; x++)
1803     {
1804       register ssize_t
1805         i;
1806
1807       for (i=0; i < (ssize_t) length; i++)
1808       {
1809         *q=0;
1810         switch (quantum_map[i])
1811         {
1812           case RedQuantum:
1813           case CyanQuantum:
1814           {
1815             *q=ScaleQuantumToShort(GetPixelRed(image,p));
1816             break;
1817           }
1818           case GreenQuantum:
1819           case MagentaQuantum:
1820           {
1821             *q=ScaleQuantumToShort(GetPixelGreen(image,p));
1822             break;
1823           }
1824           case BlueQuantum:
1825           case YellowQuantum:
1826           {
1827             *q=ScaleQuantumToShort(GetPixelBlue(image,p));
1828             break;
1829           }
1830           case AlphaQuantum:
1831           {
1832             *q=ScaleQuantumToShort(GetPixelAlpha(image,p));
1833             break;
1834           }
1835           case OpacityQuantum:
1836           {
1837             *q=ScaleQuantumToShort(GetPixelAlpha(image,p));
1838             break;
1839           }
1840           case BlackQuantum:
1841           {
1842             if (image->colorspace == CMYKColorspace)
1843               *q=ScaleQuantumToShort(GetPixelBlack(image,p));
1844             break;
1845           }
1846           case IndexQuantum:
1847           {
1848             *q=ScaleQuantumToShort(ClampToQuantum(GetPixelIntensity(image,p)));
1849             break;
1850           }
1851           default:
1852             break;
1853         }
1854         q++;
1855       }
1856       p+=GetPixelChannels(image);
1857     }
1858   }
1859 }
1860
1861 MagickExport MagickBooleanType ExportImagePixels(Image *image,
1862   const ssize_t x,const ssize_t y,const size_t width,const size_t height,
1863   const char *map,const StorageType type,void *pixels,ExceptionInfo *exception)
1864 {
1865   QuantumType
1866     *quantum_map;
1867
1868   RectangleInfo
1869     roi;
1870
1871   register ssize_t
1872     i;
1873
1874   size_t
1875     length;
1876
1877   assert(image != (Image *) NULL);
1878   assert(image->signature == MagickSignature);
1879   if (image->debug != MagickFalse)
1880     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
1881   length=strlen(map);
1882   quantum_map=(QuantumType *) AcquireQuantumMemory(length,sizeof(*quantum_map));
1883   if (quantum_map == (QuantumType *) NULL)
1884     {
1885       (void) ThrowMagickException(exception,GetMagickModule(),
1886         ResourceLimitError,"MemoryAllocationFailed","`%s'",image->filename);
1887       return(MagickFalse);
1888     }
1889   for (i=0; i < (ssize_t) length; i++)
1890   {
1891     switch (map[i])
1892     {
1893       case 'A':
1894       case 'a':
1895       {
1896         quantum_map[i]=AlphaQuantum;
1897         break;
1898       }
1899       case 'B':
1900       case 'b':
1901       {
1902         quantum_map[i]=BlueQuantum;
1903         break;
1904       }
1905       case 'C':
1906       case 'c':
1907       {
1908         quantum_map[i]=CyanQuantum;
1909         if (image->colorspace == CMYKColorspace)
1910           break;
1911         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
1912         (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1913           "ColorSeparatedImageRequired","`%s'",map);
1914         return(MagickFalse);
1915       }
1916       case 'g':
1917       case 'G':
1918       {
1919         quantum_map[i]=GreenQuantum;
1920         break;
1921       }
1922       case 'I':
1923       case 'i':
1924       {
1925         quantum_map[i]=IndexQuantum;
1926         break;
1927       }
1928       case 'K':
1929       case 'k':
1930       {
1931         quantum_map[i]=BlackQuantum;
1932         if (image->colorspace == CMYKColorspace)
1933           break;
1934         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
1935         (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1936           "ColorSeparatedImageRequired","`%s'",map);
1937         return(MagickFalse);
1938       }
1939       case 'M':
1940       case 'm':
1941       {
1942         quantum_map[i]=MagentaQuantum;
1943         if (image->colorspace == CMYKColorspace)
1944           break;
1945         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
1946         (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1947           "ColorSeparatedImageRequired","`%s'",map);
1948         return(MagickFalse);
1949       }
1950       case 'o':
1951       case 'O':
1952       {
1953         quantum_map[i]=OpacityQuantum;
1954         break;
1955       }
1956       case 'P':
1957       case 'p':
1958       {
1959         quantum_map[i]=UndefinedQuantum;
1960         break;
1961       }
1962       case 'R':
1963       case 'r':
1964       {
1965         quantum_map[i]=RedQuantum;
1966         break;
1967       }
1968       case 'Y':
1969       case 'y':
1970       {
1971         quantum_map[i]=YellowQuantum;
1972         if (image->colorspace == CMYKColorspace)
1973           break;
1974         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
1975         (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
1976           "ColorSeparatedImageRequired","`%s'",map);
1977         return(MagickFalse);
1978       }
1979       default:
1980       {
1981         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
1982         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
1983           "UnrecognizedPixelMap","`%s'",map);
1984         return(MagickFalse);
1985       }
1986     }
1987   }
1988   roi.width=width;
1989   roi.height=height;
1990   roi.x=x;
1991   roi.y=y;
1992   switch (type)
1993   {
1994     case CharPixel:
1995     {
1996       ExportCharPixel(image,&roi,map,quantum_map,pixels,exception);
1997       break;
1998     }
1999     case DoublePixel:
2000     {
2001       ExportDoublePixel(image,&roi,map,quantum_map,pixels,exception);
2002       break;
2003     }
2004     case FloatPixel:
2005     {
2006       ExportFloatPixel(image,&roi,map,quantum_map,pixels,exception);
2007       break;
2008     }
2009     case LongPixel:
2010     {
2011       ExportLongPixel(image,&roi,map,quantum_map,pixels,exception);
2012       break;
2013     }
2014     case LongLongPixel:
2015     {
2016       ExportLongLongPixel(image,&roi,map,quantum_map,pixels,exception);
2017       break;
2018     }
2019     case QuantumPixel:
2020     {
2021       ExportQuantumPixel(image,&roi,map,quantum_map,pixels,exception);
2022       break;
2023     }
2024     case ShortPixel:
2025     {
2026       ExportShortPixel(image,&roi,map,quantum_map,pixels,exception);
2027       break;
2028     }
2029     default:
2030     {
2031       quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
2032       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
2033         "UnrecognizedPixelMap","`%s'",map);
2034       break;
2035     }
2036   }
2037   quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
2038   return(MagickTrue);
2039 }
2040 \f
2041 /*
2042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2043 %                                                                             %
2044 %                                                                             %
2045 %                                                                             %
2046 %   G e t P i x e l I n f o                                                   %
2047 %                                                                             %
2048 %                                                                             %
2049 %                                                                             %
2050 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2051 %
2052 %  GetPixelInfo() initializes the PixelInfo structure.
2053 %
2054 %  The format of the GetPixelInfo method is:
2055 %
2056 %      GetPixelInfo(const Image *image,PixelInfo *pixel)
2057 %
2058 %  A description of each parameter follows:
2059 %
2060 %    o image: the image.
2061 %
2062 %    o pixel: Specifies a pointer to a PixelInfo structure.
2063 %
2064 */
2065 MagickExport void GetPixelInfo(const Image *image,PixelInfo *pixel)
2066 {
2067   pixel->storage_class=DirectClass;
2068   pixel->colorspace=sRGBColorspace;
2069   pixel->alpha_trait=UndefinedPixelTrait;
2070   pixel->fuzz=0.0;
2071   pixel->depth=MAGICKCORE_QUANTUM_DEPTH;
2072   pixel->red=0.0;
2073   pixel->green=0.0;
2074   pixel->blue=0.0;
2075   pixel->black=0.0;
2076   pixel->alpha=(double) OpaqueAlpha;
2077   pixel->index=0.0;
2078   if (image == (const Image *) NULL)
2079     return;
2080   pixel->storage_class=image->storage_class;
2081   pixel->colorspace=image->colorspace;
2082   pixel->alpha_trait=image->alpha_trait;
2083   pixel->depth=image->depth;
2084   pixel->fuzz=image->fuzz;
2085 }
2086 \f
2087 /*
2088 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2089 %                                                                             %
2090 %                                                                             %
2091 %                                                                             %
2092 %   G e t P i x e l I n t e n s i t y                                         %
2093 %                                                                             %
2094 %                                                                             %
2095 %                                                                             %
2096 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2097 %
2098 %  GetPixelIntensity() returns a single sample intensity value from the red,
2099 %  green, and blue components of a pixel based on the selected method:
2100 %
2101 %    Rec601Luma   0.298839R + 0.586811G + 0.114350B
2102 %    Rec709Luma   0.21260R + 0.71520G + 0.07220B
2103 %    Brightness   max(R, G, B)
2104 %    Lightness    (min(R, G, B) + max(R, G, B)) / 2.0
2105 %    RMS          (R^2 + G^2 + B^2) / 3.0
2106 %    Average      (R + G + B) / 3.0
2107 %
2108 %  The format of the GetPixelIntensity method is:
2109 %
2110 %      GetPixelIntensity(const Image *image,const Quantum *pixel)
2111 %
2112 %  A description of each parameter follows:
2113 %
2114 %    o image: the image.
2115 %
2116 %    o pixel: Specifies a pointer to a Quantum structure.
2117 %
2118 */
2119
2120 static inline MagickRealType MagickMax(const MagickRealType x,
2121   const MagickRealType y)
2122 {
2123   if (x > y)
2124     return(x);
2125   return(y);
2126 }
2127
2128 static inline MagickRealType MagickMin(const MagickRealType x,
2129   const MagickRealType y)
2130 {
2131   if (x < y)
2132     return(x);
2133   return(y);
2134 }
2135
2136 MagickExport MagickRealType GetPixelIntensity(const Image *restrict image,
2137   const Quantum *restrict pixel)
2138 {
2139   MagickRealType
2140     blue,
2141     green,
2142     red,
2143     intensity;
2144
2145   if (image->colorspace == GRAYColorspace)
2146     return((MagickRealType) pixel[image->channel_map[GrayPixelChannel].offset]);
2147   red=(MagickRealType) pixel[image->channel_map[RedPixelChannel].offset];
2148   green=(MagickRealType) pixel[image->channel_map[GreenPixelChannel].offset];
2149   blue=(MagickRealType) pixel[image->channel_map[BluePixelChannel].offset];
2150   switch (image->intensity)
2151   {
2152     case Rec601LumaPixelIntensityMethod:
2153     default:
2154     {
2155       if (image->colorspace == sRGBColorspace)
2156         {
2157           red=DecodePixelGamma(red);
2158           green=DecodePixelGamma(green);
2159           blue=DecodePixelGamma(blue);
2160         }
2161       intensity=0.298839f*red+0.586811f*green+0.114350f*blue;
2162       break;
2163     }
2164     case Rec709LumaPixelIntensityMethod:
2165     {
2166       if (image->colorspace == sRGBColorspace)
2167         {
2168           red=DecodePixelGamma(red);
2169           green=DecodePixelGamma(green);
2170           blue=DecodePixelGamma(blue);
2171         }
2172       intensity=0.21260f*red+0.71520f*green+0.07220f*blue;
2173       break;
2174     }
2175     case BrightnessPixelIntensityMethod:
2176     {
2177       if (image->colorspace == sRGBColorspace)
2178         {
2179           red=DecodePixelGamma(red);
2180           green=DecodePixelGamma(green);
2181           blue=DecodePixelGamma(blue);
2182         }
2183       intensity=MagickMax(MagickMax(red,green),blue);
2184       break;
2185     }
2186     case LightnessPixelIntensityMethod:
2187     {
2188       if (image->colorspace == sRGBColorspace)
2189         {
2190           red=DecodePixelGamma(red);
2191           green=DecodePixelGamma(green);
2192           blue=DecodePixelGamma(blue);
2193         }
2194       intensity=MagickMin(MagickMin(red,green),blue);
2195       break;
2196     }
2197     case RMSPixelIntensityMethod:
2198     {
2199       intensity=(MagickRealType) sqrt((double) red*red+green*green+blue*blue);
2200       break;
2201     }
2202     case AveragePixelIntensityMethod:
2203     {
2204       intensity=(red+green+blue)/3.0;
2205       break;
2206     }
2207   }
2208   return(intensity);
2209 }
2210 \f
2211 /*
2212 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2213 %                                                                             %
2214 %                                                                             %
2215 %                                                                             %
2216 %   I m p o r t I m a g e P i x e l s                                         %
2217 %                                                                             %
2218 %                                                                             %
2219 %                                                                             %
2220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2221 %
2222 %  ImportImagePixels() accepts pixel data and stores in the image at the
2223 %  location you specify.  The method returns MagickTrue on success otherwise
2224 %  MagickFalse if an error is encountered.  The pixel data can be either char,
2225 %  Quantum, short int, unsigned int, unsigned long long, float, or double in
2226 %  the order specified by map.
2227 %
2228 %  Suppose your want to upload the first scanline of a 640x480 image from
2229 %  character data in red-green-blue order:
2230 %
2231 %      ImportImagePixels(image,0,0,640,1,"RGB",CharPixel,pixels);
2232 %
2233 %  The format of the ImportImagePixels method is:
2234 %
2235 %      MagickBooleanType ImportImagePixels(Image *image,const ssize_t x,
2236 %        const ssize_t y,const size_t width,const size_t height,
2237 %        const char *map,const StorageType type,const void *pixels,
2238 %        ExceptionInfo *exception)
2239 %
2240 %  A description of each parameter follows:
2241 %
2242 %    o image: the image.
2243 %
2244 %    o x,y,width,height:  These values define the perimeter
2245 %      of a region of pixels you want to define.
2246 %
2247 %    o map:  This string reflects the expected ordering of the pixel array.
2248 %      It can be any combination or order of R = red, G = green, B = blue,
2249 %      A = alpha (0 is transparent), O = opacity (0 is opaque), C = cyan,
2250 %      Y = yellow, M = magenta, K = black, I = intensity (for grayscale),
2251 %      P = pad.
2252 %
2253 %    o type: Define the data type of the pixels.  Float and double types are
2254 %      normalized to [0..1] otherwise [0..QuantumRange].  Choose from these
2255 %      types: CharPixel (char *), DoublePixel (double *), FloatPixel (float *),
2256 %      LongPixel (unsigned int *), LongLongPixel (unsigned long long *),
2257 %      QuantumPixel (Quantum *), or ShortPixel (unsigned short *).
2258 %
2259 %    o pixels: This array of values contain the pixel components as defined by
2260 %      map and type.  You must preallocate this array where the expected
2261 %      length varies depending on the values of width, height, map, and type.
2262 %
2263 %    o exception: return any errors or warnings in this structure.
2264 %
2265 */
2266
2267 static void ImportCharPixel(Image *image,const RectangleInfo *roi,
2268   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
2269   ExceptionInfo *exception)
2270 {
2271   register const unsigned char
2272     *restrict p;
2273
2274   register Quantum
2275     *restrict q;
2276
2277   register ssize_t
2278     x;
2279
2280   size_t
2281     length;
2282
2283   ssize_t
2284     y;
2285
2286   p=(const unsigned char *) pixels;
2287   if (LocaleCompare(map,"BGR") == 0)
2288     {
2289       for (y=0; y < (ssize_t) roi->height; y++)
2290       {
2291         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2292         if (q == (Quantum *) NULL)
2293           break;
2294         for (x=0; x < (ssize_t) roi->width; x++)
2295         {
2296           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2297           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2298           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2299           q+=GetPixelChannels(image);
2300         }
2301         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2302           break;
2303       }
2304       return;
2305     }
2306   if (LocaleCompare(map,"BGRA") == 0)
2307     {
2308       for (y=0; y < (ssize_t) roi->height; y++)
2309       {
2310         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2311         if (q == (Quantum *) NULL)
2312           break;
2313         for (x=0; x < (ssize_t) roi->width; x++)
2314         {
2315           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2316           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2317           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2318           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2319           q+=GetPixelChannels(image);
2320         }
2321         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2322           break;
2323       }
2324       return;
2325     }
2326   if (LocaleCompare(map,"BGRO") == 0)
2327     {
2328       for (y=0; y < (ssize_t) roi->height; y++)
2329       {
2330         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2331         if (q == (Quantum *) NULL)
2332           break;
2333         for (x=0; x < (ssize_t) roi->width; x++)
2334         {
2335           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2336           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2337           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2338           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2339           q+=GetPixelChannels(image);
2340         }
2341         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2342           break;
2343       }
2344       return;
2345     }
2346   if (LocaleCompare(map,"BGRP") == 0)
2347     {
2348       for (y=0; y < (ssize_t) roi->height; y++)
2349       {
2350         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2351         if (q == (Quantum *) NULL)
2352           break;
2353         for (x=0; x < (ssize_t) roi->width; x++)
2354         {
2355           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2356           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2357           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2358           p++;
2359           q+=GetPixelChannels(image);
2360         }
2361         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2362           break;
2363       }
2364       return;
2365     }
2366   if (LocaleCompare(map,"I") == 0)
2367     {
2368       for (y=0; y < (ssize_t) roi->height; y++)
2369       {
2370         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2371         if (q == (Quantum *) NULL)
2372           break;
2373         for (x=0; x < (ssize_t) roi->width; x++)
2374         {
2375           SetPixelGray(image,ScaleCharToQuantum(*p++),q);
2376           q+=GetPixelChannels(image);
2377         }
2378         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2379           break;
2380       }
2381       return;
2382     }
2383   if (LocaleCompare(map,"RGB") == 0)
2384     {
2385       for (y=0; y < (ssize_t) roi->height; y++)
2386       {
2387         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2388         if (q == (Quantum *) NULL)
2389           break;
2390         for (x=0; x < (ssize_t) roi->width; x++)
2391         {
2392           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2393           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2394           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2395           q+=GetPixelChannels(image);
2396         }
2397         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2398           break;
2399       }
2400       return;
2401     }
2402   if (LocaleCompare(map,"RGBA") == 0)
2403     {
2404       for (y=0; y < (ssize_t) roi->height; y++)
2405       {
2406         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2407         if (q == (Quantum *) NULL)
2408           break;
2409         for (x=0; x < (ssize_t) roi->width; x++)
2410         {
2411           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2412           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2413           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2414           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2415           q+=GetPixelChannels(image);
2416         }
2417         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2418           break;
2419       }
2420       return;
2421     }
2422   if (LocaleCompare(map,"RGBO") == 0)
2423     {
2424       for (y=0; y < (ssize_t) roi->height; y++)
2425       {
2426         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2427         if (q == (Quantum *) NULL)
2428           break;
2429         for (x=0; x < (ssize_t) roi->width; x++)
2430         {
2431           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2432           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2433           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2434           SetPixelAlpha(image,ScaleCharToQuantum(*p++),q);
2435           q+=GetPixelChannels(image);
2436         }
2437         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2438           break;
2439       }
2440       return;
2441     }
2442   if (LocaleCompare(map,"RGBP") == 0)
2443     {
2444       for (y=0; y < (ssize_t) roi->height; y++)
2445       {
2446         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2447         if (q == (Quantum *) NULL)
2448           break;
2449         for (x=0; x < (ssize_t) roi->width; x++)
2450         {
2451           SetPixelRed(image,ScaleCharToQuantum(*p++),q);
2452           SetPixelGreen(image,ScaleCharToQuantum(*p++),q);
2453           SetPixelBlue(image,ScaleCharToQuantum(*p++),q);
2454           p++;
2455           q+=GetPixelChannels(image);
2456         }
2457         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2458           break;
2459       }
2460       return;
2461     }
2462   length=strlen(map);
2463   for (y=0; y < (ssize_t) roi->height; y++)
2464   {
2465     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2466     if (q == (Quantum *) NULL)
2467       break;
2468     for (x=0; x < (ssize_t) roi->width; x++)
2469     {
2470       register ssize_t
2471         i;
2472
2473       for (i=0; i < (ssize_t) length; i++)
2474       {
2475         switch (quantum_map[i])
2476         {
2477           case RedQuantum:
2478           case CyanQuantum:
2479           {
2480             SetPixelRed(image,ScaleCharToQuantum(*p),q);
2481             break;
2482           }
2483           case GreenQuantum:
2484           case MagentaQuantum:
2485           {
2486             SetPixelGreen(image,ScaleCharToQuantum(*p),q);
2487             break;
2488           }
2489           case BlueQuantum:
2490           case YellowQuantum:
2491           {
2492             SetPixelBlue(image,ScaleCharToQuantum(*p),q);
2493             break;
2494           }
2495           case AlphaQuantum:
2496           {
2497             SetPixelAlpha(image,ScaleCharToQuantum(*p),q);
2498             break;
2499           }
2500           case OpacityQuantum:
2501           {
2502             SetPixelAlpha(image,ScaleCharToQuantum(*p),q);
2503             break;
2504           }
2505           case BlackQuantum:
2506           {
2507             SetPixelBlack(image,ScaleCharToQuantum(*p),q);
2508             break;
2509           }
2510           case IndexQuantum:
2511           {
2512             SetPixelGray(image,ScaleCharToQuantum(*p),q);
2513             break;
2514           }
2515           default:
2516             break;
2517         }
2518         p++;
2519       }
2520       q+=GetPixelChannels(image);
2521     }
2522     if (SyncAuthenticPixels(image,exception) == MagickFalse)
2523       break;
2524   }
2525 }
2526
2527 static void ImportDoublePixel(Image *image,const RectangleInfo *roi,
2528   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
2529   ExceptionInfo *exception)
2530 {
2531   register const double
2532     *restrict p;
2533
2534   register Quantum
2535     *restrict q;
2536
2537   register ssize_t
2538     x;
2539
2540   size_t
2541     length;
2542
2543   ssize_t
2544     y;
2545
2546   p=(const double *) pixels;
2547   if (LocaleCompare(map,"BGR") == 0)
2548     {
2549       for (y=0; y < (ssize_t) roi->height; y++)
2550       {
2551         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2552         if (q == (Quantum *) NULL)
2553           break;
2554         for (x=0; x < (ssize_t) roi->width; x++)
2555         {
2556           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2557           p++;
2558           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2559           p++;
2560           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2561           p++;
2562           q+=GetPixelChannels(image);
2563         }
2564         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2565           break;
2566       }
2567       return;
2568     }
2569   if (LocaleCompare(map,"BGRA") == 0)
2570     {
2571       for (y=0; y < (ssize_t) roi->height; y++)
2572       {
2573         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2574         if (q == (Quantum *) NULL)
2575           break;
2576         for (x=0; x < (ssize_t) roi->width; x++)
2577         {
2578           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2579           p++;
2580           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2581           p++;
2582           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2583           p++;
2584           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2585           p++;
2586           q+=GetPixelChannels(image);
2587         }
2588         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2589           break;
2590       }
2591       return;
2592     }
2593   if (LocaleCompare(map,"BGRP") == 0)
2594     {
2595       for (y=0; y < (ssize_t) roi->height; y++)
2596       {
2597         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2598         if (q == (Quantum *) NULL)
2599           break;
2600         for (x=0; x < (ssize_t) roi->width; x++)
2601         {
2602           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2603           p++;
2604           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2605           p++;
2606           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2607           p++;
2608           p++;
2609           q+=GetPixelChannels(image);
2610         }
2611         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2612           break;
2613       }
2614       return;
2615     }
2616   if (LocaleCompare(map,"I") == 0)
2617     {
2618       for (y=0; y < (ssize_t) roi->height; y++)
2619       {
2620         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2621         if (q == (Quantum *) NULL)
2622           break;
2623         for (x=0; x < (ssize_t) roi->width; x++)
2624         {
2625           SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2626           p++;
2627           q+=GetPixelChannels(image);
2628         }
2629         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2630           break;
2631       }
2632       return;
2633     }
2634   if (LocaleCompare(map,"RGB") == 0)
2635     {
2636       for (y=0; y < (ssize_t) roi->height; y++)
2637       {
2638         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2639         if (q == (Quantum *) NULL)
2640           break;
2641         for (x=0; x < (ssize_t) roi->width; x++)
2642         {
2643           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2644           p++;
2645           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2646           p++;
2647           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2648           p++;
2649           q+=GetPixelChannels(image);
2650         }
2651         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2652           break;
2653       }
2654       return;
2655     }
2656   if (LocaleCompare(map,"RGBA") == 0)
2657     {
2658       for (y=0; y < (ssize_t) roi->height; y++)
2659       {
2660         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2661         if (q == (Quantum *) NULL)
2662           break;
2663         for (x=0; x < (ssize_t) roi->width; x++)
2664         {
2665           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2666           p++;
2667           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2668           p++;
2669           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2670           p++;
2671           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2672           p++;
2673           q+=GetPixelChannels(image);
2674         }
2675         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2676           break;
2677       }
2678       return;
2679     }
2680   if (LocaleCompare(map,"RGBP") == 0)
2681     {
2682       for (y=0; y < (ssize_t) roi->height; y++)
2683       {
2684         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2685         if (q == (Quantum *) NULL)
2686           break;
2687         for (x=0; x < (ssize_t) roi->width; x++)
2688         {
2689           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2690           p++;
2691           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2692           p++;
2693           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2694           p++;
2695           q+=GetPixelChannels(image);
2696         }
2697         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2698           break;
2699       }
2700       return;
2701     }
2702    length=strlen(map);
2703   for (y=0; y < (ssize_t) roi->height; y++)
2704   {
2705     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2706     if (q == (Quantum *) NULL)
2707       break;
2708     for (x=0; x < (ssize_t) roi->width; x++)
2709     {
2710       register ssize_t
2711         i;
2712
2713       for (i=0; i < (ssize_t) length; i++)
2714       {
2715         switch (quantum_map[i])
2716         {
2717           case RedQuantum:
2718           case CyanQuantum:
2719           {
2720             SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2721             break;
2722           }
2723           case GreenQuantum:
2724           case MagentaQuantum:
2725           {
2726             SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2727             break;
2728           }
2729           case BlueQuantum:
2730           case YellowQuantum:
2731           {
2732             SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2733             break;
2734           }
2735           case AlphaQuantum:
2736           {
2737             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2738             break;
2739           }
2740           case OpacityQuantum:
2741           {
2742             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2743             break;
2744           }
2745           case BlackQuantum:
2746           {
2747             SetPixelBlack(image,ClampToQuantum(QuantumRange*(*p)),q);
2748             break;
2749           }
2750           case IndexQuantum:
2751           {
2752             SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2753             break;
2754           }
2755           default:
2756             break;
2757         }
2758         p++;
2759       }
2760       q+=GetPixelChannels(image);
2761     }
2762     if (SyncAuthenticPixels(image,exception) == MagickFalse)
2763       break;
2764   }
2765 }
2766
2767 static void ImportFloatPixel(Image *image,const RectangleInfo *roi,
2768   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
2769   ExceptionInfo *exception)
2770 {
2771   register const float
2772     *restrict p;
2773
2774   register Quantum
2775     *restrict q;
2776
2777   register ssize_t
2778     x;
2779
2780   size_t
2781     length;
2782
2783   ssize_t
2784     y;
2785
2786   p=(const float *) pixels;
2787   if (LocaleCompare(map,"BGR") == 0)
2788     {
2789       for (y=0; y < (ssize_t) roi->height; y++)
2790       {
2791         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2792         if (q == (Quantum *) NULL)
2793           break;
2794         for (x=0; x < (ssize_t) roi->width; x++)
2795         {
2796           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2797           p++;
2798           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2799           p++;
2800           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2801           p++;
2802           q+=GetPixelChannels(image);
2803         }
2804         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2805           break;
2806       }
2807       return;
2808     }
2809   if (LocaleCompare(map,"BGRA") == 0)
2810     {
2811       for (y=0; y < (ssize_t) roi->height; y++)
2812       {
2813         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2814         if (q == (Quantum *) NULL)
2815           break;
2816         for (x=0; x < (ssize_t) roi->width; x++)
2817         {
2818           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2819           p++;
2820           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2821           p++;
2822           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2823           p++;
2824           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2825           p++;
2826           q+=GetPixelChannels(image);
2827         }
2828         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2829           break;
2830       }
2831       return;
2832     }
2833   if (LocaleCompare(map,"BGRP") == 0)
2834     {
2835       for (y=0; y < (ssize_t) roi->height; y++)
2836       {
2837         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2838         if (q == (Quantum *) NULL)
2839           break;
2840         for (x=0; x < (ssize_t) roi->width; x++)
2841         {
2842           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2843           p++;
2844           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2845           p++;
2846           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2847           p++;
2848           p++;
2849           q+=GetPixelChannels(image);
2850         }
2851         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2852           break;
2853       }
2854       return;
2855     }
2856   if (LocaleCompare(map,"I") == 0)
2857     {
2858       for (y=0; y < (ssize_t) roi->height; y++)
2859       {
2860         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2861         if (q == (Quantum *) NULL)
2862           break;
2863         for (x=0; x < (ssize_t) roi->width; x++)
2864         {
2865           SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2866           p++;
2867           q+=GetPixelChannels(image);
2868         }
2869         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2870           break;
2871       }
2872       return;
2873     }
2874   if (LocaleCompare(map,"RGB") == 0)
2875     {
2876       for (y=0; y < (ssize_t) roi->height; y++)
2877       {
2878         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2879         if (q == (Quantum *) NULL)
2880           break;
2881         for (x=0; x < (ssize_t) roi->width; x++)
2882         {
2883           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2884           p++;
2885           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2886           p++;
2887           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2888           p++;
2889           q+=GetPixelChannels(image);
2890         }
2891         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2892           break;
2893       }
2894       return;
2895     }
2896   if (LocaleCompare(map,"RGBA") == 0)
2897     {
2898       for (y=0; y < (ssize_t) roi->height; y++)
2899       {
2900         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2901         if (q == (Quantum *) NULL)
2902           break;
2903         for (x=0; x < (ssize_t) roi->width; x++)
2904         {
2905           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2906           p++;
2907           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2908           p++;
2909           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2910           p++;
2911           SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2912           p++;
2913           q+=GetPixelChannels(image);
2914         }
2915         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2916           break;
2917       }
2918       return;
2919     }
2920   if (LocaleCompare(map,"RGBP") == 0)
2921     {
2922       for (y=0; y < (ssize_t) roi->height; y++)
2923       {
2924         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2925         if (q == (Quantum *) NULL)
2926           break;
2927         for (x=0; x < (ssize_t) roi->width; x++)
2928         {
2929           SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2930           p++;
2931           SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2932           p++;
2933           SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2934           p++;
2935           q+=GetPixelChannels(image);
2936         }
2937         if (SyncAuthenticPixels(image,exception) == MagickFalse)
2938           break;
2939       }
2940       return;
2941     }
2942   length=strlen(map);
2943   for (y=0; y < (ssize_t) roi->height; y++)
2944   {
2945     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
2946     if (q == (Quantum *) NULL)
2947       break;
2948     for (x=0; x < (ssize_t) roi->width; x++)
2949     {
2950       register ssize_t
2951         i;
2952
2953       for (i=0; i < (ssize_t) length; i++)
2954       {
2955         switch (quantum_map[i])
2956         {
2957           case RedQuantum:
2958           case CyanQuantum:
2959           {
2960             SetPixelRed(image,ClampToQuantum(QuantumRange*(*p)),q);
2961             break;
2962           }
2963           case GreenQuantum:
2964           case MagentaQuantum:
2965           {
2966             SetPixelGreen(image,ClampToQuantum(QuantumRange*(*p)),q);
2967             break;
2968           }
2969           case BlueQuantum:
2970           case YellowQuantum:
2971           {
2972             SetPixelBlue(image,ClampToQuantum(QuantumRange*(*p)),q);
2973             break;
2974           }
2975           case AlphaQuantum:
2976           {
2977             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2978             break;
2979           }
2980           case OpacityQuantum:
2981           {
2982             SetPixelAlpha(image,ClampToQuantum(QuantumRange*(*p)),q);
2983             break;
2984           }
2985           case BlackQuantum:
2986           {
2987             SetPixelBlack(image,ClampToQuantum(QuantumRange*(*p)),q);
2988             break;
2989           }
2990           case IndexQuantum:
2991           {
2992             SetPixelGray(image,ClampToQuantum(QuantumRange*(*p)),q);
2993             break;
2994           }
2995           default:
2996             break;
2997         }
2998         p++;
2999       }
3000       q+=GetPixelChannels(image);
3001     }
3002     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3003       break;
3004   }
3005 }
3006
3007 static void ImportLongPixel(Image *image,const RectangleInfo *roi,
3008   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3009   ExceptionInfo *exception)
3010 {
3011   register const unsigned int
3012     *restrict p;
3013
3014   register Quantum
3015     *restrict q;
3016
3017   register ssize_t
3018     x;
3019
3020   size_t
3021     length;
3022
3023   ssize_t
3024     y;
3025
3026   p=(const unsigned int *) pixels;
3027   if (LocaleCompare(map,"BGR") == 0)
3028     {
3029       for (y=0; y < (ssize_t) roi->height; y++)
3030       {
3031         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3032         if (q == (Quantum *) NULL)
3033           break;
3034         for (x=0; x < (ssize_t) roi->width; x++)
3035         {
3036           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3037           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3038           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3039           q+=GetPixelChannels(image);
3040         }
3041         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3042           break;
3043       }
3044       return;
3045     }
3046   if (LocaleCompare(map,"BGRA") == 0)
3047     {
3048       for (y=0; y < (ssize_t) roi->height; y++)
3049       {
3050         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3051         if (q == (Quantum *) NULL)
3052           break;
3053         for (x=0; x < (ssize_t) roi->width; x++)
3054         {
3055           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3056           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3057           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3058           SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
3059           q+=GetPixelChannels(image);
3060         }
3061         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3062           break;
3063       }
3064       return;
3065     }
3066   if (LocaleCompare(map,"BGRP") == 0)
3067     {
3068       for (y=0; y < (ssize_t) roi->height; y++)
3069       {
3070         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3071         if (q == (Quantum *) NULL)
3072           break;
3073         for (x=0; x < (ssize_t) roi->width; x++)
3074         {
3075           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3076           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3077           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3078           p++;
3079           q+=GetPixelChannels(image);
3080         }
3081         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3082           break;
3083       }
3084       return;
3085     }
3086   if (LocaleCompare(map,"I") == 0)
3087     {
3088       for (y=0; y < (ssize_t) roi->height; y++)
3089       {
3090         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3091         if (q == (Quantum *) NULL)
3092           break;
3093         for (x=0; x < (ssize_t) roi->width; x++)
3094         {
3095           SetPixelGray(image,ScaleLongToQuantum(*p++),q);
3096           q+=GetPixelChannels(image);
3097         }
3098         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3099           break;
3100       }
3101       return;
3102     }
3103   if (LocaleCompare(map,"RGB") == 0)
3104     {
3105       for (y=0; y < (ssize_t) roi->height; y++)
3106       {
3107         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3108         if (q == (Quantum *) NULL)
3109           break;
3110         for (x=0; x < (ssize_t) roi->width; x++)
3111         {
3112           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3113           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3114           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3115           q+=GetPixelChannels(image);
3116         }
3117         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3118           break;
3119       }
3120       return;
3121     }
3122   if (LocaleCompare(map,"RGBA") == 0)
3123     {
3124       for (y=0; y < (ssize_t) roi->height; y++)
3125       {
3126         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3127         if (q == (Quantum *) NULL)
3128           break;
3129         for (x=0; x < (ssize_t) roi->width; x++)
3130         {
3131           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3132           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3133           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3134           SetPixelAlpha(image,ScaleLongToQuantum(*p++),q);
3135           q+=GetPixelChannels(image);
3136         }
3137         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3138           break;
3139       }
3140       return;
3141     }
3142   if (LocaleCompare(map,"RGBP") == 0)
3143     {
3144       for (y=0; y < (ssize_t) roi->height; y++)
3145       {
3146         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3147         if (q == (Quantum *) NULL)
3148           break;
3149         for (x=0; x < (ssize_t) roi->width; x++)
3150         {
3151           SetPixelRed(image,ScaleLongToQuantum(*p++),q);
3152           SetPixelGreen(image,ScaleLongToQuantum(*p++),q);
3153           SetPixelBlue(image,ScaleLongToQuantum(*p++),q);
3154           p++;
3155           q+=GetPixelChannels(image);
3156         }
3157         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3158           break;
3159       }
3160       return;
3161     }
3162   length=strlen(map);
3163   for (y=0; y < (ssize_t) roi->height; y++)
3164   {
3165     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3166     if (q == (Quantum *) NULL)
3167       break;
3168     for (x=0; x < (ssize_t) roi->width; x++)
3169     {
3170       register ssize_t
3171         i;
3172
3173       for (i=0; i < (ssize_t) length; i++)
3174       {
3175         switch (quantum_map[i])
3176         {
3177           case RedQuantum:
3178           case CyanQuantum:
3179           {
3180             SetPixelRed(image,ScaleLongToQuantum(*p),q);
3181             break;
3182           }
3183           case GreenQuantum:
3184           case MagentaQuantum:
3185           {
3186             SetPixelGreen(image,ScaleLongToQuantum(*p),q);
3187             break;
3188           }
3189           case BlueQuantum:
3190           case YellowQuantum:
3191           {
3192             SetPixelBlue(image,ScaleLongToQuantum(*p),q);
3193             break;
3194           }
3195           case AlphaQuantum:
3196           {
3197             SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
3198             break;
3199           }
3200           case OpacityQuantum:
3201           {
3202             SetPixelAlpha(image,ScaleLongToQuantum(*p),q);
3203             break;
3204           }
3205           case BlackQuantum:
3206           {
3207             SetPixelBlack(image,ScaleLongToQuantum(*p),q);
3208             break;
3209           }
3210           case IndexQuantum:
3211           {
3212             SetPixelGray(image,ScaleLongToQuantum(*p),q);
3213             break;
3214           }
3215           default:
3216             break;
3217         }
3218         p++;
3219       }
3220       q+=GetPixelChannels(image);
3221     }
3222     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3223       break;
3224   }
3225 }
3226
3227 static void ImportLongLongPixel(Image *image,const RectangleInfo *roi,
3228   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3229   ExceptionInfo *exception)
3230 {
3231   register const MagickSizeType
3232     *restrict p;
3233
3234   register Quantum
3235     *restrict q;
3236
3237   register ssize_t
3238     x;
3239
3240   size_t
3241     length;
3242
3243   ssize_t
3244     y;
3245
3246   p=(const MagickSizeType *) pixels;
3247   if (LocaleCompare(map,"BGR") == 0)
3248     {
3249       for (y=0; y < (ssize_t) roi->height; y++)
3250       {
3251         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3252         if (q == (Quantum *) NULL)
3253           break;
3254         for (x=0; x < (ssize_t) roi->width; x++)
3255         {
3256           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3257           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3258           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3259           q+=GetPixelChannels(image);
3260         }
3261         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3262           break;
3263       }
3264       return;
3265     }
3266   if (LocaleCompare(map,"BGRA") == 0)
3267     {
3268       for (y=0; y < (ssize_t) roi->height; y++)
3269       {
3270         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3271         if (q == (Quantum *) NULL)
3272           break;
3273         for (x=0; x < (ssize_t) roi->width; x++)
3274         {
3275           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3276           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3277           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3278           SetPixelAlpha(image,ScaleLongLongToQuantum(*p++),q);
3279           q+=GetPixelChannels(image);
3280         }
3281         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3282           break;
3283       }
3284       return;
3285     }
3286   if (LocaleCompare(map,"BGRP") == 0)
3287     {
3288       for (y=0; y < (ssize_t) roi->height; y++)
3289       {
3290         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3291         if (q == (Quantum *) NULL)
3292           break;
3293         for (x=0; x < (ssize_t) roi->width; x++)
3294         {
3295           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3296           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3297           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3298           p++;
3299           q+=GetPixelChannels(image);
3300         }
3301         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3302           break;
3303       }
3304       return;
3305     }
3306   if (LocaleCompare(map,"I") == 0)
3307     {
3308       for (y=0; y < (ssize_t) roi->height; y++)
3309       {
3310         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3311         if (q == (Quantum *) NULL)
3312           break;
3313         for (x=0; x < (ssize_t) roi->width; x++)
3314         {
3315           SetPixelGray(image,ScaleLongLongToQuantum(*p++),q);
3316           q+=GetPixelChannels(image);
3317         }
3318         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3319           break;
3320       }
3321       return;
3322     }
3323   if (LocaleCompare(map,"RGB") == 0)
3324     {
3325       for (y=0; y < (ssize_t) roi->height; y++)
3326       {
3327         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3328         if (q == (Quantum *) NULL)
3329           break;
3330         for (x=0; x < (ssize_t) roi->width; x++)
3331         {
3332           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3333           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3334           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3335           q+=GetPixelChannels(image);
3336         }
3337         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3338           break;
3339       }
3340       return;
3341     }
3342   if (LocaleCompare(map,"RGBA") == 0)
3343     {
3344       for (y=0; y < (ssize_t) roi->height; y++)
3345       {
3346         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3347         if (q == (Quantum *) NULL)
3348           break;
3349         for (x=0; x < (ssize_t) roi->width; x++)
3350         {
3351           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3352           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3353           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3354           SetPixelAlpha(image,ScaleLongLongToQuantum(*p++),q);
3355           q+=GetPixelChannels(image);
3356         }
3357         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3358           break;
3359       }
3360       return;
3361     }
3362   if (LocaleCompare(map,"RGBP") == 0)
3363     {
3364       for (y=0; y < (ssize_t) roi->height; y++)
3365       {
3366         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3367         if (q == (Quantum *) NULL)
3368           break;
3369         for (x=0; x < (ssize_t) roi->width; x++)
3370         {
3371           SetPixelRed(image,ScaleLongLongToQuantum(*p++),q);
3372           SetPixelGreen(image,ScaleLongLongToQuantum(*p++),q);
3373           SetPixelBlue(image,ScaleLongLongToQuantum(*p++),q);
3374           p++;
3375           q+=GetPixelChannels(image);
3376         }
3377         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3378           break;
3379       }
3380       return;
3381     }
3382   length=strlen(map);
3383   for (y=0; y < (ssize_t) roi->height; y++)
3384   {
3385     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3386     if (q == (Quantum *) NULL)
3387       break;
3388     for (x=0; x < (ssize_t) roi->width; x++)
3389     {
3390       register ssize_t
3391         i;
3392
3393       for (i=0; i < (ssize_t) length; i++)
3394       {
3395         switch (quantum_map[i])
3396         {
3397           case RedQuantum:
3398           case CyanQuantum:
3399           {
3400             SetPixelRed(image,ScaleLongLongToQuantum(*p),q);
3401             break;
3402           }
3403           case GreenQuantum:
3404           case MagentaQuantum:
3405           {
3406             SetPixelGreen(image,ScaleLongLongToQuantum(*p),q);
3407             break;
3408           }
3409           case BlueQuantum:
3410           case YellowQuantum:
3411           {
3412             SetPixelBlue(image,ScaleLongLongToQuantum(*p),q);
3413             break;
3414           }
3415           case AlphaQuantum:
3416           {
3417             SetPixelAlpha(image,ScaleLongLongToQuantum(*p),q);
3418             break;
3419           }
3420           case OpacityQuantum:
3421           {
3422             SetPixelAlpha(image,ScaleLongLongToQuantum(*p),q);
3423             break;
3424           }
3425           case BlackQuantum:
3426           {
3427             SetPixelBlack(image,ScaleLongLongToQuantum(*p),q);
3428             break;
3429           }
3430           case IndexQuantum:
3431           {
3432             SetPixelGray(image,ScaleLongLongToQuantum(*p),q);
3433             break;
3434           }
3435           default:
3436             break;
3437         }
3438         p++;
3439       }
3440       q+=GetPixelChannels(image);
3441     }
3442     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3443       break;
3444   }
3445 }
3446
3447 static void ImportQuantumPixel(Image *image,const RectangleInfo *roi,
3448   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3449   ExceptionInfo *exception)
3450 {
3451   register const Quantum
3452     *restrict p;
3453
3454   register Quantum
3455     *restrict q;
3456
3457   register ssize_t
3458     x;
3459
3460   size_t
3461     length;
3462
3463   ssize_t
3464     y;
3465
3466   p=(const Quantum *) pixels;
3467   if (LocaleCompare(map,"BGR") == 0)
3468     {
3469       for (y=0; y < (ssize_t) roi->height; y++)
3470       {
3471         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3472         if (q == (Quantum *) NULL)
3473           break;
3474         for (x=0; x < (ssize_t) roi->width; x++)
3475         {
3476           SetPixelBlue(image,*p++,q);
3477           SetPixelGreen(image,*p++,q);
3478           SetPixelRed(image,*p++,q);
3479           q+=GetPixelChannels(image);
3480         }
3481         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3482           break;
3483       }
3484       return;
3485     }
3486   if (LocaleCompare(map,"BGRA") == 0)
3487     {
3488       for (y=0; y < (ssize_t) roi->height; y++)
3489       {
3490         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3491         if (q == (Quantum *) NULL)
3492           break;
3493         for (x=0; x < (ssize_t) roi->width; x++)
3494         {
3495           SetPixelBlue(image,*p++,q);
3496           SetPixelGreen(image,*p++,q);
3497           SetPixelRed(image,*p++,q);
3498           SetPixelAlpha(image,*p++,q);
3499           q+=GetPixelChannels(image);
3500         }
3501         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3502           break;
3503       }
3504       return;
3505     }
3506   if (LocaleCompare(map,"BGRP") == 0)
3507     {
3508       for (y=0; y < (ssize_t) roi->height; y++)
3509       {
3510         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3511         if (q == (Quantum *) NULL)
3512           break;
3513         for (x=0; x < (ssize_t) roi->width; x++)
3514         {
3515           SetPixelBlue(image,*p++,q);
3516           SetPixelGreen(image,*p++,q);
3517           SetPixelRed(image,*p++,q);
3518           p++;
3519           q+=GetPixelChannels(image);
3520         }
3521         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3522           break;
3523       }
3524       return;
3525     }
3526   if (LocaleCompare(map,"I") == 0)
3527     {
3528       for (y=0; y < (ssize_t) roi->height; y++)
3529       {
3530         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3531         if (q == (Quantum *) NULL)
3532           break;
3533         for (x=0; x < (ssize_t) roi->width; x++)
3534         {
3535           SetPixelGray(image,*p++,q);
3536           q+=GetPixelChannels(image);
3537         }
3538         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3539           break;
3540       }
3541       return;
3542     }
3543   if (LocaleCompare(map,"RGB") == 0)
3544     {
3545       for (y=0; y < (ssize_t) roi->height; y++)
3546       {
3547         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3548         if (q == (Quantum *) NULL)
3549           break;
3550         for (x=0; x < (ssize_t) roi->width; x++)
3551         {
3552           SetPixelRed(image,*p++,q);
3553           SetPixelGreen(image,*p++,q);
3554           SetPixelBlue(image,*p++,q);
3555           q+=GetPixelChannels(image);
3556         }
3557         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3558           break;
3559       }
3560       return;
3561     }
3562   if (LocaleCompare(map,"RGBA") == 0)
3563     {
3564       for (y=0; y < (ssize_t) roi->height; y++)
3565       {
3566         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3567         if (q == (Quantum *) NULL)
3568           break;
3569         for (x=0; x < (ssize_t) roi->width; x++)
3570         {
3571           SetPixelRed(image,*p++,q);
3572           SetPixelGreen(image,*p++,q);
3573           SetPixelBlue(image,*p++,q);
3574           SetPixelAlpha(image,*p++,q);
3575           q+=GetPixelChannels(image);
3576         }
3577         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3578           break;
3579       }
3580       return;
3581     }
3582   if (LocaleCompare(map,"RGBP") == 0)
3583     {
3584       for (y=0; y < (ssize_t) roi->height; y++)
3585       {
3586         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3587         if (q == (Quantum *) NULL)
3588           break;
3589         for (x=0; x < (ssize_t) roi->width; x++)
3590         {
3591           SetPixelRed(image,*p++,q);
3592           SetPixelGreen(image,*p++,q);
3593           SetPixelBlue(image,*p++,q);
3594           p++;
3595           q+=GetPixelChannels(image);
3596         }
3597         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3598           break;
3599       }
3600       return;
3601     }
3602   length=strlen(map);
3603   for (y=0; y < (ssize_t) roi->height; y++)
3604   {
3605     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3606     if (q == (Quantum *) NULL)
3607       break;
3608     for (x=0; x < (ssize_t) roi->width; x++)
3609     {
3610       register ssize_t
3611         i;
3612
3613       for (i=0; i < (ssize_t) length; i++)
3614       {
3615         switch (quantum_map[i])
3616         {
3617           case RedQuantum:
3618           case CyanQuantum:
3619           {
3620             SetPixelRed(image,*p,q);
3621             break;
3622           }
3623           case GreenQuantum:
3624           case MagentaQuantum:
3625           {
3626             SetPixelGreen(image,*p,q);
3627             break;
3628           }
3629           case BlueQuantum:
3630           case YellowQuantum:
3631           {
3632             SetPixelBlue(image,*p,q);
3633             break;
3634           }
3635           case AlphaQuantum:
3636           {
3637             SetPixelAlpha(image,*p,q);
3638             break;
3639           }
3640           case OpacityQuantum:
3641           {
3642             SetPixelAlpha(image,*p,q);
3643             break;
3644           }
3645           case BlackQuantum:
3646           {
3647             SetPixelBlack(image,*p,q);
3648             break;
3649           }
3650           case IndexQuantum:
3651           {
3652             SetPixelGray(image,*p,q);
3653             break;
3654           }
3655           default:
3656             break;
3657         }
3658         p++;
3659       }
3660       q+=GetPixelChannels(image);
3661     }
3662     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3663       break;
3664   }
3665 }
3666
3667 static void ImportShortPixel(Image *image,const RectangleInfo *roi,
3668   const char *restrict map,const QuantumType *quantum_map,const void *pixels,
3669   ExceptionInfo *exception)
3670 {
3671   register const unsigned short
3672     *restrict p;
3673
3674   register Quantum
3675     *restrict q;
3676
3677   register ssize_t
3678     x;
3679
3680   size_t
3681     length;
3682
3683   ssize_t
3684     y;
3685
3686   p=(const unsigned short *) pixels;
3687   if (LocaleCompare(map,"BGR") == 0)
3688     {
3689       for (y=0; y < (ssize_t) roi->height; y++)
3690       {
3691         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3692         if (q == (Quantum *) NULL)
3693           break;
3694         for (x=0; x < (ssize_t) roi->width; x++)
3695         {
3696           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3697           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3698           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3699           q+=GetPixelChannels(image);
3700         }
3701         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3702           break;
3703       }
3704       return;
3705     }
3706   if (LocaleCompare(map,"BGRA") == 0)
3707     {
3708       for (y=0; y < (ssize_t) roi->height; y++)
3709       {
3710         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3711         if (q == (Quantum *) NULL)
3712           break;
3713         for (x=0; x < (ssize_t) roi->width; x++)
3714         {
3715           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3716           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3717           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3718           SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
3719           q+=GetPixelChannels(image);
3720         }
3721         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3722           break;
3723       }
3724       return;
3725     }
3726   if (LocaleCompare(map,"BGRP") == 0)
3727     {
3728       for (y=0; y < (ssize_t) roi->height; y++)
3729       {
3730         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3731         if (q == (Quantum *) NULL)
3732           break;
3733         for (x=0; x < (ssize_t) roi->width; x++)
3734         {
3735           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3736           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3737           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3738           p++;
3739           q+=GetPixelChannels(image);
3740         }
3741         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3742           break;
3743       }
3744       return;
3745     }
3746   if (LocaleCompare(map,"I") == 0)
3747     {
3748       for (y=0; y < (ssize_t) roi->height; y++)
3749       {
3750         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3751         if (q == (Quantum *) NULL)
3752           break;
3753         for (x=0; x < (ssize_t) roi->width; x++)
3754         {
3755           SetPixelGray(image,ScaleShortToQuantum(*p++),q);
3756           q+=GetPixelChannels(image);
3757         }
3758         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3759           break;
3760       }
3761       return;
3762     }
3763   if (LocaleCompare(map,"RGB") == 0)
3764     {
3765       for (y=0; y < (ssize_t) roi->height; y++)
3766       {
3767         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3768         if (q == (Quantum *) NULL)
3769           break;
3770         for (x=0; x < (ssize_t) roi->width; x++)
3771         {
3772           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3773           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3774           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3775           q+=GetPixelChannels(image);
3776         }
3777         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3778           break;
3779       }
3780       return;
3781     }
3782   if (LocaleCompare(map,"RGBA") == 0)
3783     {
3784       for (y=0; y < (ssize_t) roi->height; y++)
3785       {
3786         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3787         if (q == (Quantum *) NULL)
3788           break;
3789         for (x=0; x < (ssize_t) roi->width; x++)
3790         {
3791           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3792           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3793           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3794           SetPixelAlpha(image,ScaleShortToQuantum(*p++),q);
3795           q+=GetPixelChannels(image);
3796         }
3797         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3798           break;
3799       }
3800       return;
3801     }
3802   if (LocaleCompare(map,"RGBP") == 0)
3803     {
3804       for (y=0; y < (ssize_t) roi->height; y++)
3805       {
3806         q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3807         if (q == (Quantum *) NULL)
3808           break;
3809         for (x=0; x < (ssize_t) roi->width; x++)
3810         {
3811           SetPixelRed(image,ScaleShortToQuantum(*p++),q);
3812           SetPixelGreen(image,ScaleShortToQuantum(*p++),q);
3813           SetPixelBlue(image,ScaleShortToQuantum(*p++),q);
3814           p++;
3815           q+=GetPixelChannels(image);
3816         }
3817         if (SyncAuthenticPixels(image,exception) == MagickFalse)
3818           break;
3819       }
3820       return;
3821     }
3822   length=strlen(map);
3823   for (y=0; y < (ssize_t) roi->height; y++)
3824   {
3825     q=GetAuthenticPixels(image,roi->x,roi->y+y,roi->width,1,exception);
3826     if (q == (Quantum *) NULL)
3827       break;
3828     for (x=0; x < (ssize_t) roi->width; x++)
3829     {
3830       register ssize_t
3831         i;
3832
3833       for (i=0; i < (ssize_t) length; i++)
3834       {
3835         switch (quantum_map[i])
3836         {
3837           case RedQuantum:
3838           case CyanQuantum:
3839           {
3840             SetPixelRed(image,ScaleShortToQuantum(*p),q);
3841             break;
3842           }
3843           case GreenQuantum:
3844           case MagentaQuantum:
3845           {
3846             SetPixelGreen(image,ScaleShortToQuantum(*p),q);
3847             break;
3848           }
3849           case BlueQuantum:
3850           case YellowQuantum:
3851           {
3852             SetPixelBlue(image,ScaleShortToQuantum(*p),q);
3853             break;
3854           }
3855           case AlphaQuantum:
3856           {
3857             SetPixelAlpha(image,ScaleShortToQuantum(*p),q);
3858             break;
3859           }
3860           case OpacityQuantum:
3861           {
3862             SetPixelAlpha(image,ScaleShortToQuantum(*p),q);
3863             break;
3864           }
3865           case BlackQuantum:
3866           {
3867             SetPixelBlack(image,ScaleShortToQuantum(*p),q);
3868             break;
3869           }
3870           case IndexQuantum:
3871           {
3872             SetPixelGray(image,ScaleShortToQuantum(*p),q);
3873             break;
3874           }
3875           default:
3876             break;
3877         }
3878         p++;
3879       }
3880       q+=GetPixelChannels(image);
3881     }
3882     if (SyncAuthenticPixels(image,exception) == MagickFalse)
3883       break;
3884   }
3885 }
3886
3887 MagickExport MagickBooleanType ImportImagePixels(Image *image,const ssize_t x,
3888   const ssize_t y,const size_t width,const size_t height,const char *map,
3889   const StorageType type,const void *pixels,ExceptionInfo *exception)
3890 {
3891   QuantumType
3892     *quantum_map;
3893
3894   RectangleInfo
3895     roi;
3896
3897   register ssize_t
3898     i;
3899
3900   size_t
3901     length;
3902
3903   /*
3904     Allocate image structure.
3905   */
3906   assert(image != (Image *) NULL);
3907   assert(image->signature == MagickSignature);
3908   if (image->debug != MagickFalse)
3909     (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename);
3910   length=strlen(map);
3911   quantum_map=(QuantumType *) AcquireQuantumMemory(length,sizeof(*quantum_map));
3912   if (quantum_map == (QuantumType *) NULL)
3913     ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
3914       image->filename);
3915   for (i=0; i < (ssize_t) length; i++)
3916   {
3917     switch (map[i])
3918     {
3919       case 'a':
3920       case 'A':
3921       {
3922         quantum_map[i]=AlphaQuantum;
3923         image->alpha_trait=BlendPixelTrait;
3924         break;
3925       }
3926       case 'B':
3927       case 'b':
3928       {
3929         quantum_map[i]=BlueQuantum;
3930         break;
3931       }
3932       case 'C':
3933       case 'c':
3934       {
3935         quantum_map[i]=CyanQuantum;
3936         (void) SetImageColorspace(image,CMYKColorspace,exception);
3937         break;
3938       }
3939       case 'g':
3940       case 'G':
3941       {
3942         quantum_map[i]=GreenQuantum;
3943         break;
3944       }
3945       case 'K':
3946       case 'k':
3947       {
3948         quantum_map[i]=BlackQuantum;
3949         (void) SetImageColorspace(image,CMYKColorspace,exception);
3950         break;
3951       }
3952       case 'I':
3953       case 'i':
3954       {
3955         quantum_map[i]=IndexQuantum;
3956         (void) SetImageColorspace(image,GRAYColorspace,exception);
3957         break;
3958       }
3959       case 'm':
3960       case 'M':
3961       {
3962         quantum_map[i]=MagentaQuantum;
3963         (void) SetImageColorspace(image,CMYKColorspace,exception);
3964         break;
3965       }
3966       case 'O':
3967       case 'o':
3968       {
3969         quantum_map[i]=OpacityQuantum;
3970         image->alpha_trait=BlendPixelTrait;
3971         break;
3972       }
3973       case 'P':
3974       case 'p':
3975       {
3976         quantum_map[i]=UndefinedQuantum;
3977         break;
3978       }
3979       case 'R':
3980       case 'r':
3981       {
3982         quantum_map[i]=RedQuantum;
3983         break;
3984       }
3985       case 'Y':
3986       case 'y':
3987       {
3988         quantum_map[i]=YellowQuantum;
3989         (void) SetImageColorspace(image,CMYKColorspace,exception);
3990         break;
3991       }
3992       default:
3993       {
3994         quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
3995         (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
3996           "UnrecognizedPixelMap","`%s'",map);
3997         return(MagickFalse);
3998       }
3999     }
4000   }
4001   if (SetImageStorageClass(image,DirectClass,exception) == MagickFalse)
4002     return(MagickFalse);
4003   /*
4004     Transfer the pixels from the pixel data to the image.
4005   */
4006   roi.width=width;
4007   roi.height=height;
4008   roi.x=x;
4009   roi.y=y;
4010   switch (type)
4011   {
4012     case CharPixel:
4013     {
4014       ImportCharPixel(image,&roi,map,quantum_map,pixels,exception);
4015       break;
4016     }
4017     case DoublePixel:
4018     {
4019       ImportDoublePixel(image,&roi,map,quantum_map,pixels,exception);
4020       break;
4021     }
4022     case FloatPixel:
4023     {
4024       ImportFloatPixel(image,&roi,map,quantum_map,pixels,exception);
4025       break;
4026     }
4027     case LongPixel:
4028     {
4029       ImportLongPixel(image,&roi,map,quantum_map,pixels,exception);
4030       break;
4031     }
4032     case LongLongPixel:
4033     {
4034       ImportLongLongPixel(image,&roi,map,quantum_map,pixels,exception);
4035       break;
4036     }
4037     case QuantumPixel:
4038     {
4039       ImportQuantumPixel(image,&roi,map,quantum_map,pixels,exception);
4040       break;
4041     }
4042     case ShortPixel:
4043     {
4044       ImportShortPixel(image,&roi,map,quantum_map,pixels,exception);
4045       break;
4046     }
4047     default:
4048     {
4049       quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
4050       (void) ThrowMagickException(exception,GetMagickModule(),OptionError,
4051         "UnrecognizedPixelMap","`%s'",map);
4052       break;
4053     }
4054   }
4055   quantum_map=(QuantumType *) RelinquishMagickMemory(quantum_map);
4056   return(MagickTrue);
4057 }
4058 \f
4059 /*
4060 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4061 %                                                                             %
4062 %                                                                             %
4063 %                                                                             %
4064 +   I n i t i a l i z e P i x e l C h a n n e l M a p                         %
4065 %                                                                             %
4066 %                                                                             %
4067 %                                                                             %
4068 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4069 %
4070 %  InitializePixelChannelMap() defines the standard pixel component map.
4071 %
4072 %  The format of the InitializePixelChannelMap() method is:
4073 %
4074 %      void InitializePixelChannelMap(Image *image)
4075 %
4076 %  A description of each parameter follows:
4077 %
4078 %    o image: the image.
4079 %
4080 */
4081 MagickExport void InitializePixelChannelMap(Image *image)
4082 {
4083   PixelTrait
4084     trait;
4085
4086   register ssize_t
4087     i;
4088
4089   ssize_t
4090     n;
4091
4092   assert(image != (Image *) NULL);
4093   assert(image->signature == MagickSignature);
4094   (void) ResetMagickMemory(image->channel_map,0,MaxPixelChannels*
4095     sizeof(*image->channel_map));
4096   trait=UpdatePixelTrait;
4097   if (image->alpha_trait == BlendPixelTrait)
4098     trait=(PixelTrait) (trait | BlendPixelTrait);
4099   n=0;
4100   if (image->colorspace == GRAYColorspace)
4101     {
4102       SetPixelChannelAttributes(image,BluePixelChannel,trait,n);
4103       SetPixelChannelAttributes(image,GreenPixelChannel,trait,n);
4104       SetPixelChannelAttributes(image,RedPixelChannel,trait,n++);
4105     }
4106   else
4107     {
4108       SetPixelChannelAttributes(image,RedPixelChannel,trait,n++);
4109       SetPixelChannelAttributes(image,GreenPixelChannel,trait,n++);
4110       SetPixelChannelAttributes(image,BluePixelChannel,trait,n++);
4111     }
4112   if (image->colorspace == CMYKColorspace)
4113     SetPixelChannelAttributes(image,BlackPixelChannel,trait,n++);
4114   if (image->alpha_trait != UndefinedPixelTrait)
4115     SetPixelChannelAttributes(image,AlphaPixelChannel,CopyPixelTrait,n++);
4116   if (image->storage_class == PseudoClass)
4117     SetPixelChannelAttributes(image,IndexPixelChannel,CopyPixelTrait,n++);
4118   if (image->mask != MagickFalse)
4119     SetPixelChannelAttributes(image,MaskPixelChannel,CopyPixelTrait,n++);
4120   assert((n+image->number_meta_channels) < MaxPixelChannels);
4121   for (i=0; i < (ssize_t) image->number_meta_channels; i++)
4122     SetPixelChannelAttributes(image,(PixelChannel) (MetaPixelChannel+i),
4123       CopyPixelTrait,n++);
4124   image->number_channels=(size_t) n;
4125   if (image->debug != MagickFalse)
4126     LogPixelChannels(image);
4127   (void) SetImageChannelMask(image,image->channel_mask);
4128 }
4129 \f
4130 /*
4131 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4132 %                                                                             %
4133 %                                                                             %
4134 %                                                                             %
4135 %   I n t e r p o l a t e P i x e l C h a n n e l                             %
4136 %                                                                             %
4137 %                                                                             %
4138 %                                                                             %
4139 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4140 %
4141 %  InterpolatePixelChannel() applies a pixel interpolation method between a
4142 %  floating point coordinate and the pixels surrounding that coordinate.  No
4143 %  pixel area resampling, or scaling of the result is performed.
4144 %
4145 %  Interpolation is restricted to just the specified channel.
4146 %
4147 %  The format of the InterpolatePixelChannel method is:
4148 %
4149 %      MagickBooleanType InterpolatePixelChannel(const Image *image,
4150 %        const CacheView *image_view,const PixelChannel channel,
4151 %        const PixelInterpolateMethod method,const double x,const double y,
4152 %        double *pixel,ExceptionInfo *exception)
4153 %
4154 %  A description of each parameter follows:
4155 %
4156 %    o image: the image.
4157 %
4158 %    o image_view: the image view.
4159 %
4160 %    o channel: the pixel channel to interpolate.
4161 %
4162 %    o method: the pixel color interpolation method.
4163 %
4164 %    o x,y: A double representing the current (x,y) position of the pixel.
4165 %
4166 %    o pixel: return the interpolated pixel here.
4167 %
4168 %    o exception: return any errors or warnings in this structure.
4169 %
4170 */
4171
4172 static inline void CatromWeights(const double x,double (*weights)[4])
4173 {
4174   double
4175     alpha,
4176     beta,
4177     gamma;
4178
4179   /*
4180     Nicolas Robidoux' 10 flops (4* + 5- + 1+) refactoring of the computation
4181     of the standard four 1D Catmull-Rom weights. The sampling location is
4182     assumed between the second and third input pixel locations, and x is the
4183     position relative to the second input pixel location. Formulas originally
4184     derived for the VIPS (Virtual Image Processing System) library.
4185   */
4186   alpha=(double) 1.0-x;
4187   beta=(double) (-0.5)*x*alpha;
4188   (*weights)[0]=alpha*beta;
4189   (*weights)[3]=x*beta;
4190   /*
4191     The following computation of the inner weights from the outer ones work
4192     for all Keys cubics.
4193   */
4194   gamma=(*weights)[3]-(*weights)[0];
4195   (*weights)[1]=alpha-(*weights)[0]+gamma;
4196   (*weights)[2]=x-(*weights)[3]-gamma;
4197 }
4198
4199 static inline void SplineWeights(const double x,double (*weights)[4])
4200 {
4201   double
4202     alpha,
4203     beta;
4204
4205   /*
4206     Nicolas Robidoux' 12 flops (6* + 5- + 1+) refactoring of the
4207     computation of the standard four 1D cubic B-spline smoothing
4208     weights. The sampling location is assumed between the second and
4209     third input pixel locations, and x is the position relative to the
4210     second input pixel location.
4211   */
4212   alpha=(double) 1.0-x;
4213   (*weights)[3]=(double) (1.0/6.0)*x*x*x;
4214   (*weights)[0]=(double) (1.0/6.0)*alpha*alpha*alpha;
4215   beta=(*weights)[3]-(*weights)[0];
4216   (*weights)[1]=alpha-(*weights)[0]+beta;
4217   (*weights)[2]=x-(*weights)[3]-beta;
4218 }
4219
4220 static inline double MeshInterpolate(const PointInfo *delta,const double p,
4221   const double x,const double y)
4222 {
4223   return(delta->x*x+delta->y*y+(1.0-delta->x-delta->y)*p);
4224 }
4225
4226 /*
4227 static inline ssize_t NearestNeighbor(const double x)
4228 {
4229   if (x >= 0.0)
4230     return((ssize_t) (x+0.5));
4231   return((ssize_t) (x-0.5));
4232 }
4233 */
4234
4235 MagickExport MagickBooleanType InterpolatePixelChannel(const Image *image,
4236   const CacheView *image_view,const PixelChannel channel,
4237   const PixelInterpolateMethod method,const double x,const double y,
4238   double *pixel,ExceptionInfo *exception)
4239 {
4240   MagickBooleanType
4241     status;
4242
4243   double
4244     alpha[16],
4245     gamma,
4246     pixels[16];
4247
4248   PixelTrait
4249     traits;
4250
4251   register const Quantum
4252     *p;
4253
4254   register ssize_t
4255     i;
4256
4257   ssize_t
4258     x_offset,
4259     y_offset;
4260
4261   PixelInterpolateMethod
4262     interpolate;
4263
4264   assert(image != (Image *) NULL);
4265   assert(image != (Image *) NULL);
4266   assert(image->signature == MagickSignature);
4267   assert(image_view != (CacheView *) NULL);
4268   status=MagickTrue;
4269   *pixel=0.0;
4270   traits=GetPixelChannelTraits(image,channel);
4271   x_offset=(ssize_t) floor(x);
4272   y_offset=(ssize_t) floor(y);
4273   interpolate = method;
4274   if ( interpolate == UndefinedInterpolatePixel )
4275     interpolate = image->interpolate;
4276   switch (interpolate)
4277   {
4278     case AverageInterpolatePixel:        /* nearest 4 neighbours */
4279     case Average9InterpolatePixel:       /* nearest 9 neighbours */
4280     case Average16InterpolatePixel:      /* nearest 16 neighbours */
4281     {
4282       ssize_t
4283         count;
4284
4285       count=2;  /* size of the area to average - default nearest 4 */
4286       if (interpolate == Average9InterpolatePixel)
4287         {
4288           count=3;
4289           x_offset=(ssize_t) (floor(x+0.5)-1);
4290           y_offset=(ssize_t) (floor(y+0.5)-1);
4291         }
4292       else
4293         if (interpolate == Average16InterpolatePixel)
4294           {
4295             count=4;
4296             x_offset--;
4297             y_offset--;
4298           }
4299       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,(size_t) count,(size_t)
4300         count,exception);
4301       if (p == (const Quantum *) NULL)
4302         {
4303           status=MagickFalse;
4304           break;
4305         }
4306       count*=count;   /* Number of pixels to Average */
4307       if ((traits & BlendPixelTrait) == 0)
4308         for (i=0; i < (ssize_t) count; i++)
4309         {
4310           alpha[i]=1.0;
4311           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4312         }
4313       else
4314         for (i=0; i < (ssize_t) count; i++)
4315         {
4316           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4317             GetPixelChannels(image));
4318           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4319         }
4320       for (i=0; i < (ssize_t) count; i++)
4321       {
4322         gamma=PerceptibleReciprocal(alpha[i])/count;
4323         *pixel+=gamma*pixels[i];
4324       }
4325       break;
4326     }
4327     case BilinearInterpolatePixel:
4328     default:
4329     {
4330       PointInfo
4331         delta,
4332         epsilon;
4333
4334       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
4335       if (p == (const Quantum *) NULL)
4336         {
4337           status=MagickFalse;
4338           break;
4339         }
4340       if ((traits & BlendPixelTrait) == 0)
4341         for (i=0; i < 4; i++)
4342         {
4343           alpha[i]=1.0;
4344           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4345         }
4346       else
4347         for (i=0; i < 4; i++)
4348         {
4349           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4350             GetPixelChannels(image));
4351           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4352         }
4353       delta.x=x-x_offset;
4354       delta.y=y-y_offset;
4355       epsilon.x=1.0-delta.x;
4356       epsilon.y=1.0-delta.y;
4357       gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
4358         (epsilon.x*alpha[2]+delta.x*alpha[3])));
4359       gamma=PerceptibleReciprocal(gamma);
4360       *pixel=gamma*(epsilon.y*(epsilon.x*pixels[0]+delta.x*pixels[1])+delta.y*
4361         (epsilon.x*pixels[2]+delta.x*pixels[3]));
4362       break;
4363     }
4364     case BlendInterpolatePixel:
4365     {
4366       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
4367       if (p == (const Quantum *) NULL)
4368         {
4369           status=MagickFalse;
4370           break;
4371         }
4372       if ((traits & BlendPixelTrait) == 0)
4373         for (i=0; i < 4; i++)
4374         {
4375           alpha[i]=1.0;
4376           pixels[i]=(MagickRealType) p[i*GetPixelChannels(image)+channel];
4377         }
4378       else
4379         for (i=0; i < 4; i++)
4380         {
4381           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4382             GetPixelChannels(image));
4383           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4384         }
4385       gamma=1.0;    /* number of pixels blended together (its variable) */
4386       for (i=0; i <= 1L; i++) {
4387         if ((y-y_offset) >= 0.75)
4388           {
4389             alpha[i]=alpha[i+2];  /* take right pixels */
4390             pixels[i]=pixels[i+2];
4391           }
4392         else
4393           if ((y-y_offset) > 0.25)
4394             {
4395               gamma=2.0;  /* blend both pixels in row */
4396               alpha[i]+=alpha[i+2];  /* add up alpha weights */
4397               pixels[i]+=pixels[i+2];
4398             }
4399       }
4400       if ((x-x_offset) >= 0.75)
4401         {
4402           alpha[0]=alpha[1];  /* take bottom row blend */
4403           pixels[0]=pixels[1];
4404         }
4405       else
4406         if ((x-x_offset) > 0.25)
4407           {
4408             gamma*=2.0;  /* blend both rows */
4409             alpha[0]+=alpha[1];  /* add up alpha weights */
4410             pixels[0]+=pixels[1];
4411           }
4412       if (channel != AlphaPixelChannel)
4413         gamma=PerceptibleReciprocal(alpha[0]); /* (color) 1/alpha_weights */
4414       else
4415         gamma=PerceptibleReciprocal(gamma); /* (alpha) 1/number_of_pixels */
4416       *pixel=gamma*pixels[0];
4417       break;
4418     }
4419     case CatromInterpolatePixel:
4420     {
4421       double
4422         cx[4],
4423         cy[4];
4424
4425       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
4426         exception);
4427       if (p == (const Quantum *) NULL)
4428         {
4429           status=MagickFalse;
4430           break;
4431         }
4432       if ((traits & BlendPixelTrait) == 0)
4433         for (i=0; i < 16; i++)
4434         {
4435           alpha[i]=1.0;
4436           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4437         }
4438       else
4439         for (i=0; i < 16; i++)
4440         {
4441           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4442             GetPixelChannels(image));
4443           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4444         }
4445       CatromWeights((double) (x-x_offset),&cx);
4446       CatromWeights((double) (y-y_offset),&cy);
4447       gamma=(channel == AlphaPixelChannel ? (double) 1.0 :
4448         PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
4449         alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
4450         alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
4451         alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
4452         cx[2]*alpha[14]+cx[3]*alpha[15])));
4453       *pixel=gamma*(cy[0]*(cx[0]*pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+
4454         cx[3]*pixels[3])+cy[1]*(cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*
4455         pixels[6]+cx[3]*pixels[7])+cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+
4456         cx[2]*pixels[10]+cx[3]*pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*
4457         pixels[13]+cx[2]*pixels[14]+cx[3]*pixels[15]));
4458       break;
4459     }
4460 #if 0
4461     /* deprecated useless and very slow interpolator */
4462     case FilterInterpolatePixel:
4463     {
4464       CacheView
4465         *filter_view;
4466
4467       Image
4468         *excerpt_image,
4469         *filter_image;
4470
4471       RectangleInfo
4472         geometry;
4473
4474       geometry.width=4L;
4475       geometry.height=4L;
4476       geometry.x=x_offset-1;
4477       geometry.y=y_offset-1;
4478       excerpt_image=ExcerptImage(image,&geometry,exception);
4479       if (excerpt_image == (Image *) NULL)
4480         {
4481           status=MagickFalse;
4482           break;
4483         }
4484       filter_image=ResizeImage(excerpt_image,1,1,image->filter,exception);
4485       excerpt_image=DestroyImage(excerpt_image);
4486       if (filter_image == (Image *) NULL)
4487         break;
4488       filter_view=AcquireVirtualCacheView(filter_image,exception);
4489       p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
4490       if (p == (const Quantum *) NULL)
4491         status=MagickFalse;
4492       else
4493         *pixel=(double) GetPixelChannel(image,channel,p);
4494       filter_view=DestroyCacheView(filter_view);
4495       filter_image=DestroyImage(filter_image);
4496       break;
4497     }
4498 #endif
4499     case IntegerInterpolatePixel:
4500     {
4501       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
4502       if (p == (const Quantum *) NULL)
4503         {
4504           status=MagickFalse;
4505           break;
4506         }
4507       *pixel=(double) GetPixelChannel(image,channel,p);
4508       break;
4509     }
4510     case NearestInterpolatePixel:
4511     {
4512       x_offset=(ssize_t) floor(x+0.5);
4513       y_offset=(ssize_t) floor(y+0.5);
4514       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
4515       if (p == (const Quantum *) NULL)
4516         {
4517           status=MagickFalse;
4518           break;
4519         }
4520       *pixel=(double) GetPixelChannel(image,channel,p);
4521       break;
4522     }
4523     case MeshInterpolatePixel:
4524     {
4525       PointInfo
4526         delta,
4527         luminance;
4528
4529       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
4530       if (p == (const Quantum *) NULL)
4531         {
4532           status=MagickFalse;
4533           break;
4534         }
4535       if ((traits & BlendPixelTrait) == 0)
4536         for (i=0; i < 4; i++)
4537         {
4538           alpha[i]=1.0;
4539           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4540         }
4541       else
4542         for (i=0; i < 4; i++)
4543         {
4544           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4545             GetPixelChannels(image));
4546           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4547         }
4548       delta.x=x-x_offset;
4549       delta.y=y-y_offset;
4550       luminance.x=GetPixelLuminance(image,p)-(double)
4551         GetPixelLuminance(image,p+3*GetPixelChannels(image));
4552       luminance.y=GetPixelLuminance(image,p+GetPixelChannels(image))-(double)
4553         GetPixelLuminance(image,p+2*GetPixelChannels(image));
4554       if (fabs(luminance.x) < fabs(luminance.y))
4555         {
4556           /*
4557             Diagonal 0-3 NW-SE.
4558           */
4559           if (delta.x <= delta.y)
4560             {
4561               /*
4562                 Bottom-left triangle (pixel: 2, diagonal: 0-3).
4563               */
4564               delta.y=1.0-delta.y;
4565               gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
4566               gamma=PerceptibleReciprocal(gamma);
4567               *pixel=gamma*MeshInterpolate(&delta,pixels[2],pixels[3],
4568                 pixels[0]);
4569             }
4570           else
4571             {
4572               /*
4573                 Top-right triangle (pixel: 1, diagonal: 0-3).
4574               */
4575               delta.x=1.0-delta.x;
4576               gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
4577               gamma=PerceptibleReciprocal(gamma);
4578               *pixel=gamma*MeshInterpolate(&delta,pixels[1],pixels[0],
4579                 pixels[3]);
4580             }
4581         }
4582       else
4583         {
4584           /*
4585             Diagonal 1-2 NE-SW.
4586           */
4587           if (delta.x <= (1.0-delta.y))
4588             {
4589               /*
4590                 Top-left triangle (pixel: 0, diagonal: 1-2).
4591               */
4592               gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
4593               gamma=PerceptibleReciprocal(gamma);
4594               *pixel=gamma*MeshInterpolate(&delta,pixels[0],pixels[1],
4595                 pixels[2]);
4596             }
4597           else
4598             {
4599               /*
4600                 Bottom-right triangle (pixel: 3, diagonal: 1-2).
4601               */
4602               delta.x=1.0-delta.x;
4603               delta.y=1.0-delta.y;
4604               gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
4605               gamma=PerceptibleReciprocal(gamma);
4606               *pixel=gamma*MeshInterpolate(&delta,pixels[3],pixels[2],
4607                 pixels[1]);
4608             }
4609         }
4610       break;
4611     }
4612     case SplineInterpolatePixel:
4613     {
4614       double
4615         cx[4],
4616         cy[4];
4617
4618       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
4619         exception);
4620       if (p == (const Quantum *) NULL)
4621         {
4622           status=MagickFalse;
4623           break;
4624         }
4625       if ((traits & BlendPixelTrait) == 0)
4626         for (i=0; i < 16; i++)
4627         {
4628           alpha[i]=1.0;
4629           pixels[i]=(double) p[i*GetPixelChannels(image)+channel];
4630         }
4631       else
4632         for (i=0; i < 16; i++)
4633         {
4634           alpha[i]=QuantumScale*GetPixelAlpha(image,p+i*
4635             GetPixelChannels(image));
4636           pixels[i]=alpha[i]*p[i*GetPixelChannels(image)+channel];
4637         }
4638       SplineWeights((double) (x-x_offset),&cx);
4639       SplineWeights((double) (y-y_offset),&cy);
4640       gamma=(channel == AlphaPixelChannel ? (double) 1.0 :
4641         PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
4642         alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
4643         alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
4644         alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
4645         cx[2]*alpha[14]+cx[3]*alpha[15])));
4646       *pixel=gamma*(cy[0]*(cx[0]*pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+
4647         cx[3]*pixels[3])+cy[1]*(cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*
4648         pixels[6]+cx[3]*pixels[7])+cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+
4649         cx[2]*pixels[10]+cx[3]*pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*
4650         pixels[13]+cx[2]*pixels[14]+cx[3]*pixels[15]));
4651       break;
4652     }
4653   }
4654   return(status);
4655 }
4656 \f
4657 /*
4658 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4659 %                                                                             %
4660 %                                                                             %
4661 %                                                                             %
4662 %   I n t e r p o l a t e P i x e l C h a n n e l s                           %
4663 %                                                                             %
4664 %                                                                             %
4665 %                                                                             %
4666 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4667 %
4668 %  InterpolatePixelChannels() applies a pixel interpolation method between a
4669 %  floating point coordinate and the pixels surrounding that coordinate.  No
4670 %  pixel area resampling, or scaling of the result is performed.
4671 %
4672 %  Interpolation is restricted to just the current channel setting of the
4673 %  destination image into which the color is to be stored
4674 %
4675 %  The format of the InterpolatePixelChannels method is:
4676 %
4677 %      MagickBooleanType InterpolatePixelChannels(const Image *source,
4678 %        const CacheView *source_view,const Image *destination,
4679 %        const PixelInterpolateMethod method,const double x,const double y,
4680 %        Quantum *pixel,ExceptionInfo *exception)
4681 %
4682 %  A description of each parameter follows:
4683 %
4684 %    o source: the source.
4685 %
4686 %    o source_view: the source view.
4687 %
4688 %    o destination: the destination image, for the interpolated color
4689 %
4690 %    o method: the pixel color interpolation method.
4691 %
4692 %    o x,y: A double representing the current (x,y) position of the pixel.
4693 %
4694 %    o pixel: return the interpolated pixel here.
4695 %
4696 %    o exception: return any errors or warnings in this structure.
4697 %
4698 */
4699 MagickExport MagickBooleanType InterpolatePixelChannels(const Image *source,
4700   const CacheView *source_view,const Image *destination,
4701   const PixelInterpolateMethod method,const double x,const double y,
4702   Quantum *pixel,ExceptionInfo *exception)
4703 {
4704   MagickBooleanType
4705     status;
4706
4707   double
4708     alpha[16],
4709     gamma,
4710     pixels[16];
4711
4712   register const Quantum
4713     *p;
4714
4715   register ssize_t
4716     i;
4717
4718   ssize_t
4719     x_offset,
4720     y_offset;
4721
4722   PixelInterpolateMethod
4723     interpolate;
4724
4725   assert(source != (Image *) NULL);
4726   assert(source != (Image *) NULL);
4727   assert(source->signature == MagickSignature);
4728   assert(source_view != (CacheView *) NULL);
4729   status=MagickTrue;
4730   x_offset=(ssize_t) floor(x);
4731   y_offset=(ssize_t) floor(y);
4732   interpolate = method;
4733   if ( interpolate == UndefinedInterpolatePixel )
4734     interpolate = source->interpolate;
4735   switch (interpolate)
4736   {
4737     case AverageInterpolatePixel:        /* nearest 4 neighbours */
4738     case Average9InterpolatePixel:       /* nearest 9 neighbours */
4739     case Average16InterpolatePixel:      /* nearest 16 neighbours */
4740     {
4741       ssize_t
4742         count;
4743
4744       count=2;  /* size of the area to average - default nearest 4 */
4745       if (interpolate == Average9InterpolatePixel)
4746         {
4747           count=3;
4748           x_offset=(ssize_t) (floor(x+0.5)-1);
4749           y_offset=(ssize_t) (floor(y+0.5)-1);
4750         }
4751       else
4752         if (interpolate == Average16InterpolatePixel)
4753           {
4754             count=4;
4755             x_offset--;
4756             y_offset--;
4757           }
4758       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,(size_t) count,(size_t)
4759         count,exception);
4760       if (p == (const Quantum *) NULL)
4761         {
4762           status=MagickFalse;
4763           break;
4764         }
4765       count*=count;  /* Number of pixels to Average */
4766       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4767       {
4768         double
4769           sum;
4770
4771         register ssize_t
4772           j;
4773
4774         PixelChannel channel=GetPixelChannelChannel(source,i);
4775         PixelTrait traits=GetPixelChannelTraits(source,channel);
4776         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4777           channel);
4778         if ((traits == UndefinedPixelTrait) ||
4779             (destination_traits == UndefinedPixelTrait))
4780           continue;
4781         for (j=0; j < (ssize_t) count; j++)
4782           pixels[j]=(double) p[j*GetPixelChannels(source)+i];
4783         sum=0.0;
4784         if ((traits & BlendPixelTrait) == 0)
4785           {
4786             for (j=0; j < (ssize_t) count; j++)
4787               sum+=pixels[j];
4788             sum/=count;
4789             SetPixelChannel(destination,channel,ClampToQuantum(sum),pixel);
4790             continue;
4791           }
4792         for (j=0; j < (ssize_t) count; j++)
4793         {
4794           alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
4795             GetPixelChannels(source));
4796           pixels[j]*=alpha[j];
4797           gamma=PerceptibleReciprocal(alpha[j]);
4798           sum+=gamma*pixels[j];
4799         }
4800         sum/=count;
4801         SetPixelChannel(destination,channel,ClampToQuantum(sum),pixel);
4802       }
4803       break;
4804     }
4805     case BilinearInterpolatePixel:
4806     default:
4807     {
4808       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
4809       if (p == (const Quantum *) NULL)
4810         {
4811           status=MagickFalse;
4812           break;
4813         }
4814       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4815       {
4816         PointInfo
4817           delta,
4818           epsilon;
4819
4820         PixelChannel channel=GetPixelChannelChannel(source,i);
4821         PixelTrait traits=GetPixelChannelTraits(source,channel);
4822         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4823           channel);
4824         if ((traits == UndefinedPixelTrait) ||
4825             (destination_traits == UndefinedPixelTrait))
4826           continue;
4827         delta.x=x-x_offset;
4828         delta.y=y-y_offset;
4829         epsilon.x=1.0-delta.x;
4830         epsilon.y=1.0-delta.y;
4831         pixels[0]=(double) p[i];
4832         pixels[1]=(double) p[GetPixelChannels(source)+i];
4833         pixels[2]=(double) p[2*GetPixelChannels(source)+i];
4834         pixels[3]=(double) p[3*GetPixelChannels(source)+i];
4835         if ((traits & BlendPixelTrait) == 0)
4836           {
4837             gamma=((epsilon.y*(epsilon.x+delta.x)+delta.y*(epsilon.x+delta.x)));
4838             gamma=PerceptibleReciprocal(gamma);
4839             SetPixelChannel(destination,channel,ClampToQuantum(gamma*(epsilon.y*
4840               (epsilon.x*pixels[0]+delta.x*pixels[1])+delta.y*(epsilon.x*
4841               pixels[2]+delta.x*pixels[3]))),pixel);
4842             continue;
4843           }
4844         alpha[0]=QuantumScale*GetPixelAlpha(source,p);
4845         alpha[1]=QuantumScale*GetPixelAlpha(source,p+GetPixelChannels(source));
4846         alpha[2]=QuantumScale*GetPixelAlpha(source,p+2*
4847           GetPixelChannels(source));
4848         alpha[3]=QuantumScale*GetPixelAlpha(source,p+3*
4849           GetPixelChannels(source));
4850         pixels[0]*=alpha[0];
4851         pixels[1]*=alpha[1];
4852         pixels[2]*=alpha[2];
4853         pixels[3]*=alpha[3];
4854         gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
4855           (epsilon.x*alpha[2]+delta.x*alpha[3])));
4856         gamma=PerceptibleReciprocal(gamma);
4857         SetPixelChannel(destination,channel,ClampToQuantum(gamma*(epsilon.y*
4858           (epsilon.x*pixels[0]+delta.x*pixels[1])+delta.y*(epsilon.x*pixels[2]+
4859           delta.x*pixels[3]))),pixel);
4860       }
4861       break;
4862     }
4863     case BlendInterpolatePixel:
4864     {
4865       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
4866       if (p == (const Quantum *) NULL)
4867         {
4868           status=MagickFalse;
4869           break;
4870         }
4871       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4872       {
4873         register ssize_t
4874           j;
4875
4876         PixelChannel channel=GetPixelChannelChannel(source,i);
4877         PixelTrait traits=GetPixelChannelTraits(source,channel);
4878         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4879           channel);
4880         if ((traits == UndefinedPixelTrait) ||
4881             (destination_traits == UndefinedPixelTrait))
4882           continue;
4883         if ((traits & BlendPixelTrait) == 0)
4884           for (j=0; j < 4; j++)
4885           {
4886             alpha[j]=1.0;
4887             pixels[j]=(MagickRealType) p[j*GetPixelChannels(source)+channel];
4888           }
4889         else
4890           for (j=0; j < 4; j++)
4891           {
4892             alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
4893               GetPixelChannels(source));
4894             pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+channel];
4895           }
4896         gamma=1.0;  /* number of pixels blended together (its variable) */
4897         for (j=0; j <= 1L; j++)
4898         {
4899           if ((y-y_offset) >= 0.75)
4900             {
4901               alpha[j]=alpha[j+2];  /* take right pixels */
4902               pixels[j]=pixels[j+2];
4903             }
4904           else
4905             if ((y-y_offset) > 0.25)
4906               {
4907                 gamma=2.0;              /* blend both pixels in row */
4908                 alpha[j]+=alpha[j+2];  /* add up alpha weights */
4909                 pixels[j]+=pixels[j+2];
4910               }
4911         }
4912         if ((x-x_offset) >= 0.75)
4913           {
4914             alpha[0]=alpha[1];  /* take bottom row blend */
4915             pixels[0]=pixels[1];
4916           }
4917         else
4918            if ((x-x_offset) > 0.25)
4919              {
4920                gamma*=2.0;  /* blend both rows */
4921                alpha[0]+=alpha[1];  /* add up alpha weights */
4922                pixels[0]+=pixels[1];
4923              }
4924         if ((traits & BlendPixelTrait) == 0)
4925           gamma=PerceptibleReciprocal(alpha[0]); /* (color) 1/alpha_weights */
4926         else
4927           gamma=PerceptibleReciprocal(gamma); /* (alpha) 1/number_of_pixels */
4928         SetPixelChannel(destination,channel,ClampToQuantum(gamma*pixels[0]),
4929           pixel);
4930       }
4931       break;
4932     }
4933     case CatromInterpolatePixel:
4934     {
4935       double
4936         cx[4],
4937         cy[4];
4938
4939       p=GetCacheViewVirtualPixels(source_view,x_offset-1,y_offset-1,4,4,
4940         exception);
4941       if (p == (const Quantum *) NULL)
4942         {
4943           status=MagickFalse;
4944           break;
4945         }
4946       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4947       {
4948         register ssize_t
4949           j;
4950
4951         PixelChannel channel=GetPixelChannelChannel(source,i);
4952         PixelTrait traits=GetPixelChannelTraits(source,channel);
4953         PixelTrait destination_traits=GetPixelChannelTraits(destination,
4954           channel);
4955         if ((traits == UndefinedPixelTrait) ||
4956             (destination_traits == UndefinedPixelTrait))
4957           continue;
4958         if ((traits & BlendPixelTrait) == 0)
4959           for (j=0; j < 16; j++)
4960           {
4961             alpha[j]=1.0;
4962             pixels[j]=(double) p[j*GetPixelChannels(source)+i];
4963           }
4964         else
4965           for (j=0; j < 16; j++)
4966           {
4967             alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
4968               GetPixelChannels(source));
4969             pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+i];
4970           }
4971         CatromWeights((double) (x-x_offset),&cx);
4972         CatromWeights((double) (y-y_offset),&cy);
4973         gamma=((traits & BlendPixelTrait) ? (double) (1.0) :
4974           PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
4975           alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
4976           alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
4977           alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
4978           cx[2]*alpha[14]+cx[3]*alpha[15])));
4979         SetPixelChannel(destination,channel,ClampToQuantum(gamma*(cy[0]*(cx[0]*
4980           pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+cx[3]*pixels[3])+cy[1]*
4981           (cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*pixels[6]+cx[3]*pixels[7])+
4982           cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+cx[2]*pixels[10]+cx[3]*
4983           pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*pixels[13]+cx[2]*
4984           pixels[14]+cx[3]*pixels[15]))),pixel);
4985       }
4986       break;
4987     }
4988 #if 0
4989     /* deprecated useless and very slow interpolator */
4990     case FilterInterpolatePixel:
4991     {
4992       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
4993       {
4994         CacheView
4995           *filter_view;
4996
4997         Image
4998           *excerpt_source,
4999           *filter_source;
5000
5001         RectangleInfo
5002           geometry;
5003
5004         PixelChannel channel=GetPixelChannelChannel(source,i);
5005         PixelTrait traits=GetPixelChannelTraits(source,channel);
5006         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5007           channel);
5008         if ((traits == UndefinedPixelTrait) ||
5009             (destination_traits == UndefinedPixelTrait))
5010           continue;
5011         geometry.width=4L;
5012         geometry.height=4L;
5013         geometry.x=x_offset-1;
5014         geometry.y=y_offset-1;
5015         excerpt_source=ExcerptImage(source,&geometry,exception);
5016         if (excerpt_source == (Image *) NULL)
5017           {
5018             status=MagickFalse;
5019             continue;
5020           }
5021         filter_source=ResizeImage(excerpt_source,1,1,source->filter,exception);
5022         excerpt_source=DestroyImage(excerpt_source);
5023         if (filter_source == (Image *) NULL)
5024           continue;
5025         filter_view=AcquireVirtualCacheView(filter_source,exception);
5026         p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
5027         if (p == (const Quantum *) NULL)
5028           status=MagickFalse;
5029         else
5030           {
5031             SetPixelChannel(destination,channel,p[i],pixel);
5032           }
5033         filter_view=DestroyCacheView(filter_view);
5034         filter_source=DestroyImage(filter_source);
5035       }
5036       break;
5037     }
5038 #endif
5039     case IntegerInterpolatePixel:
5040     {
5041       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,1,1,exception);
5042       if (p == (const Quantum *) NULL)
5043         {
5044           status=MagickFalse;
5045           break;
5046         }
5047       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5048       {
5049         PixelChannel channel=GetPixelChannelChannel(source,i);
5050         PixelTrait traits=GetPixelChannelTraits(source,channel);
5051         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5052           channel);
5053         if ((traits == UndefinedPixelTrait) ||
5054             (destination_traits == UndefinedPixelTrait))
5055           continue;
5056         SetPixelChannel(destination,channel,p[i],pixel);
5057       }
5058       break;
5059     }
5060     case NearestInterpolatePixel:
5061     {
5062       x_offset=(ssize_t) floor(x+0.5);
5063       y_offset=(ssize_t) floor(y+0.5);
5064       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,1,1,exception);
5065       if (p == (const Quantum *) NULL)
5066         {
5067           status=MagickFalse;
5068           break;
5069         }
5070       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5071       {
5072         PixelChannel channel=GetPixelChannelChannel(source,i);
5073         PixelTrait traits=GetPixelChannelTraits(source,channel);
5074         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5075           channel);
5076         if ((traits == UndefinedPixelTrait) ||
5077             (destination_traits == UndefinedPixelTrait))
5078           continue;
5079         SetPixelChannel(destination,channel,p[i],pixel);
5080       }
5081       break;
5082     }
5083     case MeshInterpolatePixel:
5084     {
5085       p=GetCacheViewVirtualPixels(source_view,x_offset,y_offset,2,2,exception);
5086       if (p == (const Quantum *) NULL)
5087         {
5088           status=MagickFalse;
5089           break;
5090         }
5091       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5092       {
5093         PointInfo
5094           delta,
5095           luminance;
5096
5097         PixelChannel channel=GetPixelChannelChannel(source,i);
5098         PixelTrait traits=GetPixelChannelTraits(source,channel);
5099         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5100           channel);
5101         if ((traits == UndefinedPixelTrait) ||
5102             (destination_traits == UndefinedPixelTrait))
5103           continue;
5104         pixels[0]=(double) p[i];
5105         pixels[1]=(double) p[GetPixelChannels(source)+i];
5106         pixels[2]=(double) p[2*GetPixelChannels(source)+i];
5107         pixels[3]=(double) p[3*GetPixelChannels(source)+i];
5108         if ((traits & BlendPixelTrait) == 0)
5109           {
5110             alpha[0]=1.0;
5111             alpha[1]=1.0;
5112             alpha[2]=1.0;
5113             alpha[3]=1.0;
5114           }
5115         else
5116           {
5117             alpha[0]=QuantumScale*GetPixelAlpha(source,p);
5118             alpha[1]=QuantumScale*GetPixelAlpha(source,p+
5119               GetPixelChannels(source));
5120             alpha[2]=QuantumScale*GetPixelAlpha(source,p+2*
5121               GetPixelChannels(source));
5122             alpha[3]=QuantumScale*GetPixelAlpha(source,p+3*
5123               GetPixelChannels(source));
5124           }
5125         delta.x=x-x_offset;
5126         delta.y=y-y_offset;
5127         luminance.x=fabs((double) (GetPixelLuminance(source,p)-
5128           GetPixelLuminance(source,p+3*GetPixelChannels(source))));
5129         luminance.y=fabs((double) (GetPixelLuminance(source,p+
5130           GetPixelChannels(source))-GetPixelLuminance(source,p+2*
5131           GetPixelChannels(source))));
5132         if (luminance.x < luminance.y)
5133           {
5134             /*
5135               Diagonal 0-3 NW-SE.
5136             */
5137             if (delta.x <= delta.y)
5138               {
5139                 /*
5140                   Bottom-left triangle (pixel: 2, diagonal: 0-3).
5141                 */
5142                 delta.y=1.0-delta.y;
5143                 gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
5144                 gamma=PerceptibleReciprocal(gamma);
5145                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5146                   MeshInterpolate(&delta,pixels[2],pixels[3],pixels[0])),pixel);
5147               }
5148             else
5149               {
5150                 /*
5151                   Top-right triangle (pixel: 1, diagonal: 0-3).
5152                 */
5153                 delta.x=1.0-delta.x;
5154                 gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
5155                 gamma=PerceptibleReciprocal(gamma);
5156                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5157                   MeshInterpolate(&delta,pixels[1],pixels[0],pixels[3])),pixel);
5158               }
5159           }
5160         else
5161           {
5162             /*
5163               Diagonal 1-2 NE-SW.
5164             */
5165             if (delta.x <= (1.0-delta.y))
5166               {
5167                 /*
5168                   Top-left triangle (pixel: 0, diagonal: 1-2).
5169                 */
5170                 gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
5171                 gamma=PerceptibleReciprocal(gamma);
5172                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5173                   MeshInterpolate(&delta,pixels[0],pixels[1],pixels[2])),pixel);
5174               }
5175             else
5176               {
5177                 /*
5178                   Bottom-right triangle (pixel: 3, diagonal: 1-2).
5179                 */
5180                 delta.x=1.0-delta.x;
5181                 delta.y=1.0-delta.y;
5182                 gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
5183                 gamma=PerceptibleReciprocal(gamma);
5184                 SetPixelChannel(destination,channel,ClampToQuantum(gamma*
5185                   MeshInterpolate(&delta,pixels[3],pixels[2],pixels[1])),pixel);
5186               }
5187           }
5188       }
5189       break;
5190     }
5191     case SplineInterpolatePixel:
5192     {
5193       double
5194         cx[4],
5195         cy[4];
5196
5197       p=GetCacheViewVirtualPixels(source_view,x_offset-1,y_offset-1,4,4,
5198         exception);
5199       if (p == (const Quantum *) NULL)
5200         {
5201           status=MagickFalse;
5202           break;
5203         }
5204       for (i=0; i < (ssize_t) GetPixelChannels(source); i++)
5205       {
5206         register ssize_t
5207           j;
5208
5209         PixelChannel channel=GetPixelChannelChannel(source,i);
5210         PixelTrait traits=GetPixelChannelTraits(source,channel);
5211         PixelTrait destination_traits=GetPixelChannelTraits(destination,
5212           channel);
5213         if ((traits == UndefinedPixelTrait) ||
5214             (destination_traits == UndefinedPixelTrait))
5215           continue;
5216         if ((traits & BlendPixelTrait) == 0)
5217           for (j=0; j < 16; j++)
5218           {
5219             alpha[j]=1.0;
5220             pixels[j]=(double) p[j*GetPixelChannels(source)+i];
5221           }
5222         else
5223           for (j=0; j < 16; j++)
5224           {
5225             alpha[j]=QuantumScale*GetPixelAlpha(source,p+j*
5226               GetPixelChannels(source));
5227             pixels[j]=alpha[j]*p[j*GetPixelChannels(source)+i];
5228           }
5229         SplineWeights((double) (x-x_offset),&cx);
5230         SplineWeights((double) (y-y_offset),&cy);
5231         gamma=((traits & BlendPixelTrait) ? (double) (1.0) :
5232           PerceptibleReciprocal(cy[0]*(cx[0]*alpha[0]+cx[1]*alpha[1]+cx[2]*
5233           alpha[2]+cx[3]*alpha[3])+cy[1]*(cx[0]*alpha[4]+cx[1]*alpha[5]+cx[2]*
5234           alpha[6]+cx[3]*alpha[7])+cy[2]*(cx[0]*alpha[8]+cx[1]*alpha[9]+cx[2]*
5235           alpha[10]+cx[3]*alpha[11])+cy[3]*(cx[0]*alpha[12]+cx[1]*alpha[13]+
5236           cx[2]*alpha[14]+cx[3]*alpha[15])));
5237         SetPixelChannel(destination,channel,ClampToQuantum(gamma*(cy[0]*(cx[0]*
5238           pixels[0]+cx[1]*pixels[1]+cx[2]*pixels[2]+cx[3]*pixels[3])+cy[1]*
5239           (cx[0]*pixels[4]+cx[1]*pixels[5]+cx[2]*pixels[6]+cx[3]*pixels[7])+
5240           cy[2]*(cx[0]*pixels[8]+cx[1]*pixels[9]+cx[2]*pixels[10]+cx[3]*
5241           pixels[11])+cy[3]*(cx[0]*pixels[12]+cx[1]*pixels[13]+cx[2]*
5242           pixels[14]+cx[3]*pixels[15]))),pixel);
5243       }
5244       break;
5245     }
5246   }
5247   return(status);
5248 }
5249 \f
5250 /*
5251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5252 %                                                                             %
5253 %                                                                             %
5254 %                                                                             %
5255 %   I n t e r p o l a t e P i x e l I n f o                                   %
5256 %                                                                             %
5257 %                                                                             %
5258 %                                                                             %
5259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5260 %
5261 %  InterpolatePixelInfo() applies a pixel interpolation method between a
5262 %  floating point coordinate and the pixels surrounding that coordinate.  No
5263 %  pixel area resampling, or scaling of the result is performed.
5264 %
5265 %  Interpolation is restricted to just RGBKA channels.
5266 %
5267 %  The format of the InterpolatePixelInfo method is:
5268 %
5269 %      MagickBooleanType InterpolatePixelInfo(const Image *image,
5270 %        const CacheView *image_view,const PixelInterpolateMethod method,
5271 %        const double x,const double y,PixelInfo *pixel,
5272 %        ExceptionInfo *exception)
5273 %
5274 %  A description of each parameter follows:
5275 %
5276 %    o image: the image.
5277 %
5278 %    o image_view: the image view.
5279 %
5280 %    o method: the pixel color interpolation method.
5281 %
5282 %    o x,y: A double representing the current (x,y) position of the pixel.
5283 %
5284 %    o pixel: return the interpolated pixel here.
5285 %
5286 %    o exception: return any errors or warnings in this structure.
5287 %
5288 */
5289
5290 static inline void AlphaBlendPixelInfo(const Image *image,
5291   const Quantum *pixel,PixelInfo *pixel_info,double *alpha)
5292 {
5293   if (image->alpha_trait != BlendPixelTrait)
5294     {
5295       *alpha=1.0;
5296       pixel_info->red=(double) GetPixelRed(image,pixel);
5297       pixel_info->green=(double) GetPixelGreen(image,pixel);
5298       pixel_info->blue=(double) GetPixelBlue(image,pixel);
5299       pixel_info->black=0.0;
5300       if (image->colorspace == CMYKColorspace)
5301         pixel_info->black=(double) GetPixelBlack(image,pixel);
5302       pixel_info->alpha=(double) GetPixelAlpha(image,pixel);
5303       return;
5304     }
5305   *alpha=QuantumScale*GetPixelAlpha(image,pixel);
5306   pixel_info->red=(*alpha*GetPixelRed(image,pixel));
5307   pixel_info->green=(*alpha*GetPixelGreen(image,pixel));
5308   pixel_info->blue=(*alpha*GetPixelBlue(image,pixel));
5309   pixel_info->black=0.0;
5310   if (image->colorspace == CMYKColorspace)
5311     pixel_info->black=(*alpha*GetPixelBlack(image,pixel));
5312   pixel_info->alpha=(double) GetPixelAlpha(image,pixel);
5313 }
5314
5315 MagickExport MagickBooleanType InterpolatePixelInfo(const Image *image,
5316   const CacheView *image_view,const PixelInterpolateMethod method,
5317   const double x,const double y,PixelInfo *pixel,ExceptionInfo *exception)
5318 {
5319   MagickBooleanType
5320     status;
5321
5322   double
5323     alpha[16],
5324     gamma;
5325
5326   PixelInfo
5327     pixels[16];
5328
5329   register const Quantum
5330     *p;
5331
5332   register ssize_t
5333     i;
5334
5335   ssize_t
5336     x_offset,
5337     y_offset;
5338
5339   PixelInterpolateMethod
5340     interpolate;
5341
5342   assert(image != (Image *) NULL);
5343   assert(image->signature == MagickSignature);
5344   assert(image_view != (CacheView *) NULL);
5345   status=MagickTrue;
5346   x_offset=(ssize_t) floor(x);
5347   y_offset=(ssize_t) floor(y);
5348   interpolate = method;
5349   if ( interpolate == UndefinedInterpolatePixel )
5350     interpolate = image->interpolate;
5351   switch (interpolate)
5352   {
5353     case AverageInterpolatePixel:        /* nearest 4 neighbours */
5354     case Average9InterpolatePixel:       /* nearest 9 neighbours */
5355     case Average16InterpolatePixel:      /* nearest 16 neighbours */
5356     {
5357       ssize_t
5358         count;
5359
5360       count=2;  /* size of the area to average - default nearest 4 */
5361       if (interpolate == Average9InterpolatePixel)
5362         {
5363           count=3;
5364           x_offset=(ssize_t) (floor(x+0.5)-1);
5365           y_offset=(ssize_t) (floor(y+0.5)-1);
5366         }
5367       else if (interpolate == Average16InterpolatePixel)
5368         {
5369           count=4;
5370           x_offset--;
5371           y_offset--;
5372         }
5373       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,(size_t) count,(size_t)
5374         count,exception);
5375       if (p == (const Quantum *) NULL)
5376         {
5377           status=MagickFalse;
5378           break;
5379         }
5380       pixel->red=0.0;
5381       pixel->green=0.0;
5382       pixel->blue=0.0;
5383       pixel->black=0.0;
5384       pixel->alpha=0.0;
5385       count*=count;         /* number of pixels - square of size */
5386       for (i=0; i < (ssize_t) count; i++)
5387       {
5388         AlphaBlendPixelInfo(image,p,pixels,alpha);
5389         gamma=PerceptibleReciprocal(alpha[0]);
5390         pixel->red+=gamma*pixels[0].red;
5391         pixel->green+=gamma*pixels[0].green;
5392         pixel->blue+=gamma*pixels[0].blue;
5393         pixel->black+=gamma*pixels[0].black;
5394         pixel->alpha+=pixels[0].alpha;
5395         p += GetPixelChannels(image);
5396       }
5397       gamma=1.0/count;   /* average weighting of each pixel in area */
5398       pixel->red*=gamma;
5399       pixel->green*=gamma;
5400       pixel->blue*=gamma;
5401       pixel->black*=gamma;
5402       pixel->alpha*=gamma;
5403       break;
5404     }
5405     case BackgroundInterpolatePixel:
5406     {
5407       *pixel=image->background_color;  /* Copy PixelInfo Structure  */
5408       break;
5409     }
5410     case BilinearInterpolatePixel:
5411     default:
5412     {
5413       PointInfo
5414         delta,
5415         epsilon;
5416
5417       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
5418       if (p == (const Quantum *) NULL)
5419         {
5420           status=MagickFalse;
5421           break;
5422         }
5423       for (i=0; i < 4L; i++)
5424         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5425       delta.x=x-x_offset;
5426       delta.y=y-y_offset;
5427       epsilon.x=1.0-delta.x;
5428       epsilon.y=1.0-delta.y;
5429       gamma=((epsilon.y*(epsilon.x*alpha[0]+delta.x*alpha[1])+delta.y*
5430         (epsilon.x*alpha[2]+delta.x*alpha[3])));
5431       gamma=PerceptibleReciprocal(gamma);
5432       pixel->red=gamma*(epsilon.y*(epsilon.x*pixels[0].red+delta.x*
5433         pixels[1].red)+delta.y*(epsilon.x*pixels[2].red+delta.x*pixels[3].red));
5434       pixel->green=gamma*(epsilon.y*(epsilon.x*pixels[0].green+delta.x*
5435         pixels[1].green)+delta.y*(epsilon.x*pixels[2].green+delta.x*
5436         pixels[3].green));
5437       pixel->blue=gamma*(epsilon.y*(epsilon.x*pixels[0].blue+delta.x*
5438         pixels[1].blue)+delta.y*(epsilon.x*pixels[2].blue+delta.x*
5439         pixels[3].blue));
5440       if (image->colorspace == CMYKColorspace)
5441         pixel->black=gamma*(epsilon.y*(epsilon.x*pixels[0].black+delta.x*
5442           pixels[1].black)+delta.y*(epsilon.x*pixels[2].black+delta.x*
5443           pixels[3].black));
5444       gamma=((epsilon.y*(epsilon.x+delta.x)+delta.y*(epsilon.x+delta.x)));
5445       gamma=PerceptibleReciprocal(gamma);
5446       pixel->alpha=(epsilon.y*(epsilon.x*pixels[0].alpha+delta.x*
5447         pixels[1].alpha)+delta.y*(epsilon.x*pixels[2].alpha+delta.x*
5448         pixels[3].alpha));
5449       break;
5450     }
5451     case BlendInterpolatePixel:
5452     {
5453       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
5454       if (p == (const Quantum *) NULL)
5455         {
5456           status=MagickFalse;
5457           break;
5458         }
5459       for (i=0; i < 4L; i++)
5460         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5461       gamma=1.0;  /* number of pixels blended together (its variable) */
5462       for (i=0; i <= 1L; i++)
5463       {
5464         if ((y-y_offset) >= 0.75)
5465           {
5466             alpha[i]=alpha[i+2];  /* take right pixels */
5467             pixels[i]=pixels[i+2];
5468           }
5469         else
5470           if ((y-y_offset) > 0.25)
5471             {
5472               gamma=2.0;  /* blend both pixels in row */
5473               alpha[i]+=alpha[i+2];  /* add up alpha weights */
5474               pixels[i].red+=pixels[i+2].red;
5475               pixels[i].green+=pixels[i+2].green;
5476               pixels[i].blue+=pixels[i+2].blue;
5477               pixels[i].black+=pixels[i+2].black;
5478               pixels[i].alpha+=pixels[i+2].alpha;
5479             }
5480       }
5481       if ((x-x_offset) >= 0.75)
5482         {
5483           alpha[0]=alpha[1];
5484           pixels[0]=pixels[1];
5485         }
5486       else
5487         if ((x-x_offset) > 0.25)
5488           {
5489             gamma*=2.0;  /* blend both rows */
5490             alpha[0]+= alpha[1];      /* add up alpha weights */
5491             pixels[0].red+=pixels[1].red;
5492             pixels[0].green+=pixels[1].green;
5493             pixels[0].blue+=pixels[1].blue;
5494             pixels[0].black+=pixels[1].black;
5495             pixels[0].alpha+=pixels[1].alpha;
5496           }
5497       gamma=1.0/gamma;
5498       alpha[0]=PerceptibleReciprocal(alpha[0]);
5499       pixel->red=alpha[0]*pixels[0].red;
5500       pixel->green=alpha[0]*pixels[0].green;  /* divide by sum of alpha */
5501       pixel->blue=alpha[0]*pixels[0].blue;
5502       pixel->black=alpha[0]*pixels[0].black;
5503       pixel->alpha=gamma*pixels[0].alpha;   /* divide by number of pixels */
5504       break;
5505     }
5506     case CatromInterpolatePixel:
5507     {
5508       double
5509         cx[4],
5510         cy[4];
5511
5512       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
5513         exception);
5514       if (p == (const Quantum *) NULL)
5515         {
5516           status=MagickFalse;
5517           break;
5518         }
5519       for (i=0; i < 16L; i++)
5520         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5521       CatromWeights((double) (x-x_offset),&cx);
5522       CatromWeights((double) (y-y_offset),&cy);
5523       pixel->red=(cy[0]*(cx[0]*pixels[0].red+cx[1]*pixels[1].red+cx[2]*
5524         pixels[2].red+cx[3]*pixels[3].red)+cy[1]*(cx[0]*pixels[4].red+cx[1]*
5525         pixels[5].red+cx[2]*pixels[6].red+cx[3]*pixels[7].red)+cy[2]*(cx[0]*
5526         pixels[8].red+cx[1]*pixels[9].red+cx[2]*pixels[10].red+cx[3]*
5527         pixels[11].red)+cy[3]*(cx[0]*pixels[12].red+cx[1]*pixels[13].red+cx[2]*
5528         pixels[14].red+cx[3]*pixels[15].red));
5529       pixel->green=(cy[0]*(cx[0]*pixels[0].green+cx[1]*pixels[1].green+cx[2]*
5530         pixels[2].green+cx[3]*pixels[3].green)+cy[1]*(cx[0]*pixels[4].green+
5531         cx[1]*pixels[5].green+cx[2]*pixels[6].green+cx[3]*pixels[7].green)+
5532         cy[2]*(cx[0]*pixels[8].green+cx[1]*pixels[9].green+cx[2]*
5533         pixels[10].green+cx[3]*pixels[11].green)+cy[3]*(cx[0]*
5534         pixels[12].green+cx[1]*pixels[13].green+cx[2]*pixels[14].green+cx[3]*
5535         pixels[15].green));
5536       pixel->blue=(cy[0]*(cx[0]*pixels[0].blue+cx[1]*pixels[1].blue+cx[2]*
5537         pixels[2].blue+cx[3]*pixels[3].blue)+cy[1]*(cx[0]*pixels[4].blue+cx[1]*
5538         pixels[5].blue+cx[2]*pixels[6].blue+cx[3]*pixels[7].blue)+cy[2]*(cx[0]*
5539         pixels[8].blue+cx[1]*pixels[9].blue+cx[2]*pixels[10].blue+cx[3]*
5540         pixels[11].blue)+cy[3]*(cx[0]*pixels[12].blue+cx[1]*pixels[13].blue+
5541         cx[2]*pixels[14].blue+cx[3]*pixels[15].blue));
5542       if (image->colorspace == CMYKColorspace)
5543         pixel->black=(cy[0]*(cx[0]*pixels[0].black+cx[1]*pixels[1].black+cx[2]*
5544           pixels[2].black+cx[3]*pixels[3].black)+cy[1]*(cx[0]*pixels[4].black+
5545           cx[1]*pixels[5].black+cx[2]*pixels[6].black+cx[3]*pixels[7].black)+
5546           cy[2]*(cx[0]*pixels[8].black+cx[1]*pixels[9].black+cx[2]*
5547           pixels[10].black+cx[3]*pixels[11].black)+cy[3]*(cx[0]*
5548           pixels[12].black+cx[1]*pixels[13].black+cx[2]*pixels[14].black+cx[3]*
5549           pixels[15].black));
5550       pixel->alpha=(cy[0]*(cx[0]*pixels[0].alpha+cx[1]*pixels[1].alpha+cx[2]*
5551         pixels[2].alpha+cx[3]*pixels[3].alpha)+cy[1]*(cx[0]*pixels[4].alpha+
5552         cx[1]*pixels[5].alpha+cx[2]*pixels[6].alpha+cx[3]*pixels[7].alpha)+
5553         cy[2]*(cx[0]*pixels[8].alpha+cx[1]*pixels[9].alpha+cx[2]*
5554         pixels[10].alpha+cx[3]*pixels[11].alpha)+cy[3]*(cx[0]*pixels[12].alpha+
5555         cx[1]*pixels[13].alpha+cx[2]*pixels[14].alpha+cx[3]*pixels[15].alpha));
5556       break;
5557     }
5558 #if 0
5559     /* deprecated useless and very slow interpolator */
5560     case FilterInterpolatePixel:
5561     {
5562       CacheView
5563         *filter_view;
5564
5565       Image
5566         *excerpt_image,
5567         *filter_image;
5568
5569       RectangleInfo
5570         geometry;
5571
5572       geometry.width=4L;
5573       geometry.height=4L;
5574       geometry.x=x_offset-1;
5575       geometry.y=y_offset-1;
5576       excerpt_image=ExcerptImage(image,&geometry,exception);
5577       if (excerpt_image == (Image *) NULL)
5578         {
5579           status=MagickFalse;
5580           break;
5581         }
5582       filter_image=ResizeImage(excerpt_image,1,1,image->filter,exception);
5583       excerpt_image=DestroyImage(excerpt_image);
5584       if (filter_image == (Image *) NULL)
5585         break;
5586       filter_view=AcquireVirtualCacheView(filter_image,exception);
5587       p=GetCacheViewVirtualPixels(filter_view,0,0,1,1,exception);
5588       if (p != (const Quantum *) NULL)
5589         GetPixelInfoPixel(image,p,pixel);
5590       filter_view=DestroyCacheView(filter_view);
5591       filter_image=DestroyImage(filter_image);
5592       break;
5593     }
5594 #endif
5595     case IntegerInterpolatePixel:
5596     {
5597       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
5598       if (p == (const Quantum *) NULL)
5599         {
5600           status=MagickFalse;
5601           break;
5602         }
5603       GetPixelInfoPixel(image,p,pixel);
5604       break;
5605     }
5606     case MeshInterpolatePixel:
5607     {
5608       PointInfo
5609         delta,
5610         luminance;
5611
5612       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,2,2,exception);
5613       if (p == (const Quantum *) NULL)
5614         {
5615           status=MagickFalse;
5616           break;
5617         }
5618       delta.x=x-x_offset;
5619       delta.y=y-y_offset;
5620       luminance.x=GetPixelLuminance(image,p)-(double)
5621         GetPixelLuminance(image,p+3*GetPixelChannels(image));
5622       luminance.y=GetPixelLuminance(image,p+GetPixelChannels(image))-(double)
5623         GetPixelLuminance(image,p+2*GetPixelChannels(image));
5624       AlphaBlendPixelInfo(image,p,pixels+0,alpha+0);
5625       AlphaBlendPixelInfo(image,p+GetPixelChannels(image),pixels+1,alpha+1);
5626       AlphaBlendPixelInfo(image,p+2*GetPixelChannels(image),pixels+2,alpha+2);
5627       AlphaBlendPixelInfo(image,p+3*GetPixelChannels(image),pixels+3,alpha+3);
5628       if (fabs(luminance.x) < fabs(luminance.y))
5629         {
5630           /*
5631             Diagonal 0-3 NW-SE.
5632           */
5633           if (delta.x <= delta.y)
5634             {
5635               /*
5636                 Bottom-left triangle (pixel: 2, diagonal: 0-3).
5637               */
5638               delta.y=1.0-delta.y;
5639               gamma=MeshInterpolate(&delta,alpha[2],alpha[3],alpha[0]);
5640               gamma=PerceptibleReciprocal(gamma);
5641               pixel->red=gamma*MeshInterpolate(&delta,pixels[2].red,
5642                 pixels[3].red,pixels[0].red);
5643               pixel->green=gamma*MeshInterpolate(&delta,pixels[2].green,
5644                 pixels[3].green,pixels[0].green);
5645               pixel->blue=gamma*MeshInterpolate(&delta,pixels[2].blue,
5646                 pixels[3].blue,pixels[0].blue);
5647               if (image->colorspace == CMYKColorspace)
5648                 pixel->black=gamma*MeshInterpolate(&delta,pixels[2].black,
5649                   pixels[3].black,pixels[0].black);
5650               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5651               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[2].alpha,
5652                 pixels[3].alpha,pixels[0].alpha);
5653             }
5654           else
5655             {
5656               /*
5657                 Top-right triangle (pixel:1 , diagonal: 0-3).
5658               */
5659               delta.x=1.0-delta.x;
5660               gamma=MeshInterpolate(&delta,alpha[1],alpha[0],alpha[3]);
5661               gamma=PerceptibleReciprocal(gamma);
5662               pixel->red=gamma*MeshInterpolate(&delta,pixels[1].red,
5663                 pixels[0].red,pixels[3].red);
5664               pixel->green=gamma*MeshInterpolate(&delta,pixels[1].green,
5665                 pixels[0].green,pixels[3].green);
5666               pixel->blue=gamma*MeshInterpolate(&delta,pixels[1].blue,
5667                 pixels[0].blue,pixels[3].blue);
5668               if (image->colorspace == CMYKColorspace)
5669                 pixel->black=gamma*MeshInterpolate(&delta,pixels[1].black,
5670                   pixels[0].black,pixels[3].black);
5671               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5672               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[1].alpha,
5673                 pixels[0].alpha,pixels[3].alpha);
5674             }
5675         }
5676       else
5677         {
5678           /*
5679             Diagonal 1-2 NE-SW.
5680           */
5681           if (delta.x <= (1.0-delta.y))
5682             {
5683               /*
5684                 Top-left triangle (pixel: 0, diagonal: 1-2).
5685               */
5686               gamma=MeshInterpolate(&delta,alpha[0],alpha[1],alpha[2]);
5687               gamma=PerceptibleReciprocal(gamma);
5688               pixel->red=gamma*MeshInterpolate(&delta,pixels[0].red,
5689                 pixels[1].red,pixels[2].red);
5690               pixel->green=gamma*MeshInterpolate(&delta,pixels[0].green,
5691                 pixels[1].green,pixels[2].green);
5692               pixel->blue=gamma*MeshInterpolate(&delta,pixels[0].blue,
5693                 pixels[1].blue,pixels[2].blue);
5694               if (image->colorspace == CMYKColorspace)
5695                 pixel->black=gamma*MeshInterpolate(&delta,pixels[0].black,
5696                   pixels[1].black,pixels[2].black);
5697               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5698               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[0].alpha,
5699                 pixels[1].alpha,pixels[2].alpha);
5700             }
5701           else
5702             {
5703               /*
5704                 Bottom-right triangle (pixel: 3, diagonal: 1-2).
5705               */
5706               delta.x=1.0-delta.x;
5707               delta.y=1.0-delta.y;
5708               gamma=MeshInterpolate(&delta,alpha[3],alpha[2],alpha[1]);
5709               gamma=PerceptibleReciprocal(gamma);
5710               pixel->red=gamma*MeshInterpolate(&delta,pixels[3].red,
5711                 pixels[2].red,pixels[1].red);
5712               pixel->green=gamma*MeshInterpolate(&delta,pixels[3].green,
5713                 pixels[2].green,pixels[1].green);
5714               pixel->blue=gamma*MeshInterpolate(&delta,pixels[3].blue,
5715                 pixels[2].blue,pixels[1].blue);
5716               if (image->colorspace == CMYKColorspace)
5717                 pixel->black=gamma*MeshInterpolate(&delta,pixels[3].black,
5718                   pixels[2].black,pixels[1].black);
5719               gamma=MeshInterpolate(&delta,1.0,1.0,1.0);
5720               pixel->alpha=gamma*MeshInterpolate(&delta,pixels[3].alpha,
5721                 pixels[2].alpha,pixels[1].alpha);
5722             }
5723         }
5724       break;
5725     }
5726     case NearestInterpolatePixel:
5727     {
5728       x_offset=(ssize_t) floor(x+0.5);
5729       y_offset=(ssize_t) floor(y+0.5);
5730       p=GetCacheViewVirtualPixels(image_view,x_offset,y_offset,1,1,exception);
5731       if (p == (const Quantum *) NULL)
5732         {
5733           status=MagickFalse;
5734           break;
5735         }
5736       GetPixelInfoPixel(image,p,pixel);
5737       break;
5738     }
5739     case SplineInterpolatePixel:
5740     {
5741       double
5742         cx[4],
5743         cy[4];
5744
5745       p=GetCacheViewVirtualPixels(image_view,x_offset-1,y_offset-1,4,4,
5746         exception);
5747       if (p == (const Quantum *) NULL)
5748         {
5749           status=MagickFalse;
5750           break;
5751         }
5752       for (i=0; i < 16L; i++)
5753         AlphaBlendPixelInfo(image,p+i*GetPixelChannels(image),pixels+i,alpha+i);
5754       SplineWeights((double) (x-x_offset),&cx);
5755       SplineWeights((double) (y-y_offset),&cy);
5756       pixel->red=(cy[0]*(cx[0]*pixels[0].red+cx[1]*pixels[1].red+cx[2]*
5757         pixels[2].red+cx[3]*pixels[3].red)+cy[1]*(cx[0]*pixels[4].red+cx[1]*
5758         pixels[5].red+cx[2]*pixels[6].red+cx[3]*pixels[7].red)+cy[2]*(cx[0]*
5759         pixels[8].red+cx[1]*pixels[9].red+cx[2]*pixels[10].red+cx[3]*
5760         pixels[11].red)+cy[3]*(cx[0]*pixels[12].red+cx[1]*pixels[13].red+cx[2]*
5761         pixels[14].red+cx[3]*pixels[15].red));
5762       pixel->green=(cy[0]*(cx[0]*pixels[0].green+cx[1]*pixels[1].green+cx[2]*
5763         pixels[2].green+cx[3]*pixels[3].green)+cy[1]*(cx[0]*pixels[4].green+
5764         cx[1]*pixels[5].green+cx[2]*pixels[6].green+cx[3]*pixels[7].green)+
5765         cy[2]*(cx[0]*pixels[8].green+cx[1]*pixels[9].green+cx[2]*
5766         pixels[10].green+cx[3]*pixels[11].green)+cy[3]*(cx[0]*pixels[12].green+
5767         cx[1]*pixels[13].green+cx[2]*pixels[14].green+cx[3]*pixels[15].green));
5768       pixel->blue=(cy[0]*(cx[0]*pixels[0].blue+cx[1]*pixels[1].blue+cx[2]*
5769         pixels[2].blue+cx[3]*pixels[3].blue)+cy[1]*(cx[0]*pixels[4].blue+cx[1]*
5770         pixels[5].blue+cx[2]*pixels[6].blue+cx[3]*pixels[7].blue)+cy[2]*(cx[0]*
5771         pixels[8].blue+cx[1]*pixels[9].blue+cx[2]*pixels[10].blue+cx[3]*
5772         pixels[11].blue)+cy[3]*(cx[0]*pixels[12].blue+cx[1]*pixels[13].blue+
5773         cx[2]*pixels[14].blue+cx[3]*pixels[15].blue));
5774       if (image->colorspace == CMYKColorspace)
5775         pixel->black=(cy[0]*(cx[0]*pixels[0].black+cx[1]*pixels[1].black+cx[2]*
5776           pixels[2].black+cx[3]*pixels[3].black)+cy[1]*(cx[0]*pixels[4].black+
5777           cx[1]*pixels[5].black+cx[2]*pixels[6].black+cx[3]*pixels[7].black)+
5778           cy[2]*(cx[0]*pixels[8].black+cx[1]*pixels[9].black+cx[2]*
5779           pixels[10].black+cx[3]*pixels[11].black)+cy[3]*(cx[0]*
5780           pixels[12].black+cx[1]*pixels[13].black+cx[2]*pixels[14].black+cx[3]*
5781           pixels[15].black));
5782       pixel->alpha=(cy[0]*(cx[0]*pixels[0].alpha+cx[1]*pixels[1].alpha+cx[2]*
5783         pixels[2].alpha+cx[3]*pixels[3].alpha)+cy[1]*(cx[0]*pixels[4].alpha+
5784         cx[1]*pixels[5].alpha+cx[2]*pixels[6].alpha+cx[3]*pixels[7].alpha)+
5785         cy[2]*(cx[0]*pixels[8].alpha+cx[1]*pixels[9].alpha+cx[2]*
5786         pixels[10].alpha+cx[3]*pixels[11].alpha)+cy[3]*(cx[0]*pixels[12].alpha+
5787         cx[1]*pixels[13].alpha+cx[2]*pixels[14].alpha+cx[3]*pixels[15].alpha));
5788       break;
5789     }
5790   }
5791   return(status);
5792 }
5793 \f
5794 /*
5795 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5796 %                                                                             %
5797 %                                                                             %
5798 %                                                                             %
5799 +   I s F u z z y E q u i v a l e n c e P i x e l                             %
5800 %                                                                             %
5801 %                                                                             %
5802 %                                                                             %
5803 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5804 %
5805 %  IsFuzzyEquivalencePixel() returns MagickTrue if the distance between two
5806 %  pixels is less than the specified distance in a linear three (or four)u
5807 %  dimensional color space.
5808 %
5809 %  The format of the IsFuzzyEquivalencePixel method is:
5810 %
5811 %      void IsFuzzyEquivalencePixel(const Image *source,const Quantum *p,
5812 %        const Image *destination,const Quantum *q)
5813 %
5814 %  A description of each parameter follows:
5815 %
5816 %    o source: the source image.
5817 %
5818 %    o p: Pixel p.
5819 %
5820 %    o destination: the destination image.
5821 %
5822 %    o q: Pixel q.
5823 %
5824 */
5825 MagickExport MagickBooleanType IsFuzzyEquivalencePixel(const Image *source,
5826   const Quantum *p,const Image *destination,const Quantum *q)
5827 {
5828   double
5829     fuzz,
5830     pixel;
5831
5832   register double
5833     distance,
5834     scale;
5835
5836   fuzz=MagickMax(source->fuzz,(double) MagickSQ1_2)*MagickMax(
5837     destination->fuzz,(double) MagickSQ1_2);
5838   scale=1.0;
5839   distance=0.0;
5840   if (source->alpha_trait == BlendPixelTrait)
5841     {
5842       /*
5843         Transparencies are involved - set alpha distance
5844       */
5845       pixel=GetPixelAlpha(source,p)-(double) GetPixelAlpha(destination,q);
5846       distance=pixel*pixel;
5847       if (distance > fuzz)
5848         return(MagickFalse);
5849       /*
5850         Generate a alpha scaling factor to generate a 4D cone on colorspace
5851         Note that if one color is transparent, distance has no color component.
5852       */
5853       scale=QuantumScale*GetPixelAlpha(source,p);
5854       scale*=QuantumScale*GetPixelAlpha(destination,q);
5855       if (scale <= MagickEpsilon)
5856         return(MagickTrue);
5857     }
5858   /*
5859     RGB or CMY color cube
5860   */
5861   distance*=3.0;  /* rescale appropriately */
5862   fuzz*=3.0;
5863   pixel=GetPixelRed(source,p)-(double) GetPixelRed(destination,q);
5864   if ((source->colorspace == HSLColorspace) ||
5865       (source->colorspace == HSBColorspace) ||
5866       (source->colorspace == HWBColorspace))
5867     {
5868       /*
5869         Compute an arc distance for hue.  It should be a vector angle of
5870         'S'/'W' length with 'L'/'B' forming appropriate cones.
5871       */
5872       if (fabs((double) pixel) > (QuantumRange/2))
5873         pixel-=QuantumRange;
5874       pixel*=2;
5875     }
5876   distance+=scale*pixel*pixel;
5877   if (distance > fuzz)
5878     return(MagickFalse);
5879   pixel=GetPixelGreen(source,p)-(double) GetPixelGreen(destination,q);
5880   distance+=scale*pixel*pixel;
5881   if (distance > fuzz)
5882     return(MagickFalse);
5883   pixel=GetPixelBlue(source,p)-(double) GetPixelBlue(destination,q);
5884   distance+=scale*pixel*pixel;
5885   if (distance > fuzz)
5886     return(MagickFalse);
5887   return(MagickTrue);
5888 }
5889 \f
5890 /*
5891 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5892 %                                                                             %
5893 %                                                                             %
5894 %                                                                             %
5895 +   I s F u z z y E q u i v a l e n c e P i x e l I n f o                     %
5896 %                                                                             %
5897 %                                                                             %
5898 %                                                                             %
5899 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5900 %
5901 %  IsFuzzyEquivalencePixelInfo() returns true if the distance between two
5902 %  colors is less than the specified distance in a linear three (or four)
5903 %  dimensional color space.
5904 %
5905 %  This implements the equivalent of:
5906 %    fuzz < sqrt(color_distance^2 * u.a*v.a  + alpha_distance^2)
5907 %
5908 %  Which produces a multi-dimensional cone for that colorspace along the
5909 %  transparency vector.
5910 %
5911 %  For example for an RGB:
5912 %    color_distance^2  = ( (u.r-v.r)^2 + (u.g-v.g)^2 + (u.b-v.b)^2 ) / 3
5913 %
5914 %  See http://www.imagemagick.org/Usage/bugs/fuzz_distance/
5915 %
5916 %  Hue colorspace distances need more work.  Hue is not a distance, it is an
5917 %  angle!
5918 %
5919 %  A check that q is in the same color space as p should be made and the
5920 %  appropriate mapping made.  -- Anthony Thyssen  8 December 2010
5921 %
5922 %  The format of the IsFuzzyEquivalencePixelInfo method is:
5923 %
5924 %      MagickBooleanType IsFuzzyEquivalencePixelInfo(const PixelInfo *p,
5925 %        const PixelInfo *q)
5926 %
5927 %  A description of each parameter follows:
5928 %
5929 %    o p: Pixel p.
5930 %
5931 %    o q: Pixel q.
5932 %
5933 */
5934 MagickExport MagickBooleanType IsFuzzyEquivalencePixelInfo(const PixelInfo *p,
5935   const PixelInfo *q)
5936 {
5937   double
5938     fuzz,
5939     pixel;
5940
5941   register double
5942     scale,
5943     distance;
5944
5945   if ((p->fuzz == 0.0) && (q->fuzz == 0.0))
5946     return(IsPixelInfoEquivalent(p,q));
5947   if (p->fuzz == 0.0)
5948     fuzz=MagickMax(q->fuzz,(double) MagickSQ1_2)*MagickMax(q->fuzz,
5949       (double) MagickSQ1_2);
5950   else if (q->fuzz == 0.0)
5951     fuzz=MagickMax(p->fuzz,(double) MagickSQ1_2)*MagickMax(p->fuzz,
5952       (double) MagickSQ1_2);
5953   else
5954     fuzz=MagickMax(p->fuzz,(double) MagickSQ1_2)*MagickMax(q->fuzz,
5955       (double) MagickSQ1_2);
5956   scale=1.0;
5957   distance=0.0;
5958   if ((p->alpha_trait == BlendPixelTrait) || (q->alpha_trait == BlendPixelTrait))
5959     {
5960       /*
5961         Transparencies are involved - set alpha distance.
5962       */
5963       pixel=(p->alpha_trait == BlendPixelTrait ? p->alpha : OpaqueAlpha)-
5964         (q->alpha_trait == BlendPixelTrait ? q->alpha : OpaqueAlpha);
5965       distance=pixel*pixel;
5966       if (distance > fuzz)
5967         return(MagickFalse);
5968       /*
5969         Generate a alpha scaling factor to generate a 4D cone on colorspace.
5970         If one color is transparent, distance has no color component.
5971       */
5972       if (p->alpha_trait == BlendPixelTrait)
5973         scale=(QuantumScale*p->alpha);
5974       if (q->alpha_trait == BlendPixelTrait)
5975         scale*=(QuantumScale*q->alpha);
5976       if (scale <= MagickEpsilon )
5977         return(MagickTrue);
5978     }
5979   /*
5980     CMYK create a CMY cube with a multi-dimensional cone toward black.
5981   */
5982   if (p->colorspace == CMYKColorspace)
5983     {
5984       pixel=p->black-q->black;
5985       distance+=pixel*pixel*scale;
5986       if (distance > fuzz)
5987         return(MagickFalse);
5988       scale*=(double) (QuantumScale*(QuantumRange-p->black));
5989       scale*=(double) (QuantumScale*(QuantumRange-q->black));
5990     }
5991   /*
5992     RGB or CMY color cube.
5993   */
5994   distance*=3.0;  /* rescale appropriately */
5995   fuzz*=3.0;
5996   pixel=p->red-q->red;
5997   if ((p->colorspace == HSLColorspace) || (p->colorspace == HSBColorspace) ||
5998       (p->colorspace == HWBColorspace))
5999     {
6000       /*
6001         This calculates a arc distance for hue-- it should be a vector angle
6002         of 'S'/'W' length with 'L'/'B' forming appropriate cones.  In other
6003         words this is a hack - Anthony.
6004       */
6005       if (fabs((double) pixel) > (QuantumRange/2))
6006         pixel-=QuantumRange;
6007       pixel*=2;
6008     }
6009   distance+=pixel*pixel*scale;
6010   if (distance > fuzz)
6011     return(MagickFalse);
6012   pixel=p->green-q->green;
6013   distance+=pixel*pixel*scale;
6014   if (distance > fuzz)
6015     return(MagickFalse);
6016   pixel=p->blue-q->blue;
6017   distance+=pixel*pixel*scale;
6018   if (distance > fuzz)
6019     return(MagickFalse);
6020   return(MagickTrue);
6021 }
6022 \f
6023 /*
6024 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6025 %                                                                             %
6026 %                                                                             %
6027 %                                                                             %
6028 %   S e t P i x e l C h a n n e l M a p M a s k                               %
6029 %                                                                             %
6030 %                                                                             %
6031 %                                                                             %
6032 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6033 %
6034 %  SetPixelChannelMask() sets the pixel channel map from the specified
6035 %  channel mask.
6036 %
6037 %  The format of the SetPixelChannelMask method is:
6038 %
6039 %      void SetPixelChannelMask(Image *image,const ChannelType channel_mask)
6040 %
6041 %  A description of each parameter follows:
6042 %
6043 %    o image: the image.
6044 %
6045 %    o channel_mask: the channel mask.
6046 %
6047 */
6048 MagickExport void SetPixelChannelMask(Image *image,
6049   const ChannelType channel_mask)
6050 {
6051 #define GetChannelBit(mask,bit)  (((size_t) (mask) >> (size_t) (bit)) & 0x01)
6052
6053   register ssize_t
6054     i;
6055
6056   if (image->debug != MagickFalse)
6057     (void) LogMagickEvent(PixelEvent,GetMagickModule(),"%s[%08x]", \
6058       image->filename,channel_mask); \
6059   image->channel_mask=channel_mask;
6060   for (i=0; i < (ssize_t) GetPixelChannels(image); i++)
6061   {
6062     PixelChannel channel=GetPixelChannelChannel(image,i);
6063     SetPixelChannelTraits(image,channel,
6064       GetChannelBit(channel_mask,channel) == 0 ? CopyPixelTrait :
6065       image->alpha_trait != BlendPixelTrait || (channel == AlphaPixelChannel) ?
6066       UpdatePixelTrait : (PixelTrait) (UpdatePixelTrait | image->alpha_trait));
6067   }
6068   if (image->storage_class == PseudoClass)
6069     SetPixelChannelTraits(image,IndexPixelChannel,CopyPixelTrait);
6070   if (image->mask != MagickFalse)
6071     SetPixelChannelTraits(image,MaskPixelChannel,CopyPixelTrait);
6072   if (image->debug != MagickFalse)
6073     LogPixelChannels(image);
6074 }
6075 \f
6076 /*
6077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6078 %                                                                             %
6079 %                                                                             %
6080 %                                                                             %
6081 %   S e t P i x e l M e t a C h a n n e l s                                   %
6082 %                                                                             %
6083 %                                                                             %
6084 %                                                                             %
6085 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
6086 %
6087 %  SetPixelMetaChannels() sets the image meta channels.
6088 %
6089 %  The format of the SetPixelMetaChannels method is:
6090 %
6091 %      MagickBooleanType SetPixelMetaChannels(Image *image,
6092 %        const size_t number_meta_channels,ExceptionInfo *exception)
6093 %
6094 %  A description of each parameter follows:
6095 %
6096 %    o image: the image.
6097 %
6098 %    o number_meta_channels:  the number of meta channels.
6099 %
6100 %    o exception: return any errors or warnings in this structure.
6101 %
6102 */
6103 MagickExport MagickBooleanType SetPixelMetaChannels(Image *image,
6104   const size_t number_meta_channels,ExceptionInfo *exception)
6105 {
6106   image->number_meta_channels=number_meta_channels;
6107   return(SyncImagePixelCache(image,exception));
6108 }